summaryrefslogtreecommitdiff
path: root/src/testing
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing')
-rw-r--r--src/testing/.gitignore34
-rw-r--r--src/testing/Makefile.am423
-rw-r--r--src/testing/coins-cs.conf118
-rw-r--r--src/testing/coins-rsa.conf128
-rwxr-xr-xsrc/testing/taler-unified-setup.sh929
-rw-r--r--src/testing/test-taler-exchange-aggregator-postgres.conf50
-rw-r--r--src/testing/test-taler-exchange-wirewatch-postgres.conf52
-rw-r--r--src/testing/test_auditor_api-cs.conf4
-rw-r--r--src/testing/test_auditor_api-rsa.conf4
-rw-r--r--src/testing/test_auditor_api.c299
-rw-r--r--src/testing/test_auditor_api.conf140
-rw-r--r--src/testing/test_auditor_api_expire_reserve_now-cs.conf (renamed from src/testing/test_exchange_api_expire_reserve_now.conf)2
-rw-r--r--src/testing/test_auditor_api_expire_reserve_now-rsa.conf (renamed from src/testing/test_auditor_api_expire_reserve_now.conf)2
-rw-r--r--src/testing/test_auditor_api_version.c48
-rw-r--r--src/testing/test_bank_api.c249
-rw-r--r--src/testing/test_bank_api.conf23
-rw-r--r--src/testing/test_bank_api_fakebank.conf22
-rw-r--r--src/testing/test_bank_api_fakebank_twisted.conf24
-rw-r--r--src/testing/test_bank_api_nexus.conf38
-rw-r--r--src/testing/test_bank_api_pybank.conf21
-rw-r--r--src/testing/test_bank_api_pybank_twisted.conf43
-rw-r--r--src/testing/test_bank_api_twisted.c222
-rw-r--r--src/testing/test_exchange_api-cs.conf4
-rw-r--r--src/testing/test_exchange_api-rsa.conf4
-rw-r--r--src/testing/test_exchange_api-twisted.conf29
-rw-r--r--src/testing/test_exchange_api.c656
-rw-r--r--src/testing/test_exchange_api.conf175
-rw-r--r--src/testing/test_exchange_api_age_restriction-cs.conf4
-rw-r--r--src/testing/test_exchange_api_age_restriction-rsa.conf4
-rw-r--r--src/testing/test_exchange_api_age_restriction.c370
-rw-r--r--src/testing/test_exchange_api_age_restriction.conf119
-rw-r--r--src/testing/test_exchange_api_conflicts-cs.conf4
-rw-r--r--src/testing/test_exchange_api_conflicts-rsa.conf4
-rw-r--r--src/testing/test_exchange_api_conflicts.c312
-rw-r--r--src/testing/test_exchange_api_conflicts.conf81
-rw-r--r--src/testing/test_exchange_api_expire_reserve_now-cs.conf4
-rw-r--r--src/testing/test_exchange_api_expire_reserve_now-rsa.conf4
-rw-r--r--src/testing/test_exchange_api_home/.config/taler/account-2.json4
-rw-r--r--src/testing/test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.privbin0 -> 32 bytes
-rw-r--r--src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.privbin32 -> 32 bytes
-rw-r--r--src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv1
-rw-r--r--src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv1
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking-cs.conf18
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking-rsa.conf19
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking.c113
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking.conf84
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json4
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv1
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv1
-rw-r--r--src/testing/test_exchange_api_overlapping_keys_bug.c96
-rw-r--r--src/testing/test_exchange_api_revocation.c223
-rw-r--r--src/testing/test_exchange_api_twisted-cs.conf4
-rw-r--r--src/testing/test_exchange_api_twisted-rsa.conf4
-rw-r--r--src/testing/test_exchange_api_twisted.c271
-rw-r--r--src/testing/test_exchange_api_twisted.conf150
-rw-r--r--src/testing/test_exchange_management_api.c124
-rw-r--r--src/testing/test_exchange_p2p.c557
-rw-r--r--src/testing/test_kyc_api.c581
-rw-r--r--src/testing/test_kyc_api.conf42
-rw-r--r--src/testing/test_taler_exchange_aggregator.c311
-rw-r--r--src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json4
-rw-r--r--src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv1
-rw-r--r--src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv1
-rw-r--r--src/testing/test_taler_exchange_wirewatch.c136
-rw-r--r--src/testing/testing_api_cmd_age_withdraw.c756
-rw-r--r--src/testing/testing_api_cmd_auditor_add.c109
-rw-r--r--src/testing/testing_api_cmd_auditor_add_denom_sig.c111
-rw-r--r--src/testing/testing_api_cmd_auditor_del.c97
-rw-r--r--src/testing/testing_api_cmd_auditor_deposit_confirmation.c244
-rw-r--r--src/testing/testing_api_cmd_auditor_exchanges.c380
-rw-r--r--src/testing/testing_api_cmd_auditor_exec_auditor.c12
-rw-r--r--src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c9
-rw-r--r--src/testing/testing_api_cmd_bank_admin_add_incoming.c159
-rw-r--r--src/testing/testing_api_cmd_bank_admin_check.c60
-rw-r--r--src/testing/testing_api_cmd_bank_check.c92
-rw-r--r--src/testing/testing_api_cmd_bank_check_empty.c26
-rw-r--r--src/testing/testing_api_cmd_bank_history_credit.c584
-rw-r--r--src/testing/testing_api_cmd_bank_history_debit.c588
-rw-r--r--src/testing/testing_api_cmd_bank_transfer.c93
-rw-r--r--src/testing/testing_api_cmd_batch.c95
-rw-r--r--src/testing/testing_api_cmd_batch_deposit.c656
-rw-r--r--src/testing/testing_api_cmd_batch_withdraw.c557
-rw-r--r--src/testing/testing_api_cmd_change_auth.c154
-rw-r--r--src/testing/testing_api_cmd_check_aml_decision.c270
-rw-r--r--src/testing/testing_api_cmd_check_aml_decisions.c204
-rw-r--r--src/testing/testing_api_cmd_check_keys.c252
-rw-r--r--src/testing/testing_api_cmd_coin_history.c609
-rw-r--r--src/testing/testing_api_cmd_common.c64
-rw-r--r--src/testing/testing_api_cmd_contract_get.c316
-rw-r--r--src/testing/testing_api_cmd_deposit.c504
-rw-r--r--src/testing/testing_api_cmd_deposits_get.c121
-rw-r--r--src/testing/testing_api_cmd_exec_aggregator.c43
-rw-r--r--src/testing/testing_api_cmd_exec_auditor-offline.c163
-rw-r--r--src/testing/testing_api_cmd_exec_closer.c43
-rw-r--r--src/testing/testing_api_cmd_exec_expire.c162
-rw-r--r--src/testing/testing_api_cmd_exec_router.c161
-rw-r--r--src/testing/testing_api_cmd_exec_transfer.c15
-rw-r--r--src/testing/testing_api_cmd_exec_wget.c158
-rw-r--r--src/testing/testing_api_cmd_exec_wirewatch.c44
-rw-r--r--src/testing/testing_api_cmd_get_auditor.c286
-rw-r--r--src/testing/testing_api_cmd_get_exchange.c411
-rw-r--r--src/testing/testing_api_cmd_insert_deposit.c355
-rw-r--r--src/testing/testing_api_cmd_kyc_check_get.c243
-rw-r--r--src/testing/testing_api_cmd_kyc_proof.c259
-rw-r--r--src/testing/testing_api_cmd_kyc_wallet_get.c290
-rw-r--r--src/testing/testing_api_cmd_oauth.c412
-rw-r--r--src/testing/testing_api_cmd_offline_sign_extensions.c164
-rw-r--r--src/testing/testing_api_cmd_offline_sign_global_fees.c230
-rw-r--r--src/testing/testing_api_cmd_offline_sign_keys.c5
-rw-r--r--src/testing/testing_api_cmd_offline_sign_wire_fees.c (renamed from src/testing/testing_api_cmd_offline_sign_fees.c)16
-rw-r--r--src/testing/testing_api_cmd_purse_create_deposit.c450
-rw-r--r--src/testing/testing_api_cmd_purse_delete.c189
-rw-r--r--src/testing/testing_api_cmd_purse_deposit.c491
-rw-r--r--src/testing/testing_api_cmd_purse_get.c367
-rw-r--r--src/testing/testing_api_cmd_purse_merge.c436
-rw-r--r--src/testing/testing_api_cmd_recoup.c231
-rw-r--r--src/testing/testing_api_cmd_recoup_refresh.c441
-rw-r--r--src/testing/testing_api_cmd_refresh.c727
-rw-r--r--src/testing/testing_api_cmd_refund.c198
-rw-r--r--src/testing/testing_api_cmd_reserve_attest.c263
-rw-r--r--src/testing/testing_api_cmd_reserve_close.c260
-rw-r--r--src/testing/testing_api_cmd_reserve_get.c390
-rw-r--r--src/testing/testing_api_cmd_reserve_get_attestable.c242
-rw-r--r--src/testing/testing_api_cmd_reserve_history.c586
-rw-r--r--src/testing/testing_api_cmd_reserve_open.c349
-rw-r--r--src/testing/testing_api_cmd_reserve_purse.c371
-rw-r--r--src/testing/testing_api_cmd_revoke.c17
-rw-r--r--src/testing/testing_api_cmd_revoke_denom_key.c54
-rw-r--r--src/testing/testing_api_cmd_revoke_sign_key.c56
-rw-r--r--src/testing/testing_api_cmd_rewind.c221
-rw-r--r--src/testing/testing_api_cmd_run_fakebank.c214
-rw-r--r--src/testing/testing_api_cmd_serialize_keys.c295
-rw-r--r--src/testing/testing_api_cmd_set_officer.c301
-rw-r--r--src/testing/testing_api_cmd_set_wire_fee.c113
-rw-r--r--src/testing/testing_api_cmd_stat.c102
-rw-r--r--src/testing/testing_api_cmd_status.c424
-rw-r--r--src/testing/testing_api_cmd_system_start.c395
-rw-r--r--src/testing/testing_api_cmd_take_aml_decision.c321
-rw-r--r--src/testing/testing_api_cmd_transfer_get.c320
-rw-r--r--src/testing/testing_api_cmd_twister_exec_client.c272
-rw-r--r--src/testing/testing_api_cmd_wire.c117
-rw-r--r--src/testing/testing_api_cmd_wire_add.c109
-rw-r--r--src/testing/testing_api_cmd_wire_del.c91
-rw-r--r--src/testing/testing_api_cmd_withdraw.c460
-rw-r--r--src/testing/testing_api_helpers_auditor.c231
-rw-r--r--src/testing/testing_api_helpers_bank.c681
-rw-r--r--src/testing/testing_api_helpers_exchange.c948
-rw-r--r--src/testing/testing_api_loop.c1019
-rw-r--r--src/testing/testing_api_misc.c394
-rw-r--r--src/testing/testing_api_trait_amount.c76
-rw-r--r--src/testing/testing_api_trait_blinding_key.c77
-rw-r--r--src/testing/testing_api_trait_cmd.c80
-rw-r--r--src/testing/testing_api_trait_coin_priv.c78
-rw-r--r--src/testing/testing_api_trait_contract.c74
-rw-r--r--src/testing/testing_api_trait_denom_pub.c77
-rw-r--r--src/testing/testing_api_trait_denom_sig.c79
-rw-r--r--src/testing/testing_api_trait_exchange_pub.c77
-rw-r--r--src/testing/testing_api_trait_exchange_sig.c77
-rw-r--r--src/testing/testing_api_trait_fresh_coin.c77
-rw-r--r--src/testing/testing_api_trait_json.c165
-rw-r--r--src/testing/testing_api_trait_merchant_key.c127
-rw-r--r--src/testing/testing_api_trait_number.c229
-rw-r--r--src/testing/testing_api_trait_process.c82
-rw-r--r--src/testing/testing_api_trait_reserve_history.c76
-rw-r--r--src/testing/testing_api_trait_reserve_priv.c76
-rw-r--r--src/testing/testing_api_trait_reserve_pub.c78
-rw-r--r--src/testing/testing_api_trait_string.c231
-rw-r--r--src/testing/testing_api_trait_time.c120
-rw-r--r--src/testing/testing_api_trait_uuid.c117
-rw-r--r--src/testing/testing_api_trait_wtid.c76
-rw-r--r--src/testing/testing_api_traits.c82
-rw-r--r--src/testing/testing_api_twister_helpers.c16
-rw-r--r--src/testing/valgrind.h7165
173 files changed, 29068 insertions, 11472 deletions
diff --git a/src/testing/.gitignore b/src/testing/.gitignore
index 6f3923501..e1075ab16 100644
--- a/src/testing/.gitignore
+++ b/src/testing/.gitignore
@@ -1,13 +1,20 @@
-test_auditor_api_version
+test_auditor_api_version_cs
+test_auditor_api_version_rsa
test_bank_api_with_fakebank
test_bank_api_with_fakebank_twisted
test_bank_api_with_pybank
test_bank_api_with_pybank_twisted
test_taler_exchange_aggregator-postgres
test_taler_exchange_wirewatch-postgres
-test_exchange_api_revocation
+test_exchange_api_revocation_cs
+test_exchange_api_revocation_rsa
+test_exchange_api_age_restriction_cs
+test_exchange_api_age_restriction_rsa
+test_exchange_api_conflicts_cs
+test_exchange_api_conflicts_rsa
report*
-test_exchange_management_api
+test_exchange_management_api_cs
+test_exchange_management_api_rsa
test_exchange_api_home/.local/share/taler/crypto-eddsa/
test_exchange_api_home/.local/share/taler/crypto-rsa/
test_exchange_api_home/.local/share/taler/exchange/offline-keys/secm_tofus.priv
@@ -24,11 +31,32 @@ test_taler_exchange_httpd_home/.local/share/taler/taler-exchange-secmod-eddsa/
test_taler_exchange_httpd_home/.local/share/taler/taler-exchange-secmod-rsa/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/crypto-rsa/
test_exchange_api_home/.local/share/taler/exchange-offline/secm_tofus.pub
+test_exchange_api_home/.local/share/taler/exchange-secmod-cs/
test_exchange_api_home/.local/share/taler/exchange-secmod-eddsa/
test_exchange_api_home/.local/share/taler/exchange-secmod-rsa/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/secm_tofus.pub
+test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-secmod-cs/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-secmod-eddsa/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-secmod-rsa/
test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/secm_tofus.pub
+test_taler_exchange_httpd_home/.local/share/taler/exchange-secmod-cs/
test_taler_exchange_httpd_home/.local/share/taler/exchange-secmod-eddsa/
test_taler_exchange_httpd_home/.local/share/taler/exchange-secmod-rsa/
+test_kyc_api
+test_helper_cs_home/
+test_helper_rsa_home/test_exchange_api_twisted-cs
+test_exchange_api_twisted-rsa
+test_exchange_api_twisted_cs
+test_exchange_api_twisted_rsa
+test_exchange_p2p_cs
+test_exchange_p2p_rsa
+*.edited
+tmp-last-response.*
+test_exchange_api_home/taler/auditor/
+test_exchange_api_home/taler/exchange-offline/secm_tofus.pub
+test_exchange_api_home/taler/exchange-secmod-cs/
+test_exchange_api_home/taler/exchange-secmod-eddsa/
+test_exchange_api_home/taler/exchange-secmod-rsa/
+test_exchange_api_keys_cherry_picking_home/taler/
+test_taler_exchange_httpd_home/taler/
+libeufin-bank.pid
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 7fa7ef3d2..195ab4c55 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -13,6 +13,9 @@ endif
clean-local:
rm -rf report*
+bin_SCRIPTS = \
+ taler-unified-setup.sh
+
# Libraries
lib_LTLIBRARIES = \
@@ -37,11 +40,11 @@ libtalertesting_la_LDFLAGS = \
-version-info 0:0:0 \
-no-undefined
libtalertesting_la_SOURCES = \
+ testing_api_cmd_age_withdraw.c \
testing_api_cmd_auditor_add_denom_sig.c \
testing_api_cmd_auditor_add.c \
testing_api_cmd_auditor_del.c \
testing_api_cmd_auditor_deposit_confirmation.c \
- testing_api_cmd_auditor_exchanges.c \
testing_api_cmd_auditor_exec_auditor.c \
testing_api_cmd_auditor_exec_auditor_dbinit.c \
testing_api_cmd_bank_admin_add_incoming.c \
@@ -52,73 +55,86 @@ libtalertesting_la_SOURCES = \
testing_api_cmd_bank_history_debit.c \
testing_api_cmd_bank_transfer.c \
testing_api_cmd_batch.c \
- testing_api_cmd_change_auth.c \
- testing_api_cmd_check_keys.c \
+ testing_api_cmd_batch_deposit.c \
+ testing_api_cmd_batch_withdraw.c \
+ testing_api_cmd_check_aml_decision.c \
+ testing_api_cmd_check_aml_decisions.c \
+ testing_api_cmd_coin_history.c \
+ testing_api_cmd_common.c \
+ testing_api_cmd_contract_get.c \
testing_api_cmd_deposit.c \
testing_api_cmd_deposits_get.c \
testing_api_cmd_exec_aggregator.c \
+ testing_api_cmd_exec_auditor-offline.c \
testing_api_cmd_exec_closer.c \
+ testing_api_cmd_exec_expire.c \
+ testing_api_cmd_exec_router.c \
testing_api_cmd_exec_transfer.c \
+ testing_api_cmd_exec_wget.c \
testing_api_cmd_exec_wirewatch.c \
+ testing_api_cmd_get_auditor.c \
+ testing_api_cmd_get_exchange.c \
testing_api_cmd_insert_deposit.c \
- testing_api_cmd_offline_sign_fees.c \
+ testing_api_cmd_kyc_check_get.c \
+ testing_api_cmd_kyc_proof.c \
+ testing_api_cmd_kyc_wallet_get.c \
+ testing_api_cmd_oauth.c \
+ testing_api_cmd_offline_sign_global_fees.c \
+ testing_api_cmd_offline_sign_wire_fees.c \
testing_api_cmd_offline_sign_keys.c \
- testing_api_cmd_set_wire_fee.c \
+ testing_api_cmd_offline_sign_extensions.c \
+ testing_api_cmd_purse_create_deposit.c \
+ testing_api_cmd_purse_delete.c \
+ testing_api_cmd_purse_deposit.c \
+ testing_api_cmd_purse_get.c \
+ testing_api_cmd_purse_merge.c \
testing_api_cmd_recoup.c \
+ testing_api_cmd_recoup_refresh.c \
testing_api_cmd_refund.c \
testing_api_cmd_refresh.c \
+ testing_api_cmd_reserve_attest.c \
+ testing_api_cmd_reserve_close.c \
+ testing_api_cmd_reserve_get.c \
+ testing_api_cmd_reserve_get_attestable.c \
+ testing_api_cmd_reserve_history.c \
+ testing_api_cmd_reserve_open.c \
+ testing_api_cmd_reserve_purse.c \
testing_api_cmd_revoke.c \
testing_api_cmd_revoke_denom_key.c \
testing_api_cmd_revoke_sign_key.c \
- testing_api_cmd_rewind.c \
- testing_api_cmd_serialize_keys.c \
+ testing_api_cmd_run_fakebank.c \
+ testing_api_cmd_set_officer.c \
+ testing_api_cmd_set_wire_fee.c \
testing_api_cmd_signal.c \
testing_api_cmd_sleep.c \
testing_api_cmd_stat.c \
- testing_api_cmd_status.c \
+ testing_api_cmd_system_start.c \
+ testing_api_cmd_take_aml_decision.c \
testing_api_cmd_transfer_get.c \
testing_api_cmd_wait.c \
- testing_api_cmd_wire.c \
testing_api_cmd_wire_add.c \
testing_api_cmd_wire_del.c \
testing_api_cmd_withdraw.c \
- testing_api_helpers_auditor.c \
- testing_api_helpers_bank.c \
- testing_api_helpers_exchange.c \
testing_api_loop.c \
- testing_api_traits.c \
- testing_api_trait_amount.c \
- testing_api_trait_blinding_key.c \
- testing_api_trait_cmd.c \
- testing_api_trait_coin_priv.c \
- testing_api_trait_contract.c \
- testing_api_trait_denom_pub.c \
- testing_api_trait_denom_sig.c \
- testing_api_trait_exchange_pub.c \
- testing_api_trait_exchange_sig.c \
- testing_api_trait_fresh_coin.c \
- testing_api_trait_json.c \
- testing_api_trait_merchant_key.c \
- testing_api_trait_number.c \
- testing_api_trait_process.c \
- testing_api_trait_reserve_history.c \
- testing_api_trait_reserve_pub.c \
- testing_api_trait_reserve_priv.c \
- testing_api_trait_string.c \
- testing_api_trait_time.c \
- testing_api_trait_uuid.c \
- testing_api_trait_wtid.c
+ testing_api_misc.c \
+ testing_api_traits.c
+
+
libtalertesting_la_LIBADD = \
$(top_builddir)/src/lib/libtalerauditor.la \
$(top_builddir)/src/lib/libtalerexchange.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
$(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/mhd/libtalermhd.la \
$(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
-lgnunetcurl \
-lgnunetjson \
-lgnunetutil \
-ljansson \
+ -lmicrohttpd \
$(XLIB)
@@ -126,35 +142,64 @@ libtalertesting_la_LIBADD = \
AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
-.NOTPARALLEL:
+
check_PROGRAMS = \
- test_auditor_api \
test_auditor_api_version \
test_bank_api_with_fakebank \
- test_bank_api_with_pybank \
test_bank_api_with_nexus \
- test_exchange_api \
- test_exchange_api_keys_cherry_picking \
- test_exchange_api_revocation \
- test_exchange_api_overlapping_keys_bug \
- test_exchange_management_api \
+ test_exchange_api_cs \
+ test_exchange_api_rsa \
+ test_exchange_api_age_restriction_cs \
+ test_exchange_api_age_restriction_rsa \
+ test_exchange_api_conflicts_cs \
+ test_exchange_api_conflicts_rsa \
+ test_exchange_api_keys_cherry_picking_cs \
+ test_exchange_api_keys_cherry_picking_rsa \
+ test_exchange_api_revocation_cs \
+ test_exchange_api_revocation_rsa \
+ test_exchange_api_overlapping_keys_bug_cs \
+ test_exchange_api_overlapping_keys_bug_rsa \
+ test_exchange_management_api_cs \
+ test_exchange_management_api_rsa \
+ test_kyc_api \
test_taler_exchange_aggregator-postgres \
- test_taler_exchange_wirewatch-postgres
+ test_taler_exchange_wirewatch-postgres \
+ test_exchange_p2p_cs \
+ test_exchange_p2p_rsa
if HAVE_TWISTER
check_PROGRAMS += \
- test_exchange_api_twisted \
- test_bank_api_with_fakebank_twisted \
- test_bank_api_with_pybank_twisted
+ test_exchange_api_twisted_cs \
+ test_exchange_api_twisted_rsa \
+ test_bank_api_with_fakebank_twisted
endif
+# Removed for now...
+# test_auditor_api_cs
+# test_auditor_api_rsa
TESTS = \
$(check_PROGRAMS)
-test_auditor_api_SOURCES = \
+test_auditor_api_cs_SOURCES = \
+ test_auditor_api.c
+test_auditor_api_cs_LDADD = \
+ $(top_builddir)/src/lib/libtalerauditor.la \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+test_auditor_api_rsa_SOURCES = \
test_auditor_api.c
-test_auditor_api_LDADD = \
+test_auditor_api_rsa_LDADD = \
$(top_builddir)/src/lib/libtalerauditor.la \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
@@ -168,6 +213,7 @@ test_auditor_api_LDADD = \
-ljansson \
$(XLIB)
+
test_auditor_api_version_SOURCES = \
test_auditor_api_version.c
test_auditor_api_version_LDADD = \
@@ -184,7 +230,7 @@ test_bank_api_with_nexus_SOURCES = \
test_bank_api.c
test_bank_api_with_nexus_LDADD = \
libtalertesting.la \
- -ltalerexchange \
+ $(top_builddir)/src/lib/libtalerexchange.la \
-lgnunetutil \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(XLIB)
@@ -193,23 +239,30 @@ test_bank_api_with_fakebank_SOURCES = \
test_bank_api.c
test_bank_api_with_fakebank_LDADD = \
libtalertesting.la \
- -ltalerexchange \
+ $(top_builddir)/src/lib/libtalerexchange.la \
-lgnunetutil \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(XLIB)
-test_bank_api_with_pybank_SOURCES = \
- test_bank_api.c
-test_bank_api_with_pybank_LDADD = \
+test_exchange_api_cs_SOURCES = \
+ test_exchange_api.c
+test_exchange_api_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
- -lgnunetutil \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
$(XLIB)
-test_exchange_api_SOURCES = \
+test_exchange_api_rsa_SOURCES = \
test_exchange_api.c
-test_exchange_api_LDADD = \
+test_exchange_api_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
@@ -217,23 +270,31 @@ test_exchange_api_LDADD = \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
-test_exchange_management_api_SOURCES = \
- test_exchange_management_api.c
-test_exchange_management_api_LDADD = \
+test_exchange_api_age_restriction_cs_SOURCES = \
+ test_exchange_api_age_restriction.c
+test_exchange_api_age_restriction_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
-lgnunetutil \
+ -ljansson \
$(XLIB)
-test_exchange_api_revocation_SOURCES = \
- test_exchange_api_revocation.c
-test_exchange_api_revocation_LDADD = \
+test_exchange_api_age_restriction_rsa_SOURCES = \
+ test_exchange_api_age_restriction.c
+test_exchange_api_age_restriction_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
@@ -241,14 +302,80 @@ test_exchange_api_revocation_LDADD = \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
-test_exchange_api_keys_cherry_picking_SOURCES = \
+test_exchange_api_conflicts_cs_SOURCES = \
+ test_exchange_api_conflicts.c
+test_exchange_api_conflicts_cs_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+test_exchange_api_conflicts_rsa_SOURCES = \
+ test_exchange_api_conflicts.c
+test_exchange_api_conflicts_rsa_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+test_exchange_p2p_cs_SOURCES = \
+ test_exchange_p2p.c
+test_exchange_p2p_cs_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+test_exchange_p2p_rsa_SOURCES = \
+ test_exchange_p2p.c
+test_exchange_p2p_rsa_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/extensions/libtalerextensions.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+
+test_exchange_api_keys_cherry_picking_cs_SOURCES = \
test_exchange_api_keys_cherry_picking.c
-test_exchange_api_keys_cherry_picking_LDADD = \
+test_exchange_api_keys_cherry_picking_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
@@ -260,9 +387,68 @@ test_exchange_api_keys_cherry_picking_LDADD = \
-ljansson \
$(XLIB)
-test_exchange_api_overlapping_keys_bug_SOURCES = \
+test_exchange_api_keys_cherry_picking_rsa_SOURCES = \
+ test_exchange_api_keys_cherry_picking.c
+test_exchange_api_keys_cherry_picking_rsa_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/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 \
+ $(XLIB)
+
+test_exchange_api_revocation_cs_SOURCES = \
+ test_exchange_api_revocation.c
+test_exchange_api_revocation_cs_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+test_exchange_api_revocation_rsa_SOURCES = \
+ test_exchange_api_revocation.c
+test_exchange_api_revocation_rsa_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+
+test_exchange_api_overlapping_keys_bug_cs_SOURCES = \
+ test_exchange_api_overlapping_keys_bug.c
+test_exchange_api_overlapping_keys_bug_cs_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/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 \
+ $(XLIB)
+
+test_exchange_api_overlapping_keys_bug_rsa_SOURCES = \
test_exchange_api_overlapping_keys_bug.c
-test_exchange_api_overlapping_keys_bug_LDADD = \
+test_exchange_api_overlapping_keys_bug_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
@@ -274,6 +460,25 @@ test_exchange_api_overlapping_keys_bug_LDADD = \
-ljansson \
$(XLIB)
+test_exchange_management_api_cs_SOURCES = \
+ test_exchange_management_api.c
+test_exchange_management_api_cs_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil \
+ $(XLIB)
+
+test_exchange_management_api_rsa_SOURCES = \
+ test_exchange_management_api.c
+test_exchange_management_api_rsa_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetutil \
+ $(XLIB)
+
+
test_taler_exchange_aggregator_postgres_SOURCES = \
test_taler_exchange_aggregator.c
test_taler_exchange_aggregator_postgres_LDADD = \
@@ -307,9 +512,9 @@ test_taler_exchange_wirewatch_postgres_LDADD = \
-lpthread \
$(XLIB)
-test_exchange_api_twisted_SOURCES = \
+test_exchange_api_twisted_cs_SOURCES = \
test_exchange_api_twisted.c
-test_exchange_api_twisted_LDADD = \
+test_exchange_api_twisted_cs_LDADD = \
$(LIBGCRYPT_LIBS) \
libtalertesting.la \
libtalertwistertesting.la \
@@ -324,24 +529,26 @@ test_exchange_api_twisted_LDADD = \
-ljansson \
$(XLIB)
-test_bank_api_with_fakebank_twisted_SOURCES = \
- test_bank_api_twisted.c
-test_bank_api_with_fakebank_twisted_LDADD = \
+test_exchange_api_twisted_rsa_SOURCES = \
+ test_exchange_api_twisted.c
+test_exchange_api_twisted_rsa_LDADD = \
+ $(LIBGCRYPT_LIBS) \
libtalertesting.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ libtalertwistertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
- libtalertwistertesting.la \
+ $(top_builddir)/src/util/libtalerutil.la \
-lgnunetjson \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
-test_bank_api_with_pybank_twisted_SOURCES = \
+test_bank_api_with_fakebank_twisted_SOURCES = \
test_bank_api_twisted.c
-test_bank_api_with_pybank_twisted_LDADD = \
+test_bank_api_with_fakebank_twisted_LDADD = \
libtalertesting.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
@@ -351,34 +558,60 @@ test_bank_api_with_pybank_twisted_LDADD = \
-lgnunetjson \
-lgnunetcurl \
-lgnunetutil \
- -ljansson \
+ -ljansson \
$(XLIB)
+test_kyc_api_SOURCES = \
+ test_kyc_api.c
+test_kyc_api_LDADD = \
+ libtalertesting.la \
+ $(top_builddir)/src/lib/libtalerauditor.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
# Distribution
EXTRA_DIST = \
- test_auditor_api.conf \
- test_auditor_api_expire_reserve_now.conf \
+ $(bin_SCRIPTS) \
+ valgrind.h \
+ coins-cs.conf \
+ coins-rsa.conf \
+ test_auditor_api-cs.conf \
+ test_auditor_api-rsa.conf \
+ test_auditor_api_expire_reserve_now-cs.conf \
+ test_auditor_api_expire_reserve_now-rsa.conf \
+ test_bank_api.conf \
test_bank_api_fakebank.conf \
test_bank_api_fakebank_twisted.conf \
- test_bank_api_pybank.conf \
- test_bank_api_pybank_twisted.conf \
- test_exchange_api_home/.config/taler/account-2.json \
+ test_bank_api_nexus.conf \
+ test_exchange_api_home/taler/auditor/offline-keys/auditor.priv \
test_exchange_api_home/.local/share/taler/exchange-offline/master.priv \
- test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \
- test_exchange_api_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \
- test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json \
- test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv \
- test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv \
- test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \
+ test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv \
test_exchange_api.conf \
- test_exchange_api_twisted.conf \
+ test_exchange_api-cs.conf \
+ test_exchange_api-rsa.conf \
+ test_exchange_api_age_restriction.conf \
+ test_exchange_api_age_restriction-cs.conf \
+ test_exchange_api_age_restriction-rsa.conf \
+ test_exchange_api_conflicts.conf \
+ test_exchange_api_conflicts-cs.conf \
+ test_exchange_api_conflicts-rsa.conf \
+ test_exchange_api-twisted.conf \
+ test_exchange_api_twisted-cs.conf \
+ test_exchange_api_twisted-rsa.conf \
test_exchange_api_keys_cherry_picking.conf \
- test_exchange_api_expire_reserve_now.conf \
- test_taler_exchange_httpd_home/.config/taler/account-1.json \
- test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv \
- test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv \
- test_taler_exchange_httpd_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \
+ test_exchange_api_keys_cherry_picking-cs.conf \
+ test_exchange_api_keys_cherry_picking-rsa.conf \
+ test_exchange_api_expire_reserve_now-cs.conf \
+ test_exchange_api_expire_reserve_now-rsa.conf \
test-taler-exchange-aggregator-postgres.conf \
- test-taler-exchange-wirewatch-postgres.conf
+ test-taler-exchange-wirewatch-postgres.conf \
+ test_kyc_api.conf
diff --git a/src/testing/coins-cs.conf b/src/testing/coins-cs.conf
new file mode 100644
index 000000000..92163baac
--- /dev/null
+++ b/src/testing/coins-cs.conf
@@ -0,0 +1,118 @@
+
+# Sections starting with "coin_" specify which denominations
+# the exchange should support (and their respective fee structure)
+[coin_eur_ct_1]
+value = EUR:0.01
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.00
+fee_deposit = EUR:0.00
+fee_refresh = EUR:0.01
+fee_refund = EUR:0.01
+CIPHER = CS
+
+[coin_eur_ct_10]
+value = EUR:0.10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = CS
+
+[coin_eur_1]
+value = EUR:1
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = CS
+
+[coin_eur_5]
+value = EUR:5
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = CS
+
+[coin_eur_10]
+value = EUR:10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = CS
+
+
+[coin_eur_ct_1_age_restricted]
+value = EUR:0.01
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.00
+fee_deposit = EUR:0.00
+fee_refresh = EUR:0.01
+fee_refund = EUR:0.01
+age_restricted = YES
+CIPHER = CS
+
+[coin_eur_ct_10_age_restricted]
+value = EUR:0.10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+age_restricted = YES
+CIPHER = CS
+
+[coin_eur_1_age_restricted]
+value = EUR:1
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+age_restricted = YES
+CIPHER = CS
+
+[coin_eur_5_age_restricted]
+value = EUR:5
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+age_restricted = YES
+CIPHER = CS
+
+[coin_eur_10_age_restricted]
+value = EUR:10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+age_restricted = YES
+CIPHER = CS
diff --git a/src/testing/coins-rsa.conf b/src/testing/coins-rsa.conf
new file mode 100644
index 000000000..7a21a343b
--- /dev/null
+++ b/src/testing/coins-rsa.conf
@@ -0,0 +1,128 @@
+# This file is in the public domain.
+
+# Sections starting with "coin_" specify which denominations
+# the exchange should support (and their respective fee structure)
+[coin_eur_ct_1]
+value = EUR:0.01
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.00
+fee_deposit = EUR:0.00
+fee_refresh = EUR:0.01
+fee_refund = EUR:0.01
+CIPHER = RSA
+rsa_keysize = 1024
+
+[coin_eur_ct_10]
+value = EUR:0.10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = RSA
+rsa_keysize = 1024
+
+[coin_eur_1]
+value = EUR:1
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = RSA
+rsa_keysize = 1024
+
+[coin_eur_5]
+value = EUR:5
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = RSA
+rsa_keysize = 1024
+
+[coin_eur_10]
+value = EUR:10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = RSA
+rsa_keysize = 1024
+
+[coin_eur_ct_1_age_restricted]
+value = EUR:0.01
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.00
+fee_deposit = EUR:0.00
+fee_refresh = EUR:0.01
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+age_restricted = YES
+CIPHER = RSA
+
+[coin_eur_ct_10_age_restricted]
+value = EUR:0.10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+age_restricted = YES
+CIPHER = RSA
+
+[coin_eur_1_age_restricted]
+value = EUR:1
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+age_restricted = YES
+CIPHER = RSA
+
+[coin_eur_5_age_restricted]
+value = EUR:5
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+age_restricted = YES
+CIPHER = RSA
+
+[coin_eur_10_age_restricted]
+value = EUR:10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+age_restricted = YES
+CIPHER = RSA \ No newline at end of file
diff --git a/src/testing/taler-unified-setup.sh b/src/testing/taler-unified-setup.sh
new file mode 100755
index 000000000..2be6a97f1
--- /dev/null
+++ b/src/testing/taler-unified-setup.sh
@@ -0,0 +1,929 @@
+#!/bin/bash
+#
+# This file is part of TALER
+# Copyright (C) 2023, 2024 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/>
+#
+# Author: Christian Grothoff
+#
+# This script configures and launches various GNU Taler services.
+# Which ones depend on command-line options. Use "-h" to find out.
+# Prints "<<READY>>" on a separate line once all requested services
+# are running. Close STDIN (or input 'NEWLINE') to stop all started
+# services again.
+#
+# shellcheck disable=SC2317
+
+set -eu
+
+EXIT_STATUS=2
+
+# Exit, with status code "skip" (no 'real' failure)
+function exit_skip() {
+ echo " SKIP: " "$@" >&2
+ EXIT_STATUS=77
+ exit "$EXIT_STATUS"
+}
+
+# Exit, with error message (hard failure)
+function exit_fail() {
+ echo " FAIL: " "$@" >&2
+ EXIT_STATUS=1
+ exit "$EXIT_STATUS"
+}
+
+# Cleanup to run whenever we exit
+function cleanup()
+{
+ echo "Taler unified setup terminating at $STAGE!" >&2
+
+ for n in $(jobs -p)
+ do
+ kill "$n" 2> /dev/null || true
+ done
+ wait
+ rm -f libeufin-nexus.pid libeufin-sandbox.pid
+ exit "$EXIT_STATUS"
+}
+
+STAGE="boot"
+
+# Install cleanup handler (except for kill -9)
+trap cleanup EXIT
+
+WAIT_FOR_SIGNAL=0
+START_AUDITOR=0
+START_BACKUP=0
+START_EXCHANGE=0
+START_FAKEBANK=0
+START_DONAU=0
+START_CHALLENGER=0
+START_AGGREGATOR=0
+START_MERCHANT=0
+START_NEXUS=0
+START_BANK=0
+START_TRANSFER=0
+START_WIREWATCH=0
+START_DEPOSITCHECK=0
+START_MERCHANT_EXCHANGE=0
+START_MERCHANT_WIREWATCH=0
+USE_ACCOUNT="exchange-account-1"
+USE_VALGRIND=""
+WIRE_DOMAIN="x-taler-bank"
+CONF_ORIG="$HOME/.config/taler.conf"
+LOGLEVEL="DEBUG"
+DEFAULT_SLEEP="0.2"
+
+# Parse command-line options
+while getopts ':abc:d:DeEfghkL:mMnr:stu:vwWz' OPTION; do
+ case "$OPTION" in
+ a)
+ START_AUDITOR="1"
+ ;;
+ b)
+ START_BANK="1"
+ ;;
+ c)
+ CONF_ORIG="$OPTARG"
+ ;;
+ d)
+ WIRE_DOMAIN="$OPTARG"
+ ;;
+ D)
+ START_DONAU="1"
+ ;;
+ e)
+ START_EXCHANGE="1"
+ ;;
+ E)
+ START_MERCHANT_EXCHANGE="1"
+ ;;
+ f)
+ START_FAKEBANK="1"
+ ;;
+ h)
+ echo 'Supported options:'
+ echo ' -a -- start auditor'
+ echo ' -b -- start bank'
+ # shellcheck disable=SC2016
+ echo ' -c $CONF -- set configuration'
+ # shellcheck disable=SC2016
+ echo ' -d $METHOD -- use wire method (default: x-taler-bank)'
+ echo ' -D -- start donau'
+ echo ' -e -- start exchange'
+ echo ' -E -- start taler-merchant-exchange'
+ echo ' -f -- start fakebank'
+ echo ' -g -- start taler-exchange-aggregator'
+ echo ' -h -- print this help'
+ echo ' -k -- start challenger (KYC service)'
+ # shellcheck disable=SC2016
+ echo ' -L $LOGLEVEL -- set log level'
+ echo ' -m -- start taler-merchant'
+ echo ' -M -- start taler-merchant-depositcheck'
+ echo ' -n -- start nexus'
+ # shellcheck disable=SC2016
+ echo ' -r $MEX -- which exchange to use at the merchant (optional)'
+ echo ' -s -- start backup/sync'
+ echo ' -t -- start taler-exchange-transfer'
+ # shellcheck disable=SC2016
+ echo ' -u $SECTION -- exchange account to use'
+ echo ' -v -- use valgrind'
+ echo ' -w -- start taler-exchange-wirewatch'
+ echo ' -W -- wait for signal'
+ echo ' -z -- start taler-merchant-wirewatch'
+ exit 0
+ ;;
+ g)
+ START_AGGREGATOR="1"
+ ;;
+ k)
+ START_CHALLENGER="1"
+ ;;
+ L)
+ LOGLEVEL="$OPTARG"
+ ;;
+ m)
+ START_MERCHANT="1"
+ ;;
+ M)
+ START_DEPOSITCHECK="1"
+ ;;
+ n)
+ START_NEXUS="1"
+ ;;
+ r)
+ USE_MERCHANT_EXCHANGE="$OPTARG"
+ ;;
+ s)
+ START_BACKUP="1"
+ ;;
+ t)
+ START_TRANSFER="1"
+ ;;
+ u)
+ USE_ACCOUNT="$OPTARG"
+ ;;
+ v)
+ USE_VALGRIND="valgrind --leak-check=yes"
+ DEFAULT_SLEEP="2"
+ ;;
+ w)
+ START_WIREWATCH="1"
+ ;;
+ W)
+ WAIT_FOR_SIGNAL="1"
+ ;;
+ z)
+ START_MERCHANT_WIREWATCH="1"
+ ;;
+ ?)
+ exit_fail "Unrecognized command line option"
+ ;;
+ esac
+done
+
+STAGE="init"
+
+echo "Starting with configuration file at: $CONF_ORIG"
+CONF="$CONF_ORIG.edited"
+cp "${CONF_ORIG}" "${CONF}"
+
+STAGE="checks"
+
+echo -n "Testing for jq"
+jq -h > /dev/null || exit_skip " jq required"
+echo " FOUND"
+
+echo -n "Testing for wget"
+wget --help > /dev/null || exit_skip " wget required"
+echo " FOUND"
+
+if [ "1" = "$START_EXCHANGE" ]
+then
+ echo -n "Testing for Taler exchange"
+ taler-exchange-httpd -h > /dev/null || exit_skip " taler-exchange-httpd required"
+ echo " FOUND"
+fi
+
+if [ "1" = "$START_DONAU" ]
+then
+ echo -n "Testing for Donau"
+ donau-httpd -h > /dev/null || exit_skip " donau-httpd required"
+ echo " FOUND"
+fi
+
+if [ "1" = "$START_MERCHANT" ]
+then
+ echo -n "Testing for Taler merchant"
+ taler-merchant-httpd -h > /dev/null || exit_skip " taler-merchant-httpd required"
+ echo " FOUND"
+fi
+
+if [ "1" = "$START_CHALLENGER" ]
+then
+ echo -n "Testing for Taler challenger"
+ challenger-httpd -h > /dev/null || exit_skip " challenger-httpd required"
+ echo " FOUND"
+fi
+
+if [ "1" = "$START_BACKUP" ]
+then
+ echo -n "Testing for sync-httpd"
+ sync-httpd -h > /dev/null || exit_skip " sync-httpd required"
+ echo " FOUND"
+fi
+
+if [ "1" = "$START_NEXUS" ]
+then
+ echo -n "Testing for libeufin-cli"
+ libeufin-cli --help >/dev/null </dev/null || exit_skip " MISSING"
+ echo " FOUND"
+fi
+
+if [ "1" = "$START_BANK" ]
+then
+ echo -n "Testing for libeufin-bank"
+ libeufin-bank --help >/dev/null </dev/null || exit_skip " MISSING"
+ echo " FOUND"
+fi
+
+STAGE="config"
+
+
+EXCHANGE_URL=$(taler-config -c "$CONF" -s "EXCHANGE" -o "BASE_URL")
+CURRENCY=$(taler-config -c "$CONF" -s "TALER" -o "CURRENCY")
+
+echo "Setting up for $CURRENCY at $EXCHANGE_URL"
+
+register_bank_account() {
+ wget \
+ --http-user="$AUSER" \
+ --http-password="$APASS" \
+ --method=DELETE \
+ -o /dev/null \
+ -O /dev/null \
+ -a wget-delete-account.log \
+ "http://localhost:${BANK_PORT}/accounts/$1" \
+ || true # deletion may fail, that's OK!
+ if [ "$1" = "exchange" ] || [ "$1" = "Exchange" ]
+ then
+ IS_EXCHANGE="true"
+ else
+ IS_EXCHANGE="false"
+ fi
+ MAYBE_IBAN="${4:-}"
+ if [ -n "$MAYBE_IBAN" ]
+ then
+ # shellcheck disable=SC2001
+ ENAME=$(echo "$3" | sed -e "s/ /+/g")
+ # Note: this assumes that $3 has no spaces. Should probably escape in the future..
+ PAYTO="payto://iban/SANDBOXX/${MAYBE_IBAN}?receiver-name=$ENAME"
+ BODY='{"username":"'"$1"'","password":"'"$2"'","is_taler_exchange":'"$IS_EXCHANGE"',"name":"'"$3"'","payto_uri":"'"$PAYTO"'"}'
+ else
+ BODY='{"username":"'"$1"'","password":"'"$2"'","is_taler_exchange":'"$IS_EXCHANGE"',"name":"'"$3"'"}'
+ fi
+ wget \
+ --http-user="$AUSER" \
+ --http-password="$APASS" \
+ --method=POST \
+ --header='Content-type: application/json' \
+ --body-data="${BODY}" \
+ -o /dev/null \
+ -O /dev/null \
+ -a wget-register-account.log \
+ "http://localhost:${BANK_PORT}/accounts"
+}
+
+register_fakebank_account() {
+ if [ "$1" = "exchange" ] || [ "$1" = "Exchange" ]
+ then
+ IS_EXCHANGE="true"
+ else
+ IS_EXCHANGE="false"
+ fi
+ BODY='{"username":"'"$1"'","password":"'"$2"'","name":"'"$1"'","is_taler_exchange":'"$IS_EXCHANGE"'}'
+ wget \
+ --post-data="$BODY" \
+ --header='Content-type: application/json' \
+ --tries=3 \
+ --waitretry=1 \
+ --timeout=30 \
+ "http://localhost:$BANK_PORT/accounts" \
+ -a wget-register-account.log \
+ -o /dev/null \
+ -O /dev/null \
+ >/dev/null
+}
+
+
+if [[ "1" = "$START_BANK" ]]
+then
+ BANK_PORT=$(taler-config -c "$CONF" -s "libeufin-bank" -o "PORT")
+ BANK_URL="http://localhost:${BANK_PORT}/"
+fi
+
+if [[ "1" = "$START_FAKEBANK" ]]
+then
+ BANK_PORT=$(taler-config -c "$CONF" -s "BANK" -o "HTTP_PORT")
+ BANK_URL="http://localhost:${BANK_PORT}/"
+fi
+
+STAGE="bank"
+
+if [ "1" = "$START_BANK" ]
+then
+ echo -n "Setting up bank database ... "
+ libeufin-bank dbinit \
+ -r \
+ -c "$CONF" \
+ &> libeufin-bank-reset.log
+ echo "DONE"
+ echo -n "Launching bank ... "
+ libeufin-bank serve \
+ -c "$CONF" \
+ > libeufin-bank-stdout.log \
+ 2> libeufin-bank-stderr.log &
+ echo $! > libeufin-bank.pid
+ echo "DONE"
+ echo -n "Waiting for Bank ..."
+ OK="0"
+ for n in $(seq 1 100); do
+ echo -n "."
+ sleep "$DEFAULT_SLEEP"
+ wget --timeout=1 \
+ --tries=3 \
+ --waitretry=0 \
+ -a wget-bank-check.log \
+ -o /dev/null \
+ -O /dev/null \
+ "${BANK_URL}config" || continue
+ OK="1"
+ break
+ done
+ if [ "1" != "$OK" ]
+ then
+ exit_skip "Failed to launch services (bank)"
+ fi
+ echo "OK"
+ echo -n "Set admin password..."
+ AUSER="admin"
+ APASS="secret"
+ libeufin-bank \
+ passwd \
+ -c "$CONF" \
+ "$AUSER" "$APASS" \
+ &> libeufin-bank-passwd.log
+ libeufin-bank \
+ edit-account \
+ -c "$CONF" \
+ --debit_threshold="$CURRENCY:1000000" \
+ "$AUSER" \
+ &> libeufin-bank-debit-threshold.log
+ echo " OK"
+fi
+
+if [ "1" = "$START_NEXUS" ]
+then
+ echo "Nexus currently not supported ..."
+fi
+
+if [ "1" = "$START_FAKEBANK" ]
+then
+ echo -n "Setting up fakebank ..."
+ $USE_VALGRIND taler-fakebank-run \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ -n 4 \
+ 2> taler-fakebank-run.log &
+ echo " OK"
+fi
+
+if [[ "1" = "$START_NEXUS" || "1" = "$START_FAKEBANK" ]]
+then
+ echo -n "Waiting for the bank"
+ # Wait for bank to be available (usually the slowest)
+ OK="0"
+ for n in $(seq 1 300)
+ do
+ echo -n "."
+ sleep "$DEFAULT_SLEEP"
+ # bank
+ wget --tries=1 \
+ --waitretry=0 \
+ --timeout=1 \
+ --user admin \
+ --password secret \
+ -a wget-bank-check.log \
+ -o /dev/null \
+ -O /dev/null \
+ "http://localhost:${BANK_PORT}/" || continue
+ OK="1"
+ break
+ done
+ if [ "1" != "$OK" ]
+ then
+ exit_skip "Failed to launch services (bank)"
+ fi
+ echo " OK"
+fi
+
+STAGE="accounts"
+
+if [ "1" = "$START_FAKEBANK" ]
+then
+ echo -n "Register Fakebank users ..."
+ register_fakebank_account fortytwo x
+ register_fakebank_account fortythree x
+ register_fakebank_account exchange x
+ register_fakebank_account tor x
+ register_fakebank_account gnunet x
+ register_fakebank_account tutorial x
+ register_fakebank_account survey x
+ echo " DONE"
+fi
+
+if [ "1" = "$START_BANK" ]
+then
+ echo -n "Register bank users ..."
+ # The specified IBAN and name must match the ones hard-coded into
+ # the C helper for the add-incoming call. Without this value,
+ # libeufin-bank won't find the target account to debit along a /add-incoming
+ # call.
+ register_bank_account fortytwo x "User42" FR7630006000011234567890189
+ register_bank_account fortythree x "Forty Three"
+ register_bank_account exchange x "Exchange Company" DE989651
+ register_bank_account tor x "Tor Project"
+ register_bank_account gnunet x "GNUnet"
+ register_bank_account tutorial x "Tutorial"
+ register_bank_account survey x "Survey"
+ echo " DONE"
+fi
+
+STAGE="exchange"
+
+if [ "1" = "$START_EXCHANGE" ]
+then
+ echo -n "Starting exchange ..."
+ EXCHANGE_PORT=$(taler-config -c "$CONF" -s EXCHANGE -o PORT)
+ SERVE=$(taler-config -c "$CONF" -s EXCHANGE -o SERVE)
+ if [ "${SERVE}" = "unix" ]
+ then
+ EXCHANGE_URL=$(taler-config -c "$CONF" -s EXCHANGE -o BASE_URL)
+ else
+ EXCHANGE_URL="http://localhost:${EXCHANGE_PORT}/"
+ fi
+ MASTER_PRIV_FILE=$(taler-config -f -c "${CONF}" -s "EXCHANGE-OFFLINE" -o "MASTER_PRIV_FILE")
+ MASTER_PRIV_DIR=$(dirname "$MASTER_PRIV_FILE")
+ mkdir -p "${MASTER_PRIV_DIR}"
+ if [ ! -e "$MASTER_PRIV_FILE" ]
+ then
+ gnunet-ecc -g1 "$MASTER_PRIV_FILE" > /dev/null 2> /dev/null
+ echo -n "."
+ fi
+ MASTER_PUB=$(gnunet-ecc -p "${MASTER_PRIV_FILE}")
+ MPUB=$(taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY)
+ if [ "$MPUB" != "$MASTER_PUB" ]
+ then
+ echo -n " patching master_pub ($MASTER_PUB)..."
+ taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY -V "$MASTER_PUB"
+ fi
+ taler-exchange-dbinit -c "$CONF" --reset
+ $USE_VALGRIND taler-exchange-secmod-eddsa \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ 2> taler-exchange-secmod-eddsa.log &
+ $USE_VALGRIND taler-exchange-secmod-rsa \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ 2> taler-exchange-secmod-rsa.log &
+ $USE_VALGRIND taler-exchange-secmod-cs \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ 2> taler-exchange-secmod-cs.log &
+ $USE_VALGRIND taler-exchange-httpd \
+ -c "$CONF" \
+ -L "$LOGLEVEL" 2> taler-exchange-httpd.log &
+ echo " DONE"
+fi
+
+STAGE="donau"
+
+if [ "1" = "$START_DONAU" ]
+then
+ echo -n "Starting Donau ..."
+ DONAU_PORT=$(donau-config -c "$CONF" -s DONAU -o PORT)
+ SERVE=$(donau-config -c "$CONF" -s DONAU -o SERVE)
+ if [ "${SERVE}" = "unix" ]
+ then
+ DONAU_URL=$(donau-config -c "$CONF" -s DONAU -o BASE_URL)
+ else
+ DONAU_URL="http://localhost:${DONAU_PORT}/"
+ fi
+ donau-dbinit -c "$CONF" --reset
+ $USE_VALGRIND taler-exchange-secmod-eddsa -c "$CONF" -L "$LOGLEVEL" -s donau 2> donau-secmod-eddsa.log &
+ $USE_VALGRIND taler-exchange-secmod-rsa -c "$CONF" -L "$LOGLEVEL" -s donau 2> donau-secmod-rsa.log &
+ $USE_VALGRIND taler-exchange-secmod-cs -c "$CONF" -L "$LOGLEVEL" -s donau 2> donau-secmod-cs.log &
+ $USE_VALGRIND donau-httpd -c "$CONF" -L "$LOGLEVEL" 2> donau-httpd.log &
+ echo " DONE"
+fi
+
+STAGE="wirewatch"
+
+if [ "1" = "$START_WIREWATCH" ]
+then
+ echo -n "Starting wirewatch ..."
+ $USE_VALGRIND taler-exchange-wirewatch \
+ --account="$USE_ACCOUNT" \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ --longpoll-timeout="60 s" \
+ 2> taler-exchange-wirewatch.log &
+ echo " DONE"
+fi
+
+STAGE="aggregator"
+
+if [ "1" = "$START_AGGREGATOR" ]
+then
+ echo -n "Starting aggregator ..."
+ $USE_VALGRIND taler-exchange-aggregator \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ 2> taler-exchange-aggregator.log &
+ echo " DONE"
+fi
+
+STAGE="transfer"
+
+if [ "1" = "$START_TRANSFER" ]
+then
+ echo -n "Starting transfer ..."
+ $USE_VALGRIND taler-exchange-transfer \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ 2> taler-exchange-transfer.log &
+ echo " DONE"
+fi
+
+STAGE="merchant"
+
+if [ "1" = "$START_MERCHANT" ]
+then
+ echo -n "Starting merchant ..."
+ if [ -n "${USE_MERCHANT_EXCHANGE+x}" ]
+ then
+ MEPUB=$(taler-config -c "$CONF" -s "${USE_MERCHANT_EXCHANGE}" -o MASTER_KEY)
+ MXPUB=${MASTER_PUB:-$(taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY)}
+ if [ "$MEPUB" != "$MXPUB" ]
+ then
+ echo -n " patching master_pub ($MXPUB)..."
+ taler-config -c "$CONF" -s "${USE_MERCHANT_EXCHANGE}" -o MASTER_KEY -V "$MXPUB"
+ fi
+ fi
+ MERCHANT_TYPE=$(taler-config -c "$CONF" -s MERCHANT -o SERVE)
+ if [ "unix" = "$MERCHANT_TYPE" ]
+ then
+ MERCHANT_URL="$(taler-config -c "$CONF" -s MERCHANT -o BASE_URL)"
+ else
+ MERCHANT_PORT="$(taler-config -c "$CONF" -s MERCHANT -o PORT)"
+ MERCHANT_URL="http://localhost:${MERCHANT_PORT}/"
+ fi
+ taler-merchant-dbinit \
+ -c "$CONF" \
+ --reset &> taler-merchant-dbinit.log
+ $USE_VALGRIND taler-merchant-httpd \
+ -c "$CONF" \
+ -L "$LOGLEVEL" 2> taler-merchant-httpd.log &
+ $USE_VALGRIND taler-merchant-webhook \
+ -c "$CONF" \
+ -L "$LOGLEVEL" 2> taler-merchant-webhook.log &
+ echo " DONE"
+ if [ "1" = "$START_MERCHANT_WIREWATCH" ]
+ then
+ echo -n "Starting taler-merchant-wirewatch ..."
+ $USE_VALGRIND taler-merchant-wirewatch \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ --persist \
+ 2> taler-merchant-wirewatch.log &
+ echo " DONE"
+ fi
+ if [ "1" = "$START_MERCHANT_EXCHANGE" ]
+ then
+ echo -n "Starting taler-merchant-exchange ..."
+ $USE_VALGRIND taler-merchant-exchange \
+ -c "$CONF" \
+ -L "$LOGLEVEL" 2> taler-merchant-exchange.log &
+ echo " DONE"
+ fi
+ if [ "1" = "$START_DEPOSITCHECK" ]
+ then
+ echo -n "Starting taler-merchant-depositcheck ..."
+ $USE_VALGRIND taler-merchant-depositcheck \
+ -c "$CONF" \
+ -L "$LOGLEVEL" 2> taler-merchant-depositcheck.log &
+ echo " DONE"
+ fi
+fi
+
+STAGE="sync"
+
+if [ "1" = "$START_BACKUP" ]
+then
+ echo -n "Starting sync ..."
+ SYNC_PORT=$(taler-config -c "$CONF" -s SYNC -o PORT)
+ SERVE=$(taler-config -c "$CONF" -s SYNC -o SERVE)
+ if [ "${SERVE}" = "unix" ]
+ then
+ SYNC_URL=$(taler-config -c "$CONF" -s SYNC -o BASE_URL)
+ else
+ SYNC_URL="http://localhost:${SYNC_PORT}/"
+ fi
+ sync-dbinit -c "$CONF" --reset
+ $USE_VALGRIND sync-httpd \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ 2> sync-httpd.log &
+ echo " DONE"
+fi
+
+STAGE="challenger"
+
+if [ "1" = "$START_CHALLENGER" ]
+then
+ echo -n "Starting challenger ..."
+ CHALLENGER_PORT=$(challenger-config -c "$CONF" -s CHALLENGER -o PORT)
+ SERVE=$(taler-config -c "$CONF" -s CHALLENGER -o SERVE)
+ if [ "${SERVE}" = "unix" ]
+ then
+ CHALLENGER_URL=$(taler-config -c "$CONF" -s CHALLENGER -o BASE_URL)
+ else
+ CHALLENGER_URL="http://localhost:${CHALLENGER_PORT}/"
+ fi
+ challenger-dbinit \
+ -c "$CONF" \
+ --reset
+ $USE_VALGRIND challenger-httpd \
+ -c "$CONF" \
+ -L "$LOGLEVEL" \
+ 2> challenger-httpd.log &
+ echo " DONE"
+ for SECTION in $(taler-config -c "$CONF" -S | grep kyc-provider)
+ do
+ LOGIC=$(taler-config -c "$CONF" -s "$SECTION" -o "LOGIC")
+ if [ "${LOGIC}" = "oauth2" ]
+ then
+ INFO=$(taler-config -c "$CONF" -s "$SECTION" -o "KYC_OAUTH2_INFO_URL")
+ if [ "${CHALLENGER_URL}info" = "$INFO" ]
+ then
+ echo -n "Enabling Challenger client for $SECTION"
+ CLIENT_SECRET=$(taler-config -c "$CONF" -s "$SECTION" -o "KYC_OAUTH2_CLIENT_SECRET")
+ RFC_8959_PREFIX="secret-token:"
+ if ! echo "${CLIENT_SECRET}" | grep ^${RFC_8959_PREFIX} > /dev/null
+ then
+ exit_fail "Client secret does not begin with '${RFC_8959_PREFIX}'"
+ fi
+ REDIRECT_URI="${EXCHANGE_URL}kyc-proof/kyc-provider-example-challeger"
+ CLIENT_ID=$(challenger-admin --add="${CLIENT_SECRET}" --quiet "${REDIRECT_URI}")
+ taler-config -c "$CONF" -s "$SECTION" -o KYC_OAUTH2_CLIENT_ID -V "$CLIENT_ID"
+ echo " DONE"
+ fi
+ fi
+ done
+fi
+
+STAGE="auditor"
+
+if [ "1" = "$START_AUDITOR" ]
+then
+ echo -n "Starting auditor ..."
+ AUDITOR_URL=$(taler-config -c "$CONF" -s AUDITOR -o BASE_URL)
+ AUDITOR_PRIV_FILE=$(taler-config -f -c "$CONF" -s AUDITOR -o AUDITOR_PRIV_FILE)
+ AUDITOR_PRIV_DIR=$(dirname "$AUDITOR_PRIV_FILE")
+ mkdir -p "$AUDITOR_PRIV_DIR"
+ if [ ! -e "$AUDITOR_PRIV_FILE" ]
+ then
+ gnunet-ecc -g1 "$AUDITOR_PRIV_FILE" > /dev/null 2> /dev/null
+ echo -n "."
+ fi
+ AUDITOR_PUB=$(gnunet-ecc -p "${AUDITOR_PRIV_FILE}")
+ MAPUB=${MASTER_PUB:-$(taler-config -c "$CONF" -s exchange -o MASTER_PUBLIC_KEY)}
+ taler-auditor-dbinit \
+ -c "$CONF" \
+ --reset
+ $USE_VALGRIND taler-auditor-httpd \
+ -L "$LOGLEVEL" \
+ -c "$CONF" 2> taler-auditor-httpd.log &
+# $USE_VALGRIND taler-helper-auditor-deposits \
+# -L "$LOGLEVEL" \
+# -c "$CONF" 2> taler-helper-auditor.log &
+ echo " DONE"
+fi
+
+STAGE="wait"
+
+echo -n "Waiting for Taler services ..."
+# Wait for all other taler services to be available
+E_DONE=0
+M_DONE=0
+S_DONE=0
+K_DONE=0
+A_DONE=0
+for n in $(seq 1 20)
+do
+ sleep "$DEFAULT_SLEEP"
+ OK="0"
+ if [ "0" = "$E_DONE" ] && [ "1" = "$START_EXCHANGE" ]
+ then
+ echo -n "E"
+ wget \
+ --tries=1 \
+ --timeout=1 \
+ "${EXCHANGE_URL}config" \
+ -o /dev/null \
+ -O /dev/null >/dev/null || continue
+ E_DONE=1
+ fi
+ if [ "0" = "$M_DONE" ] && [ "1" = "$START_MERCHANT" ]
+ then
+ echo -n "M"
+ wget \
+ --tries=1 \
+ --timeout=1 \
+ "${MERCHANT_URL}config" \
+ -o /dev/null \
+ -O /dev/null >/dev/null || continue
+ M_DONE=1
+ fi
+ if [ "0" = "$S_DONE" ] && [ "1" = "$START_BACKUP" ]
+ then
+ echo -n "S"
+ wget \
+ --tries=1 \
+ --timeout=1 \
+ "${SYNC_URL}config" \
+ -o /dev/null \
+ -O /dev/null >/dev/null || continue
+ S_DONE=1
+ fi
+ if [ "0" = "$K_DONE" ] && [ "1" = "$START_CHALLENGER" ]
+ then
+ echo -n "K"
+ wget \
+ --tries=1 \
+ --timeout=1 \
+ "${CHALLENGER_URL}config" \
+ -o /dev/null \
+ -O /dev/null >/dev/null || continue
+ K_DONE=1
+ fi
+ if [ "0" = "$A_DONE" ] && [ "1" = "$START_AUDITOR" ]
+ then
+ echo -n "A"
+ wget \
+ --tries=1 \
+ --timeout=1 \
+ "${AUDITOR_URL}config" \
+ -o /dev/null \
+ -O /dev/null >/dev/null || continue
+ A_DONE=1
+ fi
+ OK="1"
+ break
+done
+if [ 1 != "$OK" ]
+then
+ exit_skip "Failed to launch (some) Taler services"
+fi
+echo " OK"
+
+if [ "1" = "$START_EXCHANGE" ]
+then
+ echo -n "Wait for exchange /management/keys to be ready "
+ OK="0"
+ LAST_RESPONSE=$(mktemp tmp-last-response.XXXXXXXX)
+ for n in $(seq 1 10)
+ do
+ echo -n "."
+ sleep "$DEFAULT_SLEEP"
+ # exchange
+ wget \
+ --tries=3 \
+ --waitretry=0 \
+ --timeout=30 \
+ "${EXCHANGE_URL}management/keys"\
+ -o /dev/null \
+ -O "$LAST_RESPONSE" \
+ >/dev/null || continue
+ OK="1"
+ break;
+ done
+ if [ "1" != "$OK" ]
+ then
+ cat "$LAST_RESPONSE"
+ exit_fail "Failed to setup exchange keys, check secmod logs"
+ fi
+ rm "$LAST_RESPONSE"
+ echo " OK"
+
+ echo -n "Setting up exchange keys ..."
+ taler-exchange-offline -c "$CONF" \
+ download \
+ sign \
+ wire-fee now "$WIRE_DOMAIN" "$CURRENCY:0.01" "$CURRENCY:0.01" \
+ global-fee now "$CURRENCY:0.01" "$CURRENCY:0.01" "$CURRENCY:0.0" 1h 1year 5 \
+ upload &> taler-exchange-offline.log
+ echo "OK"
+ ENABLED=$(taler-config -c "$CONF" -s "$USE_ACCOUNT" -o "ENABLE_CREDIT")
+ if [ "YES" = "$ENABLED" ]
+ then
+ echo -n "Configuring bank account $USE_ACCOUNT ..."
+ EXCHANGE_PAYTO_URI=$(taler-config -c "$CONF" -s "$USE_ACCOUNT" -o "PAYTO_URI")
+ taler-exchange-offline -c "$CONF" \
+ enable-account "$EXCHANGE_PAYTO_URI" \
+ upload &> "taler-exchange-offline-account.log"
+ echo " OK"
+ else
+ echo "WARNING: Account ${USE_ACCOUNT} not enabled (set to: '$ENABLED')"
+ fi
+ if [ "1" = "$START_AUDITOR" ]
+ then
+ echo -n "Enabling auditor ..."
+ taler-exchange-offline -c "$CONF" \
+ enable-auditor "$AUDITOR_PUB" "$AUDITOR_URL" "$CURRENCY Auditor" \
+ upload &> taler-exchange-offline-auditor.log
+ echo "OK"
+ fi
+
+ echo -n "Checking /keys "
+ OK="0"
+ LAST_RESPONSE=$(mktemp tmp-last-response.XXXXXXXX)
+ for n in $(seq 1 10)
+ do
+ echo -n "."
+ sleep "$DEFAULT_SLEEP"
+ wget \
+ --tries=1 \
+ --timeout=5 \
+ "${EXCHANGE_URL}keys" \
+ -a wget-keys-check.log \
+ -o /dev/null \
+ -O "$LAST_RESPONSE" \
+ >/dev/null || continue
+ OK="1"
+ break
+ done
+ if [ "1" != "$OK" ]
+ then
+ cat "$LAST_RESPONSE"
+ exit_fail " Failed to fetch ${EXCHANGE_URL}keys"
+ fi
+ rm "$LAST_RESPONSE"
+ echo " OK"
+fi
+
+if [ "1" = "$START_AUDITOR" ]
+then
+ echo -n "Setting up auditor signatures ..."
+ timeout 15 taler-auditor-offline -c "$CONF" \
+ download \
+ sign \
+ upload &> taler-auditor-offline.log
+ echo " OK"
+fi
+
+STAGE="ready"
+
+# Signal caller that we are ready.
+echo "<<READY>>"
+
+if [ "1" = "$WAIT_FOR_SIGNAL" ]
+then
+ while true
+ do
+ sleep 0.1
+ done
+else
+ # Wait until caller stops us.
+ # shellcheck disable=SC2162
+ read
+fi
+
+STAGE="exiting"
+
+echo "Taler unified setup terminating!" >&2
+EXIT_STATUS=0
+exit "$EXIT_STATUS"
diff --git a/src/testing/test-taler-exchange-aggregator-postgres.conf b/src/testing/test-taler-exchange-aggregator-postgres.conf
index 7f277629d..8c3ee4ba5 100644
--- a/src/testing/test-taler-exchange-aggregator-postgres.conf
+++ b/src/testing/test-taler-exchange-aggregator-postgres.conf
@@ -1,84 +1,59 @@
+# This file is in the public domain.
+
[PATHS]
# Persistent data storage for the testcase
TALER_TEST_HOME = test_taler_exchange_httpd_home/
-TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
[taler-exchange-secmod-rsa]
# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
[taler-exchange-secmod-eddsa]
-# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
-# Reduce from 12 weeks to ensure we have multiple
DURATION = 14 days
[taler]
-# Currency supported by the exchange (can only be one)
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
[exchange]
-# The DB plugin to use
+AML_THRESHOLD = EUR:1000000
DB = postgres
-
-# HTTP port the exchange listens to
PORT = 8081
-
-# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-
-# Expected base URL of the exchange. Used in wire transfers for
-# the tracking API.
BASE_URL = "http://localhost:8081/"
[auditor]
BASE_URL = "http://auditor.example.com/"
+PORT = 8083
[auditordb-postgres]
CONFIG = "postgres:///talercheck"
[exchangedb]
-# After how long do we close idle reserves? The exchange
-# and the auditor must agree on this value. We currently
-# expect it to be globally defined for the whole system,
-# as there is no way for wallets to query this value. Thus,
-# it is only configurable for testing, and should be treated
-# as constant in production.
IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
+LEGAL_RESERVE_EXPIRATION_TIME = 7 years
[exchangedb-postgres]
-
-#The connection string the plugin has to use for connecting to the database
CONFIG = postgres:///talercheck
-[exchangedb]
-
-# After how long do we close idle reserves? The exchange
-# and the auditor must agree on this value. We currently
-# expect it to be globally defined for the whole system,
-# as there is no way for wallets to query this value. Thus,
-# it is only configurable for testing, and should be treated
-# as constant in production.
-IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
-
-# After how long do we forget about reserves? Should be above
-# the legal expiration timeframe of withdrawn coins.
-LEGAL_RESERVE_EXPIRATION_TIME = 7 years
-
[exchange-account-1]
-
# What is the account URL?
-PAYTO_URI = "payto://x-taler-bank/localhost/2"
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
[exchange-accountcredentials-1]
-WIRE_GATEWAY_URL = "http://localhost:8082/2/"
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
WIRE_GATEWAY_AUTH_METHOD = basic
USERNAME = Exchange
PASSWORD = x
+[admin-accountcredentials-1]
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
[bank]
HTTP_PORT = 8082
@@ -92,4 +67,5 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
+CIPHER = RSA
rsa_keysize = 1024
diff --git a/src/testing/test-taler-exchange-wirewatch-postgres.conf b/src/testing/test-taler-exchange-wirewatch-postgres.conf
index d42f9d445..4f13077ac 100644
--- a/src/testing/test-taler-exchange-wirewatch-postgres.conf
+++ b/src/testing/test-taler-exchange-wirewatch-postgres.conf
@@ -1,68 +1,55 @@
+# This file is in the public domain.
+
[PATHS]
# Persistent data storage for the testcase
TALER_TEST_HOME = test_taler_exchange_httpd_home/
-TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
[taler-exchange-secmod-rsa]
-# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
[taler-exchange-secmod-eddsa]
-# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
-# Reduce from 12 weeks to ensure we have multiple
DURATION = 14 days
[taler]
-# Currency supported by the exchange (can only be one)
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
[exchange]
-# The DB plugin to use
+AML_THRESHOLD = EUR:1000000
DB = postgres
-
-# HTTP port the exchange listens to
PORT = 8081
-
-# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-
-# Expected base URL of the exchange.
BASE_URL = "http://localhost:8081/"
[exchangedb]
-# After how long do we close idle reserves? The exchange
-# and the auditor must agree on this value. We currently
-# expect it to be globally defined for the whole system,
-# as there is no way for wallets to query this value. Thus,
-# it is only configurable for testing, and should be treated
-# as constant in production.
-#
# This is THE test that requires a short reserve expiration time!
IDLE_RESERVE_EXPIRATION_TIME = 4 s
[exchangedb-postgres]
-#The connection string the plugin has to use for connecting to the database
-CONFIG = "postgres:///talercheck"
-
-[auditordb-postgres]
CONFIG = "postgres:///talercheck"
[auditor]
BASE_URL = "http://localhost:8083/"
-
-# HTTP port the auditor listens to
PORT = 8083
+[auditordb-postgres]
+CONFIG = "postgres:///talercheck"
+
[exchange-account-1]
# What is the account URL?
-PAYTO_URI = "payto://x-taler-bank/localhost/2"
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
[exchange-accountcredentials-1]
-WIRE_GATEWAY_URL = "http://localhost:8082/2/"
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
+
+[admin-accountcredentials-1]
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
WIRE_GATEWAY_AUTH_METHOD = basic
USERNAME = Exchange
PASSWORD = x
@@ -70,6 +57,16 @@ PASSWORD = x
[bank]
HTTP_PORT = 8082
+[libeufin-bank]
+CURRENCY = EUR
+DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200
+DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000
+REGISTRATION_BONUS_ENABLED = yes
+REGISTRATION_BONUS = EUR:100
+SUGGESTED_WITHDRAWAL_EXCHANGE = http://localhost:8081/
+SERVE = tcp
+PORT = 8082
+
# Need at least one coin, otherwise Exchange
# refuses to start.
[coin_eur_ct_1]
@@ -81,4 +78,5 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
+CIPHER = RSA
rsa_keysize = 1024
diff --git a/src/testing/test_auditor_api-cs.conf b/src/testing/test_auditor_api-cs.conf
new file mode 100644
index 000000000..b80696fb2
--- /dev/null
+++ b/src/testing/test_auditor_api-cs.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ coins-cs.conf
+@INLINE@ test_exchange_api.conf
diff --git a/src/testing/test_auditor_api-rsa.conf b/src/testing/test_auditor_api-rsa.conf
new file mode 100644
index 000000000..671e81108
--- /dev/null
+++ b/src/testing/test_auditor_api-rsa.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ coins-rsa.conf
+@INLINE@ test_exchange_api.conf
diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c
index 2ea173569..3810c601e 100644
--- a/src/testing/test_auditor_api.c
+++ b/src/testing/test_auditor_api.c
@@ -29,6 +29,7 @@
#include "taler_auditor_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@@ -39,20 +40,14 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
-#define CONFIG_FILE "test_auditor_api.conf"
+static char *config_file;
-#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
- "test_auditor_api_expire_reserve_now.conf"
+static char *config_file_expire_reserve_now;
/**
- * Exchange configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
+static struct TALER_TESTING_Credentials cred;
/**
* Execute the taler-exchange-wirewatch command with
@@ -61,7 +56,7 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_EXEC_WIREWATCH(label) \
- TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
+ TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, "exchange-account-2")
/**
* Execute the taler-exchange-aggregator, closer and transfer commands with
@@ -70,8 +65,9 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_EXEC_AGGREGATOR(label) \
- TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE), \
- TALER_TESTING_cmd_exec_transfer (label, CONFIG_FILE)
+ TALER_TESTING_cmd_sleep (label "-sleep", 1), \
+ TALER_TESTING_cmd_exec_aggregator (label, config_file), \
+ TALER_TESTING_cmd_exec_transfer (label, config_file)
/**
* Run wire transfer of funds from some user's account to the
@@ -82,8 +78,8 @@ static struct TALER_TESTING_BankConfiguration bc;
*/
#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
TALER_TESTING_cmd_admin_add_incoming (label, amount, \
- &bc.exchange_auth, \
- bc.user42_payto)
+ &cred.ba, \
+ cred.user42_payto)
/**
* Run the taler-auditor.
@@ -91,7 +87,7 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_RUN_AUDITOR(label) \
- TALER_TESTING_cmd_exec_auditor (label, CONFIG_FILE)
+ TALER_TESTING_cmd_exec_auditor (label, config_file)
/**
@@ -115,7 +111,7 @@ run (void *cls,
"EUR:5.01"),
TALER_TESTING_cmd_check_bank_admin_transfer
("check-create-reserve-1",
- "EUR:5.01", bc.user42_payto, bc.exchange_payto,
+ "EUR:5.01", cred.user42_payto, cred.exchange_payto,
"create-reserve-1"),
/**
* Make a reserve exist, according to the previous transfer.
@@ -127,6 +123,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
"create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_end ()
};
@@ -138,7 +135,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-simple",
"withdraw-coin-1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:5",
@@ -155,7 +152,7 @@ run (void *cls,
"EUR:5.01"),
TALER_TESTING_cmd_check_bank_admin_transfer
("check-refresh-create-reserve-1",
- "EUR:5.01", bc.user42_payto, bc.exchange_payto,
+ "EUR:5.01", cred.user42_payto, cred.exchange_payto,
"refresh-create-reserve-1"),
/**
* Make previous command effective.
@@ -167,6 +164,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
"refresh-create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/**
* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in
@@ -175,14 +173,15 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("refresh-deposit-partial",
"refresh-withdraw-coin-1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:1\"}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
MHD_HTTP_OK),
/**
* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x
- * EUR:0.13) */
+ * EUR:0.13)
+ */
TALER_TESTING_cmd_melt_double ("refresh-melt-1",
"refresh-withdraw-coin-1",
MHD_HTTP_OK,
@@ -199,7 +198,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b",
"refresh-reveal-1",
3,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:0.1",
@@ -213,74 +212,83 @@ run (void *cls,
* 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!*///
+ * a lot! */
CMD_EXEC_AGGREGATOR ("run-aggregator"),
/**
* Check all the transfers took place.
*/
- TALER_TESTING_cmd_check_bank_transfer
- ("check_bank_transfer-499c", ec.exchange_url,
- "EUR:4.98", bc.exchange_payto, bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check_bank_transfer-99c1", ec.exchange_url,
- "EUR:0.98", bc.exchange_payto, bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check_bank_transfer-99c", ec.exchange_url,
- "EUR:0.08", bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer (
+ "check_bank_transfer-499c",
+ cred.exchange_url,
+ "EUR:4.98",
+ cred.exchange_payto,
+ cred.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer (
+ "check_bank_transfer-99c1",
+ cred.exchange_url,
+ "EUR:0.98",
+ cred.exchange_payto,
+ cred.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer (
+ "check_bank_transfer-99c",
+ cred.exchange_url,
+ "EUR:0.08",
+ cred.exchange_payto,
+ cred.user43_payto),
/* The following transactions got originated within
* the "massive deposit confirms" batch. */
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-1",
- ec.exchange_url,
+ TALER_TESTING_cmd_check_bank_transfer (
+ "check-massive-transfer-1",
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-2",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-3",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-4",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-5",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-6",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-7",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-8",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-9",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_transfer
("check-massive-transfer-10",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
+ cred.exchange_payto, cred.user43_payto),
TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
TALER_TESTING_cmd_end ()
};
@@ -298,17 +306,18 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_admin_transfer (
"check_bank_transfer-unaggregated",
"EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"create-reserve-unaggregated"),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
"create-reserve-unaggregated",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit ("deposit-unaggregated",
"withdraw-coin-unaggregated",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_YEARS,
@@ -336,6 +345,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
"create-reserve-r1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/**
* Spend 5 EUR of the 5 EUR coin (in full). Merchant would
@@ -344,7 +354,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-refund-1",
"withdraw-coin-r1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_MINUTES,
"EUR:5",
@@ -361,7 +371,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-refund-2",
"withdraw-coin-r1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"more\",\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:4.99",
@@ -391,15 +401,15 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
"recoup-create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_revoke ("revoke-1",
MHD_HTTP_OK,
"recoup-withdraw-coin-1",
- CONFIG_FILE),
+ config_file),
TALER_TESTING_cmd_recoup ("recoup-1",
MHD_HTTP_OK,
"recoup-withdraw-coin-1",
- NULL,
"EUR:5"),
/**
* Re-withdraw from this reserve
@@ -407,17 +417,20 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
"recoup-create-reserve-1",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/**
* These commands should close the reserve because the aggregator
* is given a config file that overrides the reserve expiration
* time (making it now-ish)
- */CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
"EUR:5.01"),
- TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
+ TALER_TESTING_cmd_exec_wirewatch2 ("short-lived-aggregation",
+ config_file_expire_reserve_now,
+ "exchange-account-2"),
TALER_TESTING_cmd_exec_aggregator ("close-reserves",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
+ config_file_expire_reserve_now),
/**
* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
* config, then withdraw two coin, partially spend one, and
@@ -436,6 +449,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
"recoup-create-reserve-2",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/**
* Withdraw a 1 EUR coin, at fee of 1 ct
@@ -443,11 +457,12 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
"recoup-create-reserve-2",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
"recoup-withdraw-coin-2a",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:0.5",
@@ -455,11 +470,10 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-2",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
- CONFIG_FILE),
+ config_file),
TALER_TESTING_cmd_recoup ("recoup-2",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
- NULL,
"EUR:0.5"),
TALER_TESTING_cmd_end ()
};
@@ -472,57 +486,68 @@ run (void *cls,
*/
CMD_TRANSFER_TO_EXCHANGE ("massive-reserve",
"EUR:10.10"),
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check-massive-transfer",
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "check-massive-transfer",
"EUR:10.10",
- bc.user42_payto, bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"massive-reserve"),
CMD_EXEC_WIREWATCH ("massive-wirewatch"),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-2",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-3",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-4",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-5",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-6",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-7",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-8",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-9",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-10",
"massive-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-1",
+ TALER_TESTING_cmd_deposit (
+ "massive-deposit-1",
"massive-withdraw-1",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -531,7 +556,7 @@ run (void *cls,
("massive-deposit-2",
"massive-withdraw-2",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -540,7 +565,7 @@ run (void *cls,
("massive-deposit-3",
"massive-withdraw-3",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -549,7 +574,7 @@ run (void *cls,
("massive-deposit-4",
"massive-withdraw-4",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -558,7 +583,7 @@ run (void *cls,
("massive-deposit-5",
"massive-withdraw-5",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -567,7 +592,7 @@ run (void *cls,
("massive-deposit-6",
"massive-withdraw-6",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -576,7 +601,7 @@ run (void *cls,
("massive-deposit-7",
"massive-withdraw-7",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -585,7 +610,7 @@ run (void *cls,
("massive-deposit-8",
"massive-withdraw-8",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -594,24 +619,23 @@ run (void *cls,
("massive-deposit-9",
"massive-withdraw-9",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-10",
+ TALER_TESTING_cmd_deposit (
+ "massive-deposit-10",
"massive-withdraw-10",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit_confirmation ("deposit-confirmation",
- is->auditor,
"massive-deposit-10",
- 0,
+ 1,
"EUR:0.99",
MHD_HTTP_OK),
CMD_RUN_AUDITOR ("massive-auditor"),
@@ -620,25 +644,25 @@ run (void *cls,
};
struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
- CONFIG_FILE,
- "EUR:0.01",
- "EUR:0.01"),
- TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/2",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
- CONFIG_FILE),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 2),
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-u", "exchange-account-2",
+ "-ae",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_get_auditor ("get-auditor",
+ cred.cfg,
+ true),
+ TALER_TESTING_cmd_exec_auditor_offline ("auditor-offline",
+ config_file),
CMD_RUN_AUDITOR ("virgin-auditor"),
- TALER_TESTING_cmd_exchanges_with_url ("check-exchange",
- MHD_HTTP_OK,
- "http://localhost:8081/"),
TALER_TESTING_cmd_batch ("massive-deposit-confirms",
massive_deposit_confirms),
TALER_TESTING_cmd_batch ("withdraw",
@@ -659,9 +683,9 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
+ (void) cls;
+ TALER_TESTING_run (is,
+ commands);
}
@@ -669,47 +693,28 @@ int
main (int argc,
char *const *argv)
{
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-auditor-api",
- "INFO",
- NULL);
- /* Check fakebank port is available and get configuration data. */
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "exchange-account-2",
- &bc))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- GNUNET_YES,
- &ec))
+ (void) argc;
{
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (GNUNET_OK !=
- /* Set up event loop and reschedule context, plus
- * start/stop the exchange. It calls TALER_TESTING_setup
- * which creates the 'is' object.
- */
- TALER_TESTING_auditor_setup (&run,
- NULL,
- CONFIG_FILE))
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ GNUNET_asprintf (&config_file,
+ "test_auditor_api-%s.conf",
+ cipher);
+ GNUNET_asprintf (&config_file_expire_reserve_now,
+ "test_auditor_api_expire_reserve_now-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
}
- return 0;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_auditor_api.conf b/src/testing/test_auditor_api.conf
deleted file mode 100644
index 03a5e2453..000000000
--- a/src/testing/test_auditor_api.conf
+++ /dev/null
@@ -1,140 +0,0 @@
-
-# This file is in the public domain.
-#
-[PATHS]
-# Persistent data storage for the testcase
-TALER_TEST_HOME = test_exchange_api_home/
-TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
-
-[taler-exchange-secmod-rsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
-
-[taler-exchange-secmod-eddsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
-# Reduce from 12 weeks to ensure we have multiple
-DURATION = 14 days
-
-
-[taler]
-# Currency supported by the exchange (can only be one)
-CURRENCY = EUR
-CURRENCY_ROUND_UNIT = EUR:0.01
-
-[auditor]
-BASE_URL = "http://localhost:8083/"
-
-# HTTP port the auditor listens to
-PORT = 8083
-
-TINY_AMOUNT = EUR:0.01
-
-[exchange]
-
-# HTTP port the exchange listens to
-PORT = 8081
-
-# Master public key used to sign the exchange's various keys
-MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-
-# How to access our database
-DB = postgres
-
-# Base URL of the exchange. Must be set to a URL where the
-# exchange (or the twister) is actually listening.
-BASE_URL = "http://localhost:8081/"
-
-[exchangedb-postgres]
-CONFIG = "postgres:///talercheck"
-
-[auditordb-postgres]
-CONFIG = "postgres:///talercheck"
-
-# Sections starting with "exchange-account-" configure the bank accounts
-# of the exchange. The "URL" specifies the account in
-# payto://-format.
-[exchange-account-1]
-# What is the URL of our account?
-PAYTO_URI = "payto://x-taler-bank/localhost/42"
-
-[exchange-accountcredentials-1]
-WIRE_GATEWAY_URL = "http://localhost:8082/42/"
-
-[bank]
-HTTP_PORT = 8082
-
-# ENABLE_CREDIT = YES
-
-[exchange-account-2]
-# What is the bank account (with the "Taler Bank" demo system)?
-PAYTO_URI = "payto://x-taler-bank/localhost/2"
-ENABLE_DEBIT = YES
-ENABLE_CREDIT = YES
-
-# Authentication information for basic authentication
-[exchange-accountcredentials-2]
-WIRE_GATEWAY_URL = "http://localhost:8082/2/"
-WIRE_GATEWAY_AUTH_METHOD = "basic"
-USERNAME = user
-PASSWORD = pass
-
-
-
-
-# Sections starting with "coin_" specify which denominations
-# the exchange should support (and their respective fee structure)
-[coin_eur_ct_1]
-value = EUR:0.01
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.00
-fee_deposit = EUR:0.00
-fee_refresh = EUR:0.01
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_ct_10]
-value = EUR:0.10
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_1]
-value = EUR:1
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_5]
-value = EUR:5
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_10]
-value = EUR:10
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
diff --git a/src/testing/test_exchange_api_expire_reserve_now.conf b/src/testing/test_auditor_api_expire_reserve_now-cs.conf
index 05bca956b..7277a0dff 100644
--- a/src/testing/test_exchange_api_expire_reserve_now.conf
+++ b/src/testing/test_auditor_api_expire_reserve_now-cs.conf
@@ -1,4 +1,4 @@
-@INLINE@ test_exchange_api.conf
+@INLINE@ test_auditor_api-cs.conf
[exchangedb]
IDLE_RESERVE_EXPIRATION_TIME = 0 s
diff --git a/src/testing/test_auditor_api_expire_reserve_now.conf b/src/testing/test_auditor_api_expire_reserve_now-rsa.conf
index c2bf8f479..788cc36f8 100644
--- a/src/testing/test_auditor_api_expire_reserve_now.conf
+++ b/src/testing/test_auditor_api_expire_reserve_now-rsa.conf
@@ -1,4 +1,4 @@
-@INLINE@ test_auditor_api.conf
+@INLINE@ test_auditor_api-rsa.conf
[exchangedb]
IDLE_RESERVE_EXPIRATION_TIME = 0 s
diff --git a/src/testing/test_auditor_api_version.c b/src/testing/test_auditor_api_version.c
index 7b96525ac..dcd542ad8 100644
--- a/src/testing/test_auditor_api_version.c
+++ b/src/testing/test_auditor_api_version.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -39,9 +39,9 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
-#define CONFIG_FILE "test_auditor_api.conf"
+#define CONFIG_FILE "test_auditor_api-rsa.conf"
-static struct TALER_AUDITOR_Handle *ah;
+static struct TALER_AUDITOR_GetConfigHandle *ah;
static struct GNUNET_CURL_Context *ctx;
@@ -51,6 +51,7 @@ static int global_ret;
static struct GNUNET_SCHEDULER_Task *tt;
+
static void
do_shutdown (void *cls)
{
@@ -61,7 +62,11 @@ do_shutdown (void *cls)
GNUNET_SCHEDULER_cancel (tt);
tt = NULL;
}
- TALER_AUDITOR_disconnect (ah);
+ if (NULL != ah)
+ {
+ TALER_AUDITOR_get_config_cancel (ah);
+ ah = NULL;
+ }
GNUNET_CURL_fini (ctx);
GNUNET_CURL_gnunet_rc_destroy (rc);
}
@@ -81,19 +86,16 @@ do_timeout (void *cls)
* Function called with information about the auditor.
*
* @param cls closure
- * @param hr http response details
- * @param vi basic information about the auditor
- * @param compat protocol compatibility information
+ * @param vr response details
*/
static void
version_cb (void *cls,
- const struct TALER_AUDITOR_HttpResponse *hr,
- const struct TALER_AUDITOR_VersionInformation *vi,
- enum TALER_AUDITOR_VersionCompatibility compat)
+ const struct TALER_AUDITOR_ConfigResponse *vr)
{
- (void) hr;
- if ( (NULL != vi) &&
- (TALER_AUDITOR_VC_MATCH == compat) )
+ (void) cls;
+ ah = NULL;
+ if ( (MHD_HTTP_OK == vr->hr.http_status) &&
+ (TALER_AUDITOR_VC_MATCH == vr->details.ok.compat) )
global_ret = 0;
else
global_ret = 2;
@@ -116,10 +118,10 @@ run (void *cls)
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
&rc);
rc = GNUNET_CURL_gnunet_rc_create (ctx);
- ah = TALER_AUDITOR_connect (ctx,
- auditor_url,
- &version_cb,
- NULL);
+ ah = TALER_AUDITOR_get_config (ctx,
+ auditor_url,
+ &version_cb,
+ NULL);
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
@@ -134,6 +136,8 @@ main (int argc,
{
struct GNUNET_OS_Process *proc;
+ (void) argc;
+ (void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
@@ -145,15 +149,16 @@ main (int argc,
"taler-auditor-httpd",
"taler-auditor-httpd",
"-c", CONFIG_FILE,
+ "-L", "INFO",
NULL);
if (NULL == proc)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-auditor-httpd`,"
- " is your PATH correct?\n");
+ "Failed to run `taler-auditor-httpd`, is your PATH correct?\n");
return 77;
}
- if (0 != TALER_TESTING_wait_auditor_ready ("http://localhost:8083/"))
+ global_ret = TALER_TESTING_wait_httpd_ready ("http://localhost:8083/");
+ if (0 != global_ret)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to launch `taler-auditor-httpd`\n");
@@ -163,7 +168,8 @@ main (int argc,
GNUNET_SCHEDULER_run (&run,
NULL);
}
- GNUNET_OS_process_kill (proc, SIGTERM);
+ GNUNET_OS_process_kill (proc,
+ SIGTERM);
GNUNET_OS_process_wait (proc);
GNUNET_OS_process_destroy (proc);
return global_ret;
diff --git a/src/testing/test_bank_api.c b/src/testing/test_bank_api.c
index e5a125894..8cbc86bbd 100644
--- a/src/testing/test_bank_api.c
+++ b/src/testing/test_bank_api.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016-2020 Taler Systems SA
+ Copyright (C) 2016-2023 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
@@ -34,34 +34,27 @@
#include "taler_testing_lib.h"
#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank.conf"
-#define CONFIG_FILE_PYBANK "test_bank_api_pybank.conf"
+
#define CONFIG_FILE_NEXUS "test_bank_api_nexus.conf"
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
/**
- * Handle to the Py-bank daemon.
+ * Configuration file. It changes based on
+ * whether Nexus or Fakebank are used.
*/
-static struct GNUNET_OS_Process *bankd;
+static const char *cfgfile;
/**
- * Flag indicating whether the test is running against the
- * Fakebank. Set up at runtime.
+ * Our credentials.
*/
-static int with_fakebank;
+static struct TALER_TESTING_Credentials cred;
/**
- * Handles to the libeufin services.
+ * Which bank is the test running against?
+ * Set up at runtime.
*/
-static struct TALER_TESTING_LibeufinServices libeufin_services;
+static enum TALER_TESTING_BankSystem bs;
-/**
- * Needed to shutdown differently.
- */
-static int with_libeufin;
/**
* Main function that will tell the interpreter what commands to
@@ -74,51 +67,76 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_WireTransferIdentifierRawP wtid;
+ const char *ssoptions;
- memset (&wtid, 42, sizeof (wtid));
+ (void) cls;
+ switch (bs)
+ {
+ case TALER_TESTING_BS_FAKEBANK:
+ ssoptions = "-f";
+ break;
+ case TALER_TESTING_BS_IBAN:
+ ssoptions = "-b";
+ break;
+ default:
+ ssoptions = NULL;
+ break;
+ }
+ memset (&wtid,
+ 42,
+ sizeof (wtid));
{
struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_system_start ("start-taler",
+ cfgfile,
+ ssoptions,
+ NULL),
TALER_TESTING_cmd_bank_credits ("history-0",
- &bc.exchange_auth,
+ &cred.ba,
NULL,
1),
TALER_TESTING_cmd_admin_add_incoming ("credit-1",
- "KUDOS:5.01",
- &bc.exchange_auth,
- bc.user42_payto),
+ "EUR:5.01",
+ &cred.ba_admin,
+ cred.user42_payto),
+ /**
+ * This CMD doesn't care about the HTTP response code; that's
+ * because Fakebank and euFin behaves differently when a reserve
+ * pub is duplicate. Fakebank responds with 409, whereas euFin
+ * with 200 but it bounces the payment back to the customer.
+ */
TALER_TESTING_cmd_admin_add_incoming_with_ref ("credit-1-fail",
- "KUDOS:2.01",
- &bc.exchange_auth,
- bc.user42_payto,
+ "EUR:2.01",
+ &cred.ba_admin,
+ cred.user42_payto,
"credit-1",
- MHD_HTTP_CONFLICT),
- TALER_TESTING_cmd_sleep ("Waiting 4s for 'credit-1' to settle",
- 4),
+ -1),
+ /**
+ * Check that the incoming payment with a duplicate
+ * reserve public key didn't make it to the exchange.
+ */
TALER_TESTING_cmd_bank_credits ("history-1c",
- &bc.exchange_auth,
+ &cred.ba,
NULL,
5),
TALER_TESTING_cmd_bank_debits ("history-1d",
- &bc.exchange_auth,
+ &cred.ba,
NULL,
5),
TALER_TESTING_cmd_admin_add_incoming ("credit-2",
- "KUDOS:3.21",
- &bc.exchange_auth,
- bc.user42_payto),
+ "EUR:3.21",
+ &cred.ba_admin,
+ cred.user42_payto),
TALER_TESTING_cmd_transfer ("debit-1",
- "KUDOS:3.22",
- &bc.exchange_auth,
- bc.exchange_payto,
- bc.user42_payto,
+ "EUR:3.22",
+ &cred.ba,
+ cred.exchange_payto,
+ cred.user42_payto,
&wtid,
"http://exchange.example.com/"),
-
- TALER_TESTING_cmd_sleep ("Waiting 5s for 'debit-1' to settle",
- 5),
TALER_TESTING_cmd_bank_debits ("history-2b",
- &bc.exchange_auth,
+ &cred.ba,
NULL,
5),
TALER_TESTING_cmd_end ()
@@ -126,150 +144,53 @@ run (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Bank serves at `%s'\n",
- bc.exchange_auth.wire_gateway_url);
- if (GNUNET_YES == with_fakebank)
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
- else
- TALER_TESTING_run (is,
- commands);
+ cred.ba.wire_gateway_url);
+ TALER_TESTING_run (is,
+ commands);
}
}
-/**
- * Runs #TALER_TESTING_setup() using the configuration.
- *
- * @param cls unused
- * @param cfg configuration to use
- * @return status code
- */
-static int
-setup_with_cfg (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- (void) cls;
- return TALER_TESTING_setup (&run,
- NULL,
- cfg,
- NULL,
- GNUNET_NO);
-}
-
-
int
main (int argc,
char *const *argv)
{
- int rv;
- const char *cfgfile;
-
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-bank-api",
- "DEBUG",
- NULL);
-
- with_fakebank = TALER_TESTING_has_in_name (argv[0],
- "_with_fakebank");
- if (GNUNET_YES == with_fakebank)
+ (void) argc;
+ if (TALER_TESTING_has_in_name (argv[0],
+ "_with_fakebank"))
{
- TALER_LOG_DEBUG ("Running against the Fakebank.\n");
+ bs = TALER_TESTING_BS_FAKEBANK;
cfgfile = CONFIG_FILE_FAKEBANK;
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE_FAKEBANK,
- "exchange-account-2",
- &bc))
- {
- GNUNET_break (0);
- return 77;
- }
}
- else if (GNUNET_YES == TALER_TESTING_has_in_name (argv[0],
- "_with_pybank"))
+ else if (TALER_TESTING_has_in_name (argv[0],
+ "_with_nexus"))
{
- TALER_LOG_DEBUG ("Running against the Pybank.\n");
- cfgfile = CONFIG_FILE_PYBANK;
- if (GNUNET_OK !=
- TALER_TESTING_prepare_bank (CONFIG_FILE_PYBANK,
- GNUNET_YES,
- "exchange-account-2",
- &bc))
- {
- GNUNET_break (0);
- return 77;
- }
-
- if (NULL == (bankd = TALER_TESTING_run_bank (
- CONFIG_FILE_PYBANK,
- bc.exchange_auth.wire_gateway_url)))
- {
- GNUNET_break (0);
- return 77;
- }
- }
- else if (GNUNET_YES == TALER_TESTING_has_in_name (argv[0],
- "_with_nexus"))
- {
- TALER_LOG_DEBUG ("Running with Nexus.\n");
- with_libeufin = GNUNET_YES;
+ bs = TALER_TESTING_BS_IBAN;
cfgfile = CONFIG_FILE_NEXUS;
- if (GNUNET_OK !=
- TALER_TESTING_prepare_nexus (CONFIG_FILE_NEXUS,
- GNUNET_YES,
- "exchange-account-2",
- &bc))
+ if (GNUNET_SYSERR ==
+ GNUNET_OS_check_helper_binary ("libeufin-bank",
+ false,
+ NULL))
{
- GNUNET_break (0);
+ fprintf (stderr,
+ "libeufin-bank not found. Skipping test.\n");
return 77;
}
- libeufin_services = TALER_TESTING_run_libeufin (&bc);
- if ( (NULL == libeufin_services.nexus) ||
- (NULL == libeufin_services.sandbox) )
- return 77;
}
else
{
- /* no bank service was ever invoked. */
+ /* no bank service was specified. */
+ GNUNET_break (0);
return 77;
}
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_parse_and_run (cfgfile,
- &setup_with_cfg,
- NULL))
- rv = 1;
- else
- rv = 0;
-
- if (GNUNET_NO == with_fakebank)
- {
- // -> pybank
- if (GNUNET_NO == with_libeufin)
- {
-
- GNUNET_OS_process_kill (bankd,
- SIGKILL);
- GNUNET_OS_process_wait (bankd);
- GNUNET_OS_process_destroy (bankd);
- }
- else // -> libeufin
- {
- GNUNET_OS_process_kill (libeufin_services.nexus,
- SIGKILL);
- GNUNET_OS_process_wait (libeufin_services.nexus);
- GNUNET_OS_process_destroy (libeufin_services.nexus);
-
- GNUNET_OS_process_kill (libeufin_services.sandbox,
- SIGKILL);
- GNUNET_OS_process_wait (libeufin_services.sandbox);
- GNUNET_OS_process_destroy (libeufin_services.sandbox);
- }
- }
-
- return rv;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ cfgfile,
+ "exchange-account-2",
+ bs,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_bank_api.conf b/src/testing/test_bank_api.conf
new file mode 100644
index 000000000..c262ae197
--- /dev/null
+++ b/src/testing/test_bank_api.conf
@@ -0,0 +1,23 @@
+# This file is in the public domain
+
+[PATHS]
+TALER_TEST_HOME = test_exchange_api_home/
+
+[taler]
+currency = EUR
+
+[bank]
+SERVE = http
+HTTP_PORT = 8082
+
+[libeufin-bank]
+CURRENCY = EUR
+WIRE_TYPE = iban
+IBAN_PAYTO_BIC = SANDBOXX=
+DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200
+DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000
+REGISTRATION_BONUS_ENABLED = yes
+REGISTRATION_BONUS = EUR:100
+SUGGESTED_WITHDRAWAL_EXCHANGE = http://localhost:8081/
+SERVE = tcp
+PORT = 8082
diff --git a/src/testing/test_bank_api_fakebank.conf b/src/testing/test_bank_api_fakebank.conf
index b97423987..62fa4cd4c 100644
--- a/src/testing/test_bank_api_fakebank.conf
+++ b/src/testing/test_bank_api_fakebank.conf
@@ -1,21 +1,21 @@
# This file is in the public domain.
+@INLINE@ test_bank_api.conf
-[taler]
-currency = KUDOS
+[exchange-account-1]
+PAYTO_URI = "payto://x-taler-bank/localhost:8082/1?receiver-name=1"
[exchange-account-2]
-PAYTO_URI = payto://x-taler-bank/localhost/2
+PAYTO_URI = "payto://x-taler-bank/localhost:8082/2?receiver-name=2"
[exchange-accountcredentials-2]
-WIRE_GATEWAY_URL = "http://localhost:8081/2/"
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
WIRE_GATEWAY_AUTH_METHOD = basic
USERNAME = Exchange
PASSWORD = x
-[bank]
-SERVE = http
-HTTP_PORT = 8081
-DATABASE = postgres:///talercheck
-
-[auditor]
-BASE_URL = "http://localhost:8083/"
+[admin-accountcredentials-2]
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+WIRE_GATEWAY_AUTH_METHOD = basic
+# For now, fakebank still checks against the Exchange account...
+USERNAME = Exchange
+PASSWORD = x
diff --git a/src/testing/test_bank_api_fakebank_twisted.conf b/src/testing/test_bank_api_fakebank_twisted.conf
index 4dab123a7..bc66c0d88 100644
--- a/src/testing/test_bank_api_fakebank_twisted.conf
+++ b/src/testing/test_bank_api_fakebank_twisted.conf
@@ -1,12 +1,15 @@
+# This file is in the public domain.
+
+@INLINE@ test_bank_api_fakebank.conf
[twister]
+
# HTTP listen port for twister
HTTP_PORT = 8888
SERVE = tcp
-
# HTTP Destination for twister. The test-Webserver needs
# to listen on the port used here. Note: no trailing '/'!
-DESTINATION_BASE_URL = "http://localhost:8081"
+DESTINATION_BASE_URL = "http://localhost:8082"
# Control port for TCP
# PORT = 8889
@@ -18,20 +21,3 @@ ACCEPT_FROM6 = ::1;
UNIXPATH = /tmp/taler-service-twister.sock
UNIX_MATCH_UID = NO
UNIX_MATCH_GID = YES
-
-[taler]
-currency = KUDOS
-
-[bank]
-serve = http
-http_port = 8081
-database = postgres:///talercheck
-
-[exchange-account-1]
-PAYTO_URI = payto://x-taler-bank/localhost:8081/1
-
-[exchange-account-2]
-PAYTO_URI = payto://x-taler-bank/localhost:8081/2
-
-[auditor]
-BASE_URL = "http://localhost:8083/"
diff --git a/src/testing/test_bank_api_nexus.conf b/src/testing/test_bank_api_nexus.conf
index c514170e1..605c7b00e 100644
--- a/src/testing/test_bank_api_nexus.conf
+++ b/src/testing/test_bank_api_nexus.conf
@@ -1,23 +1,35 @@
# This file is in the public domain.
-
-[taler]
-currency = KUDOS
+@INLINE@ test_bank_api.conf
[exchange-account-2]
PAYTO_URI = payto://iban/BIC/ES9121000418450200051332?receiver-name=Exchange
[exchange-accountcredentials-2]
-WIRE_GATEWAY_URL = http://localhost:5001/facades/my-facade/taler/
+WIRE_GATEWAY_URL = http://localhost:8082/accounts/exchange/taler-wire-gateway/
WIRE_GATEWAY_AUTH_METHOD = basic
-# the exchange authenticates as the 'admin' user,
-# since that makes the test preparation just easier.
-USERNAME = Exchange
+USERNAME = exchange
PASSWORD = x
-[bank]
-# not (!) used by the nexus, only by the helper
-# check to make sure the port is free for the nexus.
-HTTP_PORT = 5001
+[admin-accountcredentials-2]
+WIRE_GATEWAY_URL = http://localhost:8082/accounts/exchange/taler-wire-gateway/
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = admin
+# 'secret' is from taler-unified-setup.sh
+PASSWORD = secret
+
+[libeufin-bankdb-postgres]
+CONFIG="postgresql:///talercheck"
-[auditor]
-BASE_URL = "http://localhost:8083/"
+# libeufin doesn't search our config.d/currencies.conf
+# as it has a different resource path. Thus replicated
+# here.
+[currency-euro]
+ENABLED = YES
+name = "Euro"
+code = "EUR"
+decimal_separator = ","
+fractional_input_digits = 2
+fractional_normal_digits = 2
+fractional_trailing_zero_digits = 2
+is_currency_name_leading = NO
+alt_unit_names = {"0":"€"}
diff --git a/src/testing/test_bank_api_pybank.conf b/src/testing/test_bank_api_pybank.conf
deleted file mode 100644
index 6603ba8a5..000000000
--- a/src/testing/test_bank_api_pybank.conf
+++ /dev/null
@@ -1,21 +0,0 @@
-# This file is in the public domain.
-
-[taler]
-currency = KUDOS
-
-[exchange-account-2]
-PAYTO_URI = payto://x-taler-bank/localhost/Exchange
-
-[exchange-accountcredentials-2]
-WIRE_GATEWAY_URL = "http://localhost:8081/taler-wire-gateway/Exchange/"
-WIRE_GATEWAY_AUTH_METHOD = basic
-USERNAME = Exchange
-PASSWORD = x
-
-[bank]
-SERVE = http
-HTTP_PORT = 8081
-DATABASE = postgres:///talercheck
-
-[auditor]
-BASE_URL = "http://localhost:8083/"
diff --git a/src/testing/test_bank_api_pybank_twisted.conf b/src/testing/test_bank_api_pybank_twisted.conf
deleted file mode 100644
index d89cf0469..000000000
--- a/src/testing/test_bank_api_pybank_twisted.conf
+++ /dev/null
@@ -1,43 +0,0 @@
-[twister]
-# HTTP listen port for twister
-HTTP_PORT = 8888
-SERVE = tcp
-
-# HTTP Destination for twister. The test-Webserver needs
-# to listen on the port used here. Note: no trailing '/'!
-DESTINATION_BASE_URL = "http://localhost:8081"
-
-# Control port for TCP
-# PORT = 8889
-HOSTNAME = localhost
-ACCEPT_FROM = 127.0.0.1;
-ACCEPT_FROM6 = ::1;
-
-# Control port for UNIX
-UNIXPATH = /tmp/taler-service-twister.sock
-UNIX_MATCH_UID = NO
-UNIX_MATCH_GID = YES
-
-[auditor]
-BASE_URL = "http://localhost:8083/"
-
-[taler]
-currency = KUDOS
-
-[bank]
-serve = http
-http_port = 8081
-database = postgres:///talercheck
-
-[exchange-account-1]
-PAYTO_URI = payto://x-taler-bank/localhost/1
-
-
-[exchange-account-2]
-PAYTO_URI = payto://x-taler-bank/localhost/Exchange
-
-[exchange-accountcredentials-2]
-WIRE_GATEWAY_URL = "http://localhost:8888/taler-wire-gateway/Exchange/"
-WIRE_GATEWAY_AUTH_METHOD = basic
-USERNAME = Exchange
-PASSWORD = x
diff --git a/src/testing/test_bank_api_twisted.c b/src/testing/test_bank_api_twisted.c
index 8e505cdf3..038ec8a1f 100644
--- a/src/testing/test_bank_api_twisted.c
+++ b/src/testing/test_bank_api_twisted.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -17,7 +17,7 @@
<http://www.gnu.org/licenses/>
*/
/**
- * @file testing/test_bank_api_with_fakebank_twisted.c
+ * @file testing/test_bank_api_twisted.c
* @author Marcello Stanisci
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Christian Grothoff
@@ -42,19 +42,20 @@
#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank_twisted.conf"
/**
- * Separate config file for running with the pybank.
+ * Configuration file we use.
*/
-#define CONFIG_FILE_PYBANK "test_bank_api_pybank_twisted.conf"
+static const char *cfgfile;
/**
- * True when the test runs against Fakebank.
+ * Our credentials.
*/
-static int with_fakebank;
+static struct TALER_TESTING_Credentials cred;
/**
- * Bank configuration data.
+ * Which bank is the test running against?
+ * Set up at runtime.
*/
-static struct TALER_TESTING_BankConfiguration bc;
+static enum TALER_TESTING_BankSystem bs;
/**
* (real) Twister URL. Used at startup time to check if it runs.
@@ -66,11 +67,6 @@ static char *twister_url;
*/
static struct GNUNET_OS_Process *twisterd;
-/**
- * Python bank process handle.
- */
-static struct GNUNET_OS_Process *bankd;
-
/**
* Main function that will tell
@@ -83,174 +79,118 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_WireTransferIdentifierRawP wtid;
- /* Route our commands through twister. */
+ /* Authentication data to route our commands through twister. */
struct TALER_BANK_AuthenticationData exchange_auth_twisted;
+ const char *systype = NULL;
+ (void) cls;
memset (&wtid,
0x5a,
sizeof (wtid));
- memcpy (&exchange_auth_twisted,
- &bc.exchange_auth,
- sizeof (struct TALER_BANK_AuthenticationData));
- if (with_fakebank)
- exchange_auth_twisted.wire_gateway_url =
- "http://localhost:8888/2/";
- else
- exchange_auth_twisted.wire_gateway_url =
- "http://localhost:8888/taler-wire-gateway/Exchange/";
+ GNUNET_memcpy (&exchange_auth_twisted,
+ &cred.ba,
+ sizeof (struct TALER_BANK_AuthenticationData));
+ switch (bs)
+ {
+ case TALER_TESTING_BS_FAKEBANK:
+ exchange_auth_twisted.wire_gateway_url
+ = "http://localhost:8888/accounts/2/taler-wire-gateway/";
+ systype = "-f";
+ break;
+ case TALER_TESTING_BS_IBAN:
+ exchange_auth_twisted.wire_gateway_url
+ = "http://localhost:8888/accounts/Exchange/taler-wire-gateway/";
+ systype = "-b";
+ break;
+ }
+ GNUNET_assert (NULL != systype);
- struct TALER_TESTING_Command commands[] = {
- /* Test retrying transfer after failure. */
- TALER_TESTING_cmd_malform_response ("malform-transfer",
- CONFIG_FILE_FAKEBANK),
- TALER_TESTING_cmd_transfer_retry (
- TALER_TESTING_cmd_transfer ("debit-1",
- "KUDOS:3.22",
- &exchange_auth_twisted,
- bc.exchange_payto,
- bc.user42_payto,
- &wtid,
- "http://exchange.example.com/")),
- TALER_TESTING_cmd_end ()
- };
+ {
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_system_start ("start-taler",
+ cfgfile,
+ systype,
+ NULL),
+ /* Test retrying transfer after failure. */
+ TALER_TESTING_cmd_malform_response ("malform-transfer",
+ cfgfile),
+ TALER_TESTING_cmd_transfer_retry (
+ TALER_TESTING_cmd_transfer ("debit-1",
+ "EUR:3.22",
+ &exchange_auth_twisted,
+ cred.exchange_payto,
+ cred.user42_payto,
+ &wtid,
+ "http://exchange.example.com/")),
+ TALER_TESTING_cmd_end ()
+ };
- if (GNUNET_YES == with_fakebank)
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
- else
TALER_TESTING_run (is,
commands);
+ }
}
/**
* Kill, wait, and destroy convenience function.
*
- * @param process process to purge.
+ * @param[in] process process to purge.
*/
static void
purge_process (struct GNUNET_OS_Process *process)
{
- GNUNET_OS_process_kill (process, SIGINT);
+ GNUNET_OS_process_kill (process,
+ SIGINT);
GNUNET_OS_process_wait (process);
GNUNET_OS_process_destroy (process);
}
-/**
- * Runs #TALER_TESTING_setup() using the configuration.
- *
- * @param cls unused
- * @param cfg configuration to use
- * @return status code
- */
-static int
-setup_with_cfg (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- (void) cls;
- return TALER_TESTING_setup (&run,
- NULL,
- cfg,
- NULL,
- GNUNET_NO);
-}
-
-
int
main (int argc,
char *const *argv)
{
int ret;
- const char *cfgfilename;
-
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-bank-api-with-(fake)bank-twisted",
- "DEBUG",
- NULL);
- with_fakebank = TALER_TESTING_has_in_name (argv[0],
- "_with_fakebank");
-
- if (with_fakebank)
- cfgfilename = CONFIG_FILE_FAKEBANK;
- else
- cfgfilename = CONFIG_FILE_PYBANK;
-
- if (NULL == (twister_url = TALER_TWISTER_prepare_twister (
- cfgfilename)))
- {
- GNUNET_break (0);
- return 77;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "twister_url is %s\n",
- twister_url);
- if (NULL == (twisterd = TALER_TWISTER_run_twister (cfgfilename)))
+ (void) argc;
+ if (TALER_TESTING_has_in_name (argv[0],
+ "_with_fakebank"))
{
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
+ bs = TALER_TESTING_BS_FAKEBANK;
+ cfgfile = CONFIG_FILE_FAKEBANK;
}
- if (GNUNET_YES == with_fakebank)
+ else if (TALER_TESTING_has_in_name (argv[0],
+ "_with_nexus"))
{
- TALER_LOG_DEBUG ("Running against the Fakebank.\n");
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (cfgfilename,
- "exchange-account-2",
- &bc))
- {
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
- }
+ GNUNET_assert (0); /* FIXME: test with nexus not yet implemented */
+ bs = TALER_TESTING_BS_IBAN;
+ /* cfgfile = CONFIG_FILE_NEXUS; */
}
else
{
- TALER_LOG_DEBUG ("Running against the Pybank.\n");
- if (GNUNET_OK !=
- TALER_TESTING_prepare_bank (cfgfilename,
- GNUNET_YES,
- "exchange-account-2",
- &bc))
- {
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
- }
-
- if (NULL == (bankd = TALER_TESTING_run_bank (
- cfgfilename,
- bc.exchange_auth.wire_gateway_url)))
- {
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
- }
+ /* no bank service was specified. */
+ GNUNET_break (0);
+ return 77;
}
- sleep (5);
- ret = GNUNET_CONFIGURATION_parse_and_run (cfgfilename,
- &setup_with_cfg,
- NULL);
+ /* FIXME: introduce commands for twister! */
+ twister_url = TALER_TWISTER_prepare_twister (cfgfile);
+ if (NULL == twister_url)
+ return 77;
+ twisterd = TALER_TWISTER_run_twister (cfgfile);
+ if (NULL == twisterd)
+ return 77;
+ ret = TALER_TESTING_main (argv,
+ "INFO",
+ cfgfile,
+ "exchange-account-2",
+ bs,
+ &cred,
+ &run,
+ NULL);
purge_process (twisterd);
-
- if (GNUNET_NO == with_fakebank)
- {
- GNUNET_OS_process_kill (bankd,
- SIGKILL);
- GNUNET_OS_process_wait (bankd);
- GNUNET_OS_process_destroy (bankd);
- }
-
GNUNET_free (twister_url);
- if (GNUNET_OK == ret)
- return 0;
-
- return 1;
+ return ret;
}
diff --git a/src/testing/test_exchange_api-cs.conf b/src/testing/test_exchange_api-cs.conf
new file mode 100644
index 000000000..b80696fb2
--- /dev/null
+++ b/src/testing/test_exchange_api-cs.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ coins-cs.conf
+@INLINE@ test_exchange_api.conf
diff --git a/src/testing/test_exchange_api-rsa.conf b/src/testing/test_exchange_api-rsa.conf
new file mode 100644
index 000000000..351c876d9
--- /dev/null
+++ b/src/testing/test_exchange_api-rsa.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ coins-rsa.conf
+@INLINE@ test_exchange_api.conf \ No newline at end of file
diff --git a/src/testing/test_exchange_api-twisted.conf b/src/testing/test_exchange_api-twisted.conf
new file mode 100644
index 000000000..536d36ee4
--- /dev/null
+++ b/src/testing/test_exchange_api-twisted.conf
@@ -0,0 +1,29 @@
+# This file is in the public domain.
+
+[exchange]
+# Base URL of the exchange ('S PROXY). This URL is where the
+# twister listens at, so that it will be able to get all the
+# connection addressed to the exchange. In fact, the presence
+# of the twister is 100% transparent to the test case, as it
+# only seeks the exchange/BASE_URL URL to connect to the exchange.
+BASE_URL = "http://localhost:8888/"
+
+[twister]
+# HTTP listen port for twister
+HTTP_PORT = 8888
+SERVE = tcp
+
+# HTTP Destination for twister. The test-Webserver needs
+# to listen on the port used here. Note: no trailing '/'!
+DESTINATION_BASE_URL = "http://localhost:8081"
+
+# Control port for TCP
+# PORT = 8889
+HOSTNAME = localhost
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+
+# Control port for UNIX
+UNIXPATH = /tmp/taler-service-twister.sock
+UNIX_MATCH_UID = NO
+UNIX_MATCH_GID = YES
diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c
index 008eefb20..caeec1e76 100644
--- a/src/testing/test_exchange_api.c
+++ b/src/testing/test_exchange_api.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014--2020 Taler Systems SA
+ Copyright (C) 2014--2022 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
@@ -29,31 +29,38 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
#include "taler_testing_lib.h"
+#include "taler_extensions.h"
/**
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
-#define CONFIG_FILE "test_exchange_api.conf"
-
-#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
- "test_exchange_api_expire_reserve_now.conf"
-
+static char *config_file;
/**
- * Exchange configuration data.
+ * Special configuration file to use when we want reserves
+ * to expire 'immediately'.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
+static char *config_file_expire_reserve_now;
/**
- * Bank configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_BankConfiguration bc;
+static struct TALER_TESTING_Credentials cred;
+/**
+ * Some tests behave differently when using CS as we cannot
+ * reuse the coin private key for different denominations
+ * due to the derivation of it with the /csr values. Hence
+ * some tests behave differently in CS mode, hence this
+ * flag.
+ */
+static bool uses_cs;
/**
* Execute the taler-exchange-wirewatch command with
@@ -62,7 +69,7 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_EXEC_WIREWATCH(label) \
- TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
+ TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, "exchange-account-2")
/**
* Execute the taler-exchange-aggregator, closer and transfer commands with
@@ -71,8 +78,9 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_EXEC_AGGREGATOR(label) \
- TALER_TESTING_cmd_exec_aggregator (label "-aggregator", CONFIG_FILE), \
- TALER_TESTING_cmd_exec_transfer (label "-transfer", CONFIG_FILE)
+ TALER_TESTING_cmd_sleep ("sleep-before-aggregator", 2), \
+ TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
+ TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
/**
@@ -84,8 +92,8 @@ static struct TALER_TESTING_BankConfiguration bc;
*/
#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
TALER_TESTING_cmd_admin_add_incoming (label, amount, \
- &bc.exchange_auth, \
- bc.user42_payto)
+ &cred.ba, \
+ cred.user42_payto)
/**
* Main function that will tell the interpreter what commands to
@@ -99,21 +107,6 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
/**
- * Checks made against /wire response.
- */
- struct TALER_TESTING_Command wire[] = {
- /**
- * Check if 'x-taler-bank' wire method is offered
- * by the exchange.
- */
- TALER_TESTING_cmd_wire ("wire-taler-bank-1",
- "x-taler-bank",
- NULL,
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end ()
- };
-
- /**
* Test withdrawal plus spending.
*/
struct TALER_TESTING_Command withdraw[] = {
@@ -122,30 +115,45 @@ run (void *cls,
*/
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
"EUR:6.02"),
+ TALER_TESTING_cmd_reserve_poll ("poll-reserve-1",
+ "create-reserve-1",
+ "EUR:6.02",
+ GNUNET_TIME_UNIT_MINUTES,
+ MHD_HTTP_OK),
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
"EUR:6.02",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"create-reserve-1"),
/**
* Make a reserve exist, according to the previous
* transfer.
*/
CMD_EXEC_WIREWATCH ("wirewatch-1"),
+ TALER_TESTING_cmd_reserve_poll_finish ("finish-poll-reserve-1",
+ GNUNET_TIME_UNIT_SECONDS,
+ "poll-reserve-1"),
/**
* Withdraw EUR:5.
*/
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
"create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/**
* Withdraw EUR:1 using the SAME private coin key as for the previous coin
* (in violation of the specification, to be detected on spending!).
+ * However, note that this does NOT work with 'CS', as for a different
+ * denomination we get different R0/R1 values from the exchange, and
+ * thus will generate a different coin private key as R0/R1 are hashed
+ * into the coin priv. So here, we fail to 'reuse' the key due to the
+ * cryptographic construction!
*/
TALER_TESTING_cmd_withdraw_amount_reuse_key ("withdraw-coin-1x",
"create-reserve-1",
"EUR:1",
+ 0, /* age restriction off */
"withdraw-coin-1",
MHD_HTTP_OK),
/**
@@ -161,6 +169,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
"create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_CONFLICT),
TALER_TESTING_cmd_end ()
};
@@ -172,29 +181,43 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-simple",
"withdraw-coin-1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:5",
MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay",
+ TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-1",
+ "deposit-simple",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_sleep ("sleep-before-deposit-replay",
+ 1),
+ TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-2",
"deposit-simple",
MHD_HTTP_OK),
+ /* This creates a conflict, as we have the same coin public key (reuse!),
+ but different denomination public keys (which is not allowed).
+ However, note that this does NOT work with 'CS', as for a different
+ denomination we get different R0/R1 values from the exchange, and
+ thus will generate a different coin private key as R0/R1 are hashed
+ into the coin priv. So here, we fail to 'reuse' the key due to the
+ cryptographic construction! */
TALER_TESTING_cmd_deposit ("deposit-reused-coin-key-failure",
"withdraw-coin-1x",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
- MHD_HTTP_CONFLICT),
+ uses_cs
+ ? MHD_HTTP_OK
+ : MHD_HTTP_CONFLICT),
/**
* Try to double spend using different wire details.
*/
TALER_TESTING_cmd_deposit ("deposit-double-1",
"withdraw-coin-1",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:5",
@@ -208,7 +231,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-double-1",
"withdraw-coin-1",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:5",
@@ -219,7 +242,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-double-2",
"withdraw-coin-1",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:5",
@@ -230,7 +253,10 @@ run (void *cls,
struct TALER_TESTING_Command refresh[] = {
/**
* Try to melt the coin that shared the private key with another
- * coin (should fail). */
+ * coin (should fail). Note that in the CS-case, we fail also
+ * with MHD_HTTP_CONFLICT, but for a different reason: here it
+ * is not a denomination conflict, but a double-spending conflict.
+ */
TALER_TESTING_cmd_melt ("refresh-melt-reused-coin-key-failure",
"withdraw-coin-1x",
MHD_HTTP_CONFLICT,
@@ -241,8 +267,8 @@ run (void *cls,
"EUR:5.01"),
TALER_TESTING_cmd_check_bank_admin_transfer ("ck-refresh-create-reserve-1",
"EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"refresh-create-reserve-1"),
/**
* Make previous command effective.
@@ -254,14 +280,16 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
"refresh-create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
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) *///
+ * deposit fee)
+ */
TALER_TESTING_cmd_deposit ("refresh-deposit-partial",
"refresh-withdraw-coin-1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -298,7 +326,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1a",
"refresh-reveal-1-idempotency",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -309,7 +337,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b",
"refresh-reveal-1",
3,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:0.1",
@@ -330,11 +358,74 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
+ /**
+ * Test withdrawal with age restriction. Success is expected, so it MUST be
+ * called _after_ TALER_TESTING_cmd_exec_offline_sign_extensions is called,
+ * i. e. age restriction is activated in the exchange!
+ *
+ * TODO: create a test that tries to withdraw coins with age restriction but
+ * (expectedly) fails because the exchange doesn't support age restriction
+ * yet.
+ */
+ struct TALER_TESTING_Command withdraw_age[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age",
+ "EUR:6.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age",
+ "EUR:6.01",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-age"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-age"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-age-1",
+ "create-reserve-age",
+ "EUR:5",
+ 13,
+ MHD_HTTP_OK),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend_age[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-simple-age",
+ "withdraw-coin-age-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:4.99",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age",
+ "deposit-simple-age",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age-1",
+ "deposit-simple-age",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_sleep ("sleep-before-age-deposit-replay",
+ 1),
+ TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age-2",
+ "deposit-simple-age",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
struct TALER_TESTING_Command track[] = {
/* Try resolving a deposit's WTID, as we never triggered
* execution of transactions, the answer should be that
* the exchange knows about the deposit, but has no WTID yet.
- *///
+ */
TALER_TESTING_cmd_track_transaction ("deposit-wtid-found",
"deposit-simple",
0,
@@ -343,7 +434,7 @@ run (void *cls,
/* Try resolving a deposit's WTID for a failed deposit.
* As the deposit failed, the answer should be that the
* exchange does NOT know about the deposit.
- *///
+ */
TALER_TESTING_cmd_track_transaction ("deposit-wtid-failing",
"deposit-double-2",
0,
@@ -352,42 +443,69 @@ run (void *cls,
/* Try resolving an undefined (all zeros) WTID; this
* should fail as obviously the exchange didn't use that
* WTID value for any transaction.
- *///
+ */
TALER_TESTING_cmd_track_transfer_empty ("wire-deposit-failing",
NULL,
- 0,
MHD_HTTP_NOT_FOUND),
- TALER_TESTING_cmd_sleep ("sleep-before-aggregator",
- 1),
/* Run transfers. Note that _actual_ aggregation will NOT
* happen here, as each deposit operation is run with a
* fresh merchant public key, so the aggregator will treat
* them as "different" merchants and do the wire transfers
- * individually. *///
+ * individually. */
CMD_EXEC_AGGREGATOR ("run-aggregator"),
/**
* Check all the transfers took place.
*/
TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:4.98",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c2",
+ cred.exchange_url,
+ "EUR:4.97",
+ cred.exchange_payto,
+ cred.user42_payto),
TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c2",
- ec.exchange_url,
+ cred.exchange_url,
+ "EUR:0.98",
+ cred.exchange_payto,
+ cred.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c3",
+ cred.exchange_url,
"EUR:0.98",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c",
- ec.exchange_url,
+ cred.exchange_payto,
+ cred.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c4",
+ cred.exchange_url,
+ "EUR:0.98",
+ cred.exchange_payto,
+ cred.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-08c",
+ cred.exchange_url,
+ "EUR:0.08",
+ cred.exchange_payto,
+ cred.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-08c2",
+ cred.exchange_url,
"EUR:0.08",
- bc.exchange_payto,
- bc.user43_payto),
+ cred.exchange_payto,
+ cred.user43_payto),
+ /* In case of CS, one transaction above succeeded that
+ failed for RSA, hence we need to check for an extra transfer here */
+ uses_cs
+ ? TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-98c",
+ cred.exchange_url,
+ "EUR:0.98",
+ cred.exchange_payto,
+ cred.user42_payto)
+ : TALER_TESTING_cmd_sleep ("dummy",
+ 0),
TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
TALER_TESTING_cmd_track_transaction ("deposit-wtid-ok",
"deposit-simple",
@@ -396,20 +514,17 @@ run (void *cls,
"check_bank_transfer-499c"),
TALER_TESTING_cmd_track_transfer ("wire-deposit-success-bank",
"check_bank_transfer-99c1",
- 0,
MHD_HTTP_OK,
"EUR:0.98",
"EUR:0.01"),
TALER_TESTING_cmd_track_transfer ("wire-deposits-success-wtid",
"deposit-wtid-ok",
- 0,
MHD_HTTP_OK,
"EUR:4.98",
"EUR:0.01"),
TALER_TESTING_cmd_end ()
};
-
/**
* This block checks whether a wire deadline
* very far in the future does NOT get aggregated now.
@@ -422,18 +537,19 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_admin_transfer (
"check-create-reserve-unaggregated",
"EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"create-reserve-unaggregated"),
CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
"create-reserve-unaggregated",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit ("deposit-unaggregated",
"withdraw-coin-unaggregated",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_relative_multiply (
GNUNET_TIME_UNIT_YEARS,
@@ -442,12 +558,108 @@ run (void *cls,
MHD_HTTP_OK),
CMD_EXEC_AGGREGATOR ("aggregation-attempt"),
- TALER_TESTING_cmd_check_bank_empty
- ("far-future-aggregation-b"),
+ TALER_TESTING_cmd_check_bank_empty (
+ "far-future-aggregation-b"),
TALER_TESTING_cmd_end ()
};
+ struct TALER_TESTING_Command refresh_age[] = {
+ /* Fill reserve with EUR:5, 1ct is for fees. */
+ CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-age-1",
+ "EUR:6.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "ck-refresh-create-reserve-age-1",
+ "EUR:6.01",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "refresh-create-reserve-age-1"),
+ /**
+ * Make previous command effective.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-age-2"),
+ /**
+ * Withdraw EUR:7 with age restriction for age 13.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-age-1",
+ "refresh-create-reserve-age-1",
+ "EUR:5",
+ 13,
+ 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-age",
+ "refresh-withdraw-coin-age-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Melt the rest of the coin's value
+ * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
+ TALER_TESTING_cmd_melt_double ("refresh-melt-age-1",
+ "refresh-withdraw-coin-age-1",
+ MHD_HTTP_OK,
+ NULL),
+ /**
+ * Complete (successful) melt operation, and
+ * withdraw the coins
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1",
+ "refresh-melt-age-1",
+ MHD_HTTP_OK),
+ /**
+ * Do it again to check idempotency
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1-idempotency",
+ "refresh-melt-age-1",
+ MHD_HTTP_OK),
+ /**
+ * Test that /refresh/link works
+ */
+ TALER_TESTING_cmd_refresh_link ("refresh-link-age-1",
+ "refresh-reveal-age-1",
+ MHD_HTTP_OK),
+ /**
+ * Try to spend a refreshed EUR:1 coin
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1a",
+ "refresh-reveal-age-1-idempotency",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Try to spend a refreshed EUR:0.1 coin
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1b",
+ "refresh-reveal-age-1",
+ 3,
+ cred.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.1",
+ MHD_HTTP_OK),
+ /* Test running a failing melt operation (same operation
+ * again must fail) */
+ TALER_TESTING_cmd_melt ("refresh-melt-failing-age",
+ "refresh-withdraw-coin-age-1",
+ MHD_HTTP_CONFLICT,
+ NULL),
+ /* Test running a failing melt operation (on a coin that
+ was itself revealed and subsequently deposited) */
+ TALER_TESTING_cmd_melt ("refresh-melt-failing-age-2",
+ "refresh-reveal-age-1",
+ MHD_HTTP_CONFLICT,
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
/**
* This block exercises the aggretation logic by making two payments
@@ -460,18 +672,19 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_admin_transfer (
"check-create-reserve-aggtest",
"EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"create-reserve-aggtest"),
CMD_EXEC_WIREWATCH ("wirewatch-aggtest"),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-aggtest",
"create-reserve-aggtest",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit ("deposit-aggtest-1",
"withdraw-coin-aggtest",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:2",
@@ -479,7 +692,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit_with_ref ("deposit-aggtest-2",
"withdraw-coin-aggtest",
0,
- bc.user43_payto,
+ cred.user43_payto,
"{\"items\":[{\"name\":\"foo bar\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:2",
@@ -487,10 +700,10 @@ run (void *cls,
"deposit-aggtest-1"),
CMD_EXEC_AGGREGATOR ("aggregation-aggtest"),
TALER_TESTING_cmd_check_bank_transfer ("check-bank-transfer-aggtest",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:3.97",
- bc.exchange_payto,
- bc.user43_payto),
+ cred.exchange_payto,
+ cred.user43_payto),
TALER_TESTING_cmd_check_bank_empty ("check-bank-empty-aggtest"),
TALER_TESTING_cmd_end ()
};
@@ -504,8 +717,8 @@ run (void *cls,
"EUR:5.01"),
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-r1",
"EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"create-reserve-r1"),
/**
* Run wire-watch to trigger the reserve creation.
@@ -515,6 +728,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
"create-reserve-r1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/**
* Spend 5 EUR of the 5 EUR coin (in full) (merchant would
@@ -523,7 +737,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-refund-1",
"withdraw-coin-r1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_MINUTES,
"EUR:5",
@@ -536,7 +750,7 @@ run (void *cls,
* 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. *///
+ * other transfers around. */
TALER_TESTING_cmd_check_bank_empty ("check_bank_transfer-pre-refund"),
TALER_TESTING_cmd_refund_with_id ("refund-ok",
MHD_HTTP_OK,
@@ -557,7 +771,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-refund-insufficient-refund",
"withdraw-coin-r1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:4\"}]}",
GNUNET_TIME_UNIT_MINUTES,
"EUR:4",
@@ -574,7 +788,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-refund-2",
"withdraw-coin-r1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"more ice cream\",\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:4.99",
@@ -588,10 +802,10 @@ run (void *cls,
* Check that deposit did run.
*/
TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-pre-refund",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:4.97",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
/**
* Run failing refund, as past deadline & aggregation.
*/
@@ -608,18 +822,19 @@ run (void *cls,
"EUR:5.01"),
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-rb",
"EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"create-reserve-rb"),
CMD_EXEC_WIREWATCH ("wirewatch-rb"),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb",
"create-reserve-rb",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit ("deposit-refund-1b",
"withdraw-coin-rb",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:5",
@@ -636,7 +851,7 @@ run (void *cls,
* 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"),
@@ -653,8 +868,8 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_admin_transfer (
"recoup-create-reserve-1-check",
"EUR:15.02",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"recoup-create-reserve-1"),
/**
* Run wire-watch to trigger the reserve creation.
@@ -664,11 +879,13 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
"recoup-create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/* Withdraw a 10 EUR coin, at fee of 1 ct */
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1b",
"recoup-create-reserve-1",
"EUR:10",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/* melt 10 EUR coin to get 5 EUR refreshed coin */
TALER_TESTING_cmd_melt ("recoup-melt-coin-1b",
@@ -683,12 +900,11 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-0-EUR:5",
MHD_HTTP_OK,
"recoup-withdraw-coin-1",
- CONFIG_FILE),
+ config_file),
/* Recoup coin to reserve */
TALER_TESTING_cmd_recoup ("recoup-1",
MHD_HTTP_OK,
"recoup-withdraw-coin-1",
- NULL,
"EUR:5"),
/* Check the money is back with the reserve */
TALER_TESTING_cmd_status ("recoup-reserve-status-1",
@@ -696,11 +912,11 @@ run (void *cls,
"EUR:5.0",
MHD_HTTP_OK),
/* Recoup-refresh coin to 10 EUR coin */
- TALER_TESTING_cmd_recoup ("recoup-1b",
- MHD_HTTP_OK,
- "recoup-reveal-coin-1b",
- "recoup-melt-coin-1b",
- "EUR:5"),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1b",
+ MHD_HTTP_OK,
+ "recoup-reveal-coin-1b",
+ "recoup-melt-coin-1b",
+ "EUR:5"),
/* melt 10 EUR coin *again* to get 1 EUR refreshed coin */
TALER_TESTING_cmd_melt ("recoup-remelt-coin-1a",
"recoup-withdraw-coin-1b",
@@ -760,6 +976,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
"recoup-create-reserve-1",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/**
* This withdrawal will test the logic to create a "recoup"
@@ -768,6 +985,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2-over",
"recoup-create-reserve-1",
"EUR:10",
+ 0, /* age restriction off */
MHD_HTTP_CONFLICT),
TALER_TESTING_cmd_status ("recoup-reserve-status-2",
"recoup-create-reserve-1",
@@ -780,18 +998,19 @@ run (void *cls,
"EUR:5.01"),
TALER_TESTING_cmd_check_bank_admin_transfer ("check-short-lived-reserve",
"EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"short-lived-reserve"),
- TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
+ TALER_TESTING_cmd_exec_wirewatch2 ("short-lived-aggregation",
+ config_file_expire_reserve_now,
+ "exchange-account-2"),
TALER_TESTING_cmd_exec_closer ("close-reserves",
- CONFIG_FILE_EXPIRE_RESERVE_NOW,
+ config_file_expire_reserve_now,
"EUR:5",
"EUR:0.01",
"short-lived-reserve"),
TALER_TESTING_cmd_exec_transfer ("close-reserves-transfer",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
+ config_file_expire_reserve_now),
TALER_TESTING_cmd_status ("short-lived-status",
"short-lived-reserve",
@@ -800,23 +1019,24 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("expired-withdraw",
"short-lived-reserve",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_CONFLICT),
TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:5",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
/* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
* config, then withdraw two coin, partially spend one, and
* then have the rest paid back. Check deposit of other coin
* fails. Do not use EUR:5 here as the EUR:5 coin was
- * revoked and we did not bother to create a new one... *///
+ * revoked and we did not bother to create a new one... */
CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2",
"EUR:2.02"),
TALER_TESTING_cmd_check_bank_admin_transfer ("ck-recoup-create-reserve-2",
"EUR:2.02",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"recoup-create-reserve-2"),
/* Make previous command effective. */
CMD_EXEC_WIREWATCH ("wirewatch-5"),
@@ -824,16 +1044,18 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
"recoup-create-reserve-2",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/* Withdraw a 1 EUR coin, at fee of 1 ct */
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
"recoup-create-reserve-2",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
"recoup-withdraw-coin-2a",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:0.5",
@@ -841,28 +1063,27 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-1-EUR:1",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
- CONFIG_FILE),
- /* Check recoup is failing for the coin with the reused coin key */
+ config_file),
+ /* Check recoup is failing for the coin with the reused coin key
+ (fails either because of denomination conflict (RSA) or
+ double-spending (CS))*/
TALER_TESTING_cmd_recoup ("recoup-2x",
MHD_HTTP_CONFLICT,
"withdraw-coin-1x",
- NULL,
"EUR:1"),
TALER_TESTING_cmd_recoup ("recoup-2",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
- NULL,
"EUR:0.5"),
/* Idempotency of recoup (withdrawal variant) */
TALER_TESTING_cmd_recoup ("recoup-2b",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
- NULL,
- NULL),
+ "EUR:0.5"),
TALER_TESTING_cmd_deposit ("recoup-deposit-revoked",
"recoup-withdraw-coin-2b",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -874,7 +1095,7 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup",
"recoup-withdraw-coin-2a",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:0.5",
@@ -885,13 +1106,14 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_admin_transfer (
"check-recoup-create-reserve-3",
"EUR:1.01",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"recoup-create-reserve-3"),
CMD_EXEC_WIREWATCH ("wirewatch-6"),
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked",
"recoup-create-reserve-3",
"EUR:1",
+ 0, /* age restriction off */
MHD_HTTP_GONE),
/* check that we are empty before the rejection test */
TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
@@ -899,12 +1121,83 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
+ /**
+ * Test batch withdrawal plus spending.
+ */
+ struct TALER_TESTING_Command batch_withdraw[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-batch-reserve-1",
+ "EUR:6.03"),
+ TALER_TESTING_cmd_reserve_poll ("poll-batch-reserve-1",
+ "create-batch-reserve-1",
+ "EUR:6.03",
+ GNUNET_TIME_UNIT_MINUTES,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-batch-reserve-1",
+ "EUR:6.03",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-batch-reserve-1"),
+ /*
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-batch-1"),
+ TALER_TESTING_cmd_reserve_poll_finish ("finish-poll-batch-reserve-1",
+ GNUNET_TIME_UNIT_SECONDS,
+ "poll-batch-reserve-1"),
+ /**
+ * Withdraw EUR:5 AND EUR:1.
+ */
+ TALER_TESTING_cmd_batch_withdraw ("batch-withdraw-coin-1",
+ "create-batch-reserve-1",
+ 0, /* age restriction off */
+ MHD_HTTP_OK,
+ "EUR:5",
+ "EUR:1",
+ NULL),
+ /**
+ * Check the reserve is (almost) depleted.
+ */
+ TALER_TESTING_cmd_status ("status-batch-1",
+ "create-batch-reserve-1",
+ "EUR:0.01",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_reserve_history ("history-batch-1",
+ "create-batch-reserve-1",
+ "EUR:0.01",
+ MHD_HTTP_OK),
+ /**
+ * Spend the coins.
+ */
+ TALER_TESTING_cmd_batch_deposit ("batch-deposit-1",
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":5}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ MHD_HTTP_OK,
+ "batch-withdraw-coin-1#0",
+ "EUR:5",
+ "batch-withdraw-coin-1#1",
+ "EUR:1",
+ NULL),
+ TALER_TESTING_cmd_coin_history ("coin-history-batch-1",
+ "batch-withdraw-coin-1#0",
+ "EUR:0.0",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+
#define RESERVE_OPEN_CLOSE_CHUNK 4
#define RESERVE_OPEN_CLOSE_ITERATIONS 3
struct TALER_TESTING_Command reserve_open_close[(RESERVE_OPEN_CLOSE_ITERATIONS
* RESERVE_OPEN_CLOSE_CHUNK)
+ 1];
+
+ (void) cls;
for (unsigned int i = 0;
i < RESERVE_OPEN_CLOSE_ITERATIONS;
i++)
@@ -913,11 +1206,12 @@ run (void *cls,
= CMD_TRANSFER_TO_EXCHANGE ("reserve-open-close-key",
"EUR:20");
reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1]
- = TALER_TESTING_cmd_exec_wirewatch ("reserve-open-close-wirewatch",
- CONFIG_FILE_EXPIRE_RESERVE_NOW);
+ = TALER_TESTING_cmd_exec_wirewatch2 ("reserve-open-close-wirewatch",
+ config_file_expire_reserve_now,
+ "exchange-account-2");
reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2]
= TALER_TESTING_cmd_exec_closer ("reserve-open-close-aggregation",
- CONFIG_FILE_EXPIRE_RESERVE_NOW,
+ config_file_expire_reserve_now,
"EUR:19.99",
"EUR:0.01",
"reserve-open-close-key");
@@ -932,30 +1226,30 @@ run (void *cls,
{
struct TALER_TESTING_Command commands[] = {
- /* setup exchange */
- TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/2",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
- CONFIG_FILE),
- TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
- CONFIG_FILE,
- "EUR:0.01",
- "EUR:0.01"),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 1),
- TALER_TESTING_cmd_batch ("wire",
- wire),
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
TALER_TESTING_cmd_batch ("withdraw",
withdraw),
TALER_TESTING_cmd_batch ("spend",
spend),
TALER_TESTING_cmd_batch ("refresh",
refresh),
+ TALER_TESTING_cmd_batch ("withdraw-age",
+ withdraw_age),
+ TALER_TESTING_cmd_batch ("spend-age",
+ spend_age),
+ TALER_TESTING_cmd_batch ("refresh-age",
+ refresh_age),
TALER_TESTING_cmd_batch ("track",
track),
TALER_TESTING_cmd_batch ("unaggregation",
@@ -964,6 +1258,8 @@ run (void *cls,
aggregation),
TALER_TESTING_cmd_batch ("refund",
refund),
+ TALER_TESTING_cmd_batch ("batch-withdraw",
+ batch_withdraw),
TALER_TESTING_cmd_batch ("recoup",
recoup),
TALER_TESTING_cmd_batch ("reserve-open-close",
@@ -972,9 +1268,8 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
+ TALER_TESTING_run (is,
+ commands);
}
}
@@ -983,47 +1278,30 @@ int
main (int argc,
char *const *argv)
{
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-exchange-api",
- "INFO",
- NULL);
- /* Check fakebank port is available and get config */
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "exchange-account-2",
- &bc))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- GNUNET_YES,
- &ec))
+ (void) argc;
{
- 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;
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ uses_cs = (0 == strcmp (cipher,
+ "cs"));
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api-%s.conf",
+ cipher);
+ GNUNET_asprintf (&config_file_expire_reserve_now,
+ "test_exchange_api_expire_reserve_now-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
}
- return 0;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf
index a1b743658..c25f5091a 100644
--- a/src/testing/test_exchange_api.conf
+++ b/src/testing/test_exchange_api.conf
@@ -2,69 +2,80 @@
#
[PATHS]
-# Persistent data storage for the testcase
TALER_TEST_HOME = test_exchange_api_home/
-TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
-[taler-exchange-secmod-rsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
+[libeufin-bank]
+CURRENCY = EUR
+DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200
+DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000
+REGISTRATION_BONUS_ENABLED = yes
+REGISTRATION_BONUS = EUR:100
+SUGGESTED_WITHDRAWAL_EXCHANGE = http://localhost:8081/
+WIRE_TYPE = iban
+IBAN_PAYTO_BIC = SANDBOXX
+SERVE = tcp
+PORT = 8082
+
+[libeufin-bankdb-postgres]
+CONFIG = postgresql:///talercheck
-[taler-exchange-secmod-eddsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
-# Reduce from 12 weeks to ensure we have multiple
-DURATION = 14 days
[taler]
-# Currency supported by the exchange (can only be one)
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
[auditor]
BASE_URL = "http://localhost:8083/"
-
-# HTTP port the auditor listens to
PORT = 8083
+PUBLIC_KEY = 9QZ7CCC5QFMWE9FVF50MGYWV7JR92SFHY5KHT8A1A2VNHM37VCRG
+TINY_AMOUNT = EUR:0.01
-[exchange]
+[auditordb-postgres]
+CONFIG = "postgres:///talercheck"
-TERMS_ETAG = 0
-PRIVACY_ETAG = 0
+[bank]
+HTTP_PORT = 8082
-# HTTP port the exchange listens to
+[exchange]
+TERMS_ETAG = tos
+PRIVACY_ETAG = 0
+AML_THRESHOLD = EUR:1000000
PORT = 8081
-
-# Master public key used to sign the exchange's various keys
-MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-
-# How to access our database
+MASTER_PUBLIC_KEY = QD6H521CBJBW0Z7PRN0JTAGH5JCQ97RDZRPPV5TQZSE78NQRT3KG
DB = postgres
-
-# Base URL of the exchange. Must be set to a URL where the
-# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
+EXPIRE_SHARD_SIZE ="300 ms"
+EXPIRE_IDLE_SLEEP_INTERVAL ="1 s"
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"
-[auditordb-postgres]
-CONFIG = "postgres:///talercheck"
+[taler-exchange-secmod-cs]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-rsa]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-eddsa]
+LOOKAHEAD_SIGN = "24 days"
+DURATION = "14 days"
+
-# Sections starting with "exchange-account-" configure the bank accounts
-# of the exchange. The "URL" specifies the account in
-# payto://-format.
[exchange-account-1]
-# What is the URL of our account?
-PAYTO_URI = "payto://x-taler-bank/localhost/42"
-# ENABLE_CREDIT = YES
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
[exchange-accountcredentials-1]
-WIRE_GATEWAY_URL = "http://localhost:9081/42/"
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+[admin-accountcredentials-1]
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
[exchange-account-2]
-# What is the bank account (with the "Taler Bank" demo system)?
-PAYTO_URI = "payto://x-taler-bank/localhost/2"
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
@@ -72,64 +83,36 @@ ENABLE_CREDIT = YES
WIRE_GATEWAY_AUTH_METHOD = basic
USERNAME = Exchange
PASSWORD = x
-WIRE_GATEWAY_URL = "http://localhost:9081/2/"
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
-[bank]
-HTTP_PORT = 9081
-
-# Sections starting with "coin_" specify which denominations
-# the exchange should support (and their respective fee structure)
-[coin_eur_ct_1]
-value = EUR:0.01
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.00
-fee_deposit = EUR:0.00
-fee_refresh = EUR:0.01
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_ct_10]
-value = EUR:0.10
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_1]
-value = EUR:1
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_5]
-value = EUR:5
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_10]
-value = EUR:10
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
+[admin-accountcredentials-2]
+WIRE_GATEWAY_AUTH_METHOD = basic
+# For now, fakebank still checks against the Exchange account...
+USERNAME = Exchange
+PASSWORD = x
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+
+[kyc-provider-test-oauth2]
+COST = 0
+LOGIC = oauth2
+USER_TYPE = INDIVIDUAL
+PROVIDED_CHECKS = DUMMY
+KYC_OAUTH2_VALIDITY = forever
+KYC_OAUTH2_TOKEN_URL = http://localhost:6666/oauth/v2/token
+KYC_OAUTH2_AUTHORIZE_URL = http://localhost:6666/oauth/v2/login
+KYC_OAUTH2_INFO_URL = http://localhost:6666/api/user/me
+KYC_OAUTH2_CLIENT_ID = taler-exchange
+KYC_OAUTH2_CLIENT_SECRET = exchange-secret
+KYC_OAUTH2_POST_URL = http://example.com/
+KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh
+
+[kyc-legitimization-close]
+OPERATION_TYPE = CLOSE
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:0
+TIMEFRAME = 1d
+
+[exchange-extension-age_restriction]
+ENABLED = YES
+#AGE_GROUPS = "8:10:12:14:16:18:21"
diff --git a/src/testing/test_exchange_api_age_restriction-cs.conf b/src/testing/test_exchange_api_age_restriction-cs.conf
new file mode 100644
index 000000000..12195f9ba
--- /dev/null
+++ b/src/testing/test_exchange_api_age_restriction-cs.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_age_restriction.conf
+@INLINE@ coins-cs.conf
diff --git a/src/testing/test_exchange_api_age_restriction-rsa.conf b/src/testing/test_exchange_api_age_restriction-rsa.conf
new file mode 100644
index 000000000..30d75090f
--- /dev/null
+++ b/src/testing/test_exchange_api_age_restriction-rsa.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_age_restriction.conf
+@INLINE@ coins-rsa.conf
diff --git a/src/testing/test_exchange_api_age_restriction.c b/src/testing/test_exchange_api_age_restriction.c
new file mode 100644
index 000000000..5ba24a00c
--- /dev/null
+++ b/src/testing/test_exchange_api_age_restriction.c
@@ -0,0 +1,370 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/test_exchange_api_age_restriction.c
+ * @brief testcase to test exchange's age-restrictrition related HTTP API interfaces
+ * @author Özgür Kesim
+ */
+#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 <gnunet/gnunet_testing_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+#include "taler_extensions.h"
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+static char *config_file;
+
+/**
+ * Our credentials.
+ */
+static struct TALER_TESTING_Credentials cred;
+
+/**
+ * Some tests behave differently when using CS as we cannot
+ * reuse the coin private key for different denominations
+ * due to the derivation of it with the /csr values. Hence
+ * some tests behave differently in CS mode, hence this
+ * flag.
+ */
+static bool uses_cs;
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_WIREWATCH(label) \
+ TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, "exchange-account-2")
+
+/**
+ * Execute the taler-exchange-aggregator, closer and transfer commands with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_sleep ("sleep-before-aggregator", 2), \
+ TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
+ TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
+
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ */
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+ TALER_TESTING_cmd_admin_add_incoming (label, amount, \
+ &cred.ba, \
+ cred.user42_payto)
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ * @param is interpreter we use to run commands
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ (void) cls;
+ /**
+ * Test withdrawal with age restriction. Success is expected (because the
+ * amount is below the kyc threshold ), so it MUST be
+ * called _after_ TALER_TESTING_cmd_exec_offline_sign_extensions is called,
+ * i. e. age restriction is activated in the exchange!
+ *
+ * TODO: create a test that tries to withdraw coins with age restriction but
+ * (expectedly) fails because the exchange doesn't support age restriction
+ * yet.
+ */
+ struct TALER_TESTING_Command withdraw_age[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age",
+ "EUR:6.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age",
+ "EUR:6.01",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-age"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-age"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-age-1",
+ "create-reserve-age",
+ "EUR:5",
+ 13,
+ MHD_HTTP_OK),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend_age[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-simple-age",
+ "withdraw-coin-age-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:4.99",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age",
+ "deposit-simple-age",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+
+ struct TALER_TESTING_Command refresh_age[] = {
+ /* Fill reserve with EUR:5, 1ct is for fees. */
+ CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-age-1",
+ "EUR:6.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "ck-refresh-create-reserve-age-1",
+ "EUR:6.01",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "refresh-create-reserve-age-1"),
+ /**
+ * Make previous command effective.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-age-2"),
+ /**
+ * Withdraw EUR:7 with age restriction for age 13.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-age-1",
+ "refresh-create-reserve-age-1",
+ "EUR:5",
+ 13,
+ 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-age",
+ "refresh-withdraw-coin-age-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Melt the rest of the coin's value
+ * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
+ TALER_TESTING_cmd_melt_double ("refresh-melt-age-1",
+ "refresh-withdraw-coin-age-1",
+ MHD_HTTP_OK,
+ NULL),
+ /**
+ * Complete (successful) melt operation, and
+ * withdraw the coins
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1",
+ "refresh-melt-age-1",
+ MHD_HTTP_OK),
+ /**
+ * Do it again to check idempotency
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-age-1-idempotency",
+ "refresh-melt-age-1",
+ MHD_HTTP_OK),
+ /**
+ * Test that /refresh/link works
+ */
+ TALER_TESTING_cmd_refresh_link ("refresh-link-age-1",
+ "refresh-reveal-age-1",
+ MHD_HTTP_OK),
+ /**
+ * Try to spend a refreshed EUR:1 coin
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1a",
+ "refresh-reveal-age-1-idempotency",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Try to spend a refreshed EUR:0.1 coin
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-age-1b",
+ "refresh-reveal-age-1",
+ 3,
+ cred.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.1",
+ MHD_HTTP_OK),
+ /* Test running a failing melt operation (same operation
+ * again must fail) */
+ TALER_TESTING_cmd_melt ("refresh-melt-failing-age",
+ "refresh-withdraw-coin-age-1",
+ MHD_HTTP_CONFLICT,
+ NULL),
+ /* Test running a failing melt operation (on a coin that
+ was itself revealed and subsequently deposited) */
+ TALER_TESTING_cmd_melt ("refresh-melt-failing-age-2",
+ "refresh-reveal-age-1",
+ MHD_HTTP_CONFLICT,
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
+
+ /**
+ * Test with age-withdraw, after kyc process has set a birthdate
+ */
+ struct TALER_TESTING_Command age_withdraw[] = {
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-kyc-1",
+ "EUR:30.02"),
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "check-create-reserve-kyc-1",
+ "EUR:30.02",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-kyc-1"),
+ CMD_EXEC_WIREWATCH ("wirewatch-age-withdraw-1"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-lacking-kyc",
+ "create-reserve-kyc-1",
+ "EUR:10",
+ 0, /* age restriction off */
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-withdraw",
+ "withdraw-coin-1-lacking-kyc",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc",
+ "withdraw-coin-1-lacking-kyc",
+ "kyc-provider-test-oauth2",
+ "pass",
+ MHD_HTTP_SEE_OTHER),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-with-kyc",
+ "create-reserve-kyc-1",
+ "EUR:10",
+ 0, /* age restriction off */
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_age_withdraw ("age-withdraw-coin-1-too-low",
+ "create-reserve-kyc-1",
+ 18, /* Too high */
+ MHD_HTTP_CONFLICT,
+ "EUR:10",
+ NULL),
+ TALER_TESTING_cmd_age_withdraw ("age-withdraw-coins-1",
+ "create-reserve-kyc-1",
+ 8,
+ MHD_HTTP_OK,
+ "EUR:10",
+ "EUR:10",
+ "EUR:5",
+ NULL),
+ TALER_TESTING_cmd_age_withdraw_reveal ("age-withdraw-coins-reveal-1",
+ "age-withdraw-coins-1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end (),
+ };
+
+ {
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_oauth_with_birthdate ("oauth-service-with-birthdate",
+ "2015-00-00", /* enough for a while */
+ 6666),
+ TALER_TESTING_cmd_batch ("withdraw-age",
+ withdraw_age),
+ TALER_TESTING_cmd_batch ("spend-age",
+ spend_age),
+ TALER_TESTING_cmd_batch ("refresh-age",
+ refresh_age),
+ TALER_TESTING_cmd_batch ("age-withdraw",
+ age_withdraw),
+ /* End the suite. */
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run (is,
+ commands);
+ }
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ (void) argc;
+ {
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ uses_cs = (0 == strcmp (cipher,
+ "cs"));
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api_age_restriction-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
+ }
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
+}
+
+
+/* end of test_exchange_api_age_restriction.c */
diff --git a/src/testing/test_exchange_api_age_restriction.conf b/src/testing/test_exchange_api_age_restriction.conf
new file mode 100644
index 000000000..1345fcb1a
--- /dev/null
+++ b/src/testing/test_exchange_api_age_restriction.conf
@@ -0,0 +1,119 @@
+# This file is in the public domain.
+#
+
+[PATHS]
+TALER_TEST_HOME = test_exchange_api_home/
+
+[taler]
+CURRENCY = EUR
+CURRENCY_ROUND_UNIT = EUR:0.01
+
+[auditor]
+BASE_URL = "http://localhost:8083/"
+PORT = 8083
+PUBLIC_KEY = T0XJ9QZ59YDN7QG3RE40SB2HY7W0ASR1EKF4WZDGZ1G159RSQC80
+TINY_AMOUNT = EUR:0.01
+
+[auditordb-postgres]
+CONFIG = "postgres:///talercheck"
+
+[bank]
+HTTP_PORT = 8082
+
+[exchange]
+TERMS_ETAG = tos
+PRIVACY_ETAG = 0
+AML_THRESHOLD = EUR:10
+PORT = 8081
+MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
+DB = postgres
+BASE_URL = "http://localhost:8081/"
+EXPIRE_SHARD_SIZE ="300 ms"
+EXPIRE_IDLE_SLEEP_INTERVAL ="1 s"
+
+[exchangedb-postgres]
+CONFIG = "postgres:///talercheck"
+
+[taler-exchange-secmod-cs]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-rsa]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-eddsa]
+LOOKAHEAD_SIGN = "24 days"
+DURATION = "14 days"
+
+
+[exchange-account-1]
+PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+[exchange-accountcredentials-1]
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/42/taler-wire-gateway/"
+
+[admin-accountcredentials-1]
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/42/taler-wire-gateway/"
+
+[exchange-account-2]
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+[exchange-accountcredentials-2]
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+[admin-accountcredentials-2]
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+
+[kyc-provider-test-oauth2]
+COST = 0
+LOGIC = oauth2
+USER_TYPE = INDIVIDUAL
+PROVIDED_CHECKS = DUMMY
+KYC_OAUTH2_VALIDITY = forever
+KYC_OAUTH2_TOKEN_URL = http://localhost:6666/oauth/v2/token
+KYC_OAUTH2_AUTHORIZE_URL = http://localhost:6666/oauth/v2/login
+KYC_OAUTH2_INFO_URL = http://localhost:6666/api/user/me
+KYC_OAUTH2_CLIENT_ID = taler-exchange
+KYC_OAUTH2_CLIENT_SECRET = exchange-secret
+KYC_OAUTH2_POST_URL = http://example.com/
+KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh
+
+[kyc-legitimization-balance-high]
+OPERATION_TYPE = BALANCE
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:20
+
+[kyc-legitimization-deposit-any]
+OPERATION_TYPE = DEPOSIT
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:10
+TIMEFRAME = 1d
+
+[kyc-legitimization-withdraw]
+OPERATION_TYPE = WITHDRAW
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:15
+TIMEFRAME = 1d
+
+[kyc-legitimization-merge]
+OPERATION_TYPE = MERGE
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:15
+TIMEFRAME = 1d
+
+
+[exchange-extension-age_restriction]
+ENABLED = YES
+#AGE_GROUPS = "8:10:12:14:16:18:21"
diff --git a/src/testing/test_exchange_api_conflicts-cs.conf b/src/testing/test_exchange_api_conflicts-cs.conf
new file mode 100644
index 000000000..c15d55490
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts-cs.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_conflicts.conf
+@INLINE@ coins-cs.conf
diff --git a/src/testing/test_exchange_api_conflicts-rsa.conf b/src/testing/test_exchange_api_conflicts-rsa.conf
new file mode 100644
index 000000000..f56111eee
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts-rsa.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_conflicts.conf
+@INLINE@ coins-rsa.conf
diff --git a/src/testing/test_exchange_api_conflicts.c b/src/testing/test_exchange_api_conflicts.c
new file mode 100644
index 000000000..070809d9d
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts.c
@@ -0,0 +1,312 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/test_exchange_api_conflicts.c
+ * @brief testcase to test exchange's handling of coin conflicts: same private
+ * keys but different denominations or age restrictions
+ * @author Özgür Kesim
+ */
+#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 <gnunet/gnunet_testing_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+#include "taler_extensions.h"
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+static char *config_file;
+
+/**
+ * Our credentials.
+ */
+static struct TALER_TESTING_Credentials cred;
+
+/**
+ * Some tests behave differently when using CS as we cannot
+ * reuse the coin private key for different denominations
+ * due to the derivation of it with the /csr values. Hence
+ * some tests behave differently in CS mode, hence this
+ * flag.
+ */
+static bool uses_cs;
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_WIREWATCH(label) \
+ TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, \
+ "exchange-account-2")
+
+/**
+ * Execute the taler-exchange-aggregator, closer and transfer commands with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_sleep ("sleep-before-aggregator", 2), \
+ TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
+ TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
+
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ */
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+ TALER_TESTING_cmd_admin_add_incoming (label, amount, \
+ &cred.ba, \
+ cred.user42_payto)
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ * @param is interpreter we use to run commands
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ (void) cls;
+ /**
+ * Test withdrawal with conflicting coins.
+ */
+ struct TALER_TESTING_Command withdraw_conflict_denom[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-denom",
+ "EUR:21.14"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-denom",
+ "EUR:21.14",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-denom"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-conflict-denom"),
+ /**
+ * Withdraw EUR:0.10, EUR:1, EUR:5, EUR:15, but using the same private key each time.
+ */
+ TALER_TESTING_cmd_batch_withdraw_with_conflict ("withdraw-coin-denom-1",
+ "create-reserve-denom",
+ true,
+ 0, /* age */
+ MHD_HTTP_OK,
+ "EUR:1",
+ "EUR:5",
+ "EUR:10",
+ "EUR:0.10",
+ NULL),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend_conflict_denom[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-denom",
+ "withdraw-coin-denom-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("deposit-denom-conflict",
+ "withdraw-coin-denom-1",
+ 1,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:4.99",
+ /* Note: For CS, even though the master secret is the
+ * same for each coin, their private keys differ due
+ * to the random choice of the nonce by the exchange. */
+ uses_cs ? MHD_HTTP_OK : MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_deposit ("deposit-denom-conflict-2",
+ "withdraw-coin-denom-1",
+ 2,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:9.99",
+ /* Note: For CS, even though the master secret is the
+ * same for each coin, their private keys differ due
+ * to the random choice of the nonce by the exchange. */
+ uses_cs ? MHD_HTTP_OK : MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_deposit ("deposit-denom-conflict-3",
+ "withdraw-coin-denom-1",
+ 3,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.09",
+ /* Note: For CS, even though the master secret is the
+ * same for each coin, their private keys differ due
+ * to the random choice of the nonce by the exchange. */
+ uses_cs ? MHD_HTTP_OK : MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command withdraw_conflict_age[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age",
+ "EUR:3.03"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age",
+ "EUR:3.03",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-age"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-conflict-age"),
+ /**
+ * Withdraw EUR:1, EUR:5, EUR:15, but using the same private key each time.
+ */
+ TALER_TESTING_cmd_batch_withdraw_with_conflict ("withdraw-coin-age-1",
+ "create-reserve-age",
+ true,
+ 10, /* age */
+ MHD_HTTP_OK,
+ "EUR:1",
+ "EUR:1",
+ "EUR:1",
+ NULL),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend_conflict_age[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-age",
+ "withdraw-coin-age-1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("deposit-age-conflict",
+ "withdraw-coin-age-1",
+ 1,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_deposit ("deposit-age-conflict-2",
+ "withdraw-coin-age-1",
+ 2,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.99",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_end ()
+ };
+
+
+ {
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_batch ("withdraw-conflict-denom",
+ withdraw_conflict_denom),
+ TALER_TESTING_cmd_batch ("spend-conflict-denom",
+ spend_conflict_denom),
+ TALER_TESTING_cmd_batch ("withdraw-conflict-age",
+ withdraw_conflict_age),
+ TALER_TESTING_cmd_batch ("spend-conflict-age",
+ spend_conflict_age),
+ /* End the suite. */
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run (is,
+ commands);
+ }
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ (void) argc;
+ {
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ uses_cs = (0 == strcmp (cipher,
+ "cs"));
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api_conflicts-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
+ }
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
+}
+
+
+/* end of test_exchange_api_conflicts.c */
diff --git a/src/testing/test_exchange_api_conflicts.conf b/src/testing/test_exchange_api_conflicts.conf
new file mode 100644
index 000000000..d04379f05
--- /dev/null
+++ b/src/testing/test_exchange_api_conflicts.conf
@@ -0,0 +1,81 @@
+# This file is in the public domain.
+#
+
+[PATHS]
+TALER_TEST_HOME = test_exchange_api_home/
+
+[taler]
+CURRENCY = EUR
+CURRENCY_ROUND_UNIT = EUR:0.01
+
+[auditor]
+BASE_URL = "http://localhost:8083/"
+PORT = 8083
+PUBLIC_KEY = T0XJ9QZ59YDN7QG3RE40SB2HY7W0ASR1EKF4WZDGZ1G159RSQC80
+TINY_AMOUNT = EUR:0.01
+
+[auditordb-postgres]
+CONFIG = "postgres:///talercheck"
+
+[bank]
+HTTP_PORT = 8082
+
+[exchange]
+TERMS_ETAG = tos
+PRIVACY_ETAG = 0
+PORT = 8081
+AML_THRESHOLD = "EUR:99999999"
+MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
+DB = postgres
+BASE_URL = "http://localhost:8081/"
+EXPIRE_SHARD_SIZE ="300 ms"
+EXPIRE_IDLE_SLEEP_INTERVAL ="1 s"
+
+[exchangedb-postgres]
+CONFIG = "postgres:///talercheck"
+
+[taler-exchange-secmod-cs]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-rsa]
+LOOKAHEAD_SIGN = "24 days"
+
+[taler-exchange-secmod-eddsa]
+LOOKAHEAD_SIGN = "24 days"
+DURATION = "14 days"
+
+
+[exchange-account-1]
+PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+[exchange-accountcredentials-1]
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/42/taler-wire-gateway/"
+
+[admin-accountcredentials-1]
+WIRE_GATEWAY_AUTH_METHOD = none
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/42/taler-wire-gateway/"
+
+[exchange-account-2]
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+[exchange-accountcredentials-2]
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+[admin-accountcredentials-2]
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
+WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/"
+
+
+[exchange-extension-age_restriction]
+ENABLED = YES
+#AGE_GROUPS = "8:10:12:14:16:18:21"
diff --git a/src/testing/test_exchange_api_expire_reserve_now-cs.conf b/src/testing/test_exchange_api_expire_reserve_now-cs.conf
new file mode 100644
index 000000000..2cc4e0917
--- /dev/null
+++ b/src/testing/test_exchange_api_expire_reserve_now-cs.conf
@@ -0,0 +1,4 @@
+@INLINE@ test_exchange_api-cs.conf
+
+[exchangedb]
+IDLE_RESERVE_EXPIRATION_TIME = 0 s
diff --git a/src/testing/test_exchange_api_expire_reserve_now-rsa.conf b/src/testing/test_exchange_api_expire_reserve_now-rsa.conf
new file mode 100644
index 000000000..52b829871
--- /dev/null
+++ b/src/testing/test_exchange_api_expire_reserve_now-rsa.conf
@@ -0,0 +1,4 @@
+@INLINE@ test_exchange_api-rsa.conf
+
+[exchangedb]
+IDLE_RESERVE_EXPIRATION_TIME = 0 s
diff --git a/src/testing/test_exchange_api_home/.config/taler/account-2.json b/src/testing/test_exchange_api_home/.config/taler/account-2.json
deleted file mode 100644
index 21a7500b4..000000000
--- a/src/testing/test_exchange_api_home/.config/taler/account-2.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "payto_uri": "payto://x-taler-bank/localhost/2",
- "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R"
-} \ No newline at end of file
diff --git a/src/testing/test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv b/src/testing/test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv
new file mode 100644
index 000000000..5b1c8fa05
--- /dev/null
+++ b/src/testing/test_exchange_api_home/.local/share/taler/auditor/offline-keys/auditor.priv
Binary files differ
diff --git a/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv b/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv
index 394926938..391b6ea73 100644
--- a/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv
+++ b/src/testing/test_exchange_api_home/.local/share/taler/exchange-offline/master.priv
Binary files differ
diff --git a/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv
deleted file mode 100644
index 394926938..000000000
--- a/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv
+++ /dev/null
@@ -1 +0,0 @@
-pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ \ No newline at end of file
diff --git a/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv
new file mode 100644
index 000000000..7e712e483
--- /dev/null
+++ b/src/testing/test_exchange_api_home/taler/auditor/offline-keys/auditor.priv
@@ -0,0 +1 @@
+·G,U²†{ ~#ræ-½Hê ‘¶ÒÆÏâÿñ \ No newline at end of file
diff --git a/src/testing/test_exchange_api_keys_cherry_picking-cs.conf b/src/testing/test_exchange_api_keys_cherry_picking-cs.conf
new file mode 100644
index 000000000..d25ef3c00
--- /dev/null
+++ b/src/testing/test_exchange_api_keys_cherry_picking-cs.conf
@@ -0,0 +1,18 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_keys_cherry_picking.conf
+
+[taler-exchange-secmod-cs]
+OVERLAP_DURATION = 1 s
+LOOKAHEAD_SIGN = 20 s
+
+[coin_eur_1]
+value = EUR:1
+duration_withdraw = 5 s
+duration_spend = 6 s
+duration_legal = 7 s
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = CS
diff --git a/src/testing/test_exchange_api_keys_cherry_picking-rsa.conf b/src/testing/test_exchange_api_keys_cherry_picking-rsa.conf
new file mode 100644
index 000000000..672639b3f
--- /dev/null
+++ b/src/testing/test_exchange_api_keys_cherry_picking-rsa.conf
@@ -0,0 +1,19 @@
+# This file is in the public domain.
+#
+@INLINE@ test_exchange_api_keys_cherry_picking.conf
+
+[taler-exchange-secmod-rsa]
+OVERLAP_DURATION = 1 s
+LOOKAHEAD_SIGN = 20 s
+
+[coin_eur_1]
+value = EUR:1
+duration_withdraw = 5 s
+duration_spend = 6 s
+duration_legal = 7 s
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+CIPHER = RSA
+rsa_keysize = 1024
diff --git a/src/testing/test_exchange_api_keys_cherry_picking.c b/src/testing/test_exchange_api_keys_cherry_picking.c
index e79bc2c55..2919ea8d5 100644
--- a/src/testing/test_exchange_api_keys_cherry_picking.c
+++ b/src/testing/test_exchange_api_keys_cherry_picking.c
@@ -29,6 +29,7 @@ lished
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@@ -39,12 +40,12 @@ lished
* 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"
+static char *config_file;
/**
- * Exchange configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
+static struct TALER_TESTING_Credentials cred;
/**
@@ -58,47 +59,31 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/2",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
- CONFIG_FILE,
- "EUR:0.01",
- "EUR:0.01"),
- TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
- CONFIG_FILE),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("initial-/keys",
- 1),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
TALER_TESTING_cmd_sleep ("sleep",
6 /* seconds */),
- TALER_TESTING_cmd_check_keys ("check-keys-1",
- 2 /* generation */),
- TALER_TESTING_cmd_check_keys_with_last_denom ("check-keys-2",
- 3 /* generation */,
- "check-keys-1"),
- TALER_TESTING_cmd_serialize_keys ("serialize-keys"),
- TALER_TESTING_cmd_connect_with_state ("reconnect-with-state",
- "serialize-keys"),
- /**
- * Make sure we have the same keys situation as
- * it was before the serialization.
- */
- TALER_TESTING_cmd_check_keys ("check-keys-after-deserialization",
- 4),
- /**
- * Use one of the deserialized keys.
- */
- TALER_TESTING_cmd_wire ("wire-with-serialized-keys",
- "x-taler-bank",
- NULL,
- MHD_HTTP_OK),
+ TALER_TESTING_cmd_get_exchange ("get-exchange-1",
+ cred.cfg,
+ "get-exchange",
+ true,
+ true),
+ TALER_TESTING_cmd_get_exchange ("get-exchange-2",
+ cred.cfg,
+ "get-exchange-1",
+ true,
+ true),
TALER_TESTING_cmd_end ()
};
+ (void) cls;
TALER_TESTING_run (is,
commands);
}
@@ -108,41 +93,25 @@ int
main (int argc,
char *const *argv)
{
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-exchange-api-cherry-picking",
- "DEBUG",
- NULL);
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- GNUNET_YES,
- &ec))
+ (void) argc;
{
- 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;
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api_keys_cherry_picking-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
}
- return 0;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_exchange_api_keys_cherry_picking.conf b/src/testing/test_exchange_api_keys_cherry_picking.conf
index d7dd95352..142242424 100644
--- a/src/testing/test_exchange_api_keys_cherry_picking.conf
+++ b/src/testing/test_exchange_api_keys_cherry_picking.conf
@@ -3,52 +3,23 @@
[PATHS]
# Persistent data storage for the testcase
TALER_TEST_HOME = test_exchange_api_keys_cherry_picking_home/
-TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
-
-# Persistent data storage
-TALER_DATA_HOME = $TALER_HOME/.local/share/taler/
-
-# Configuration files
-TALER_CONFIG_HOME = $TALER_HOME/.config/taler/
-
-# Cached data, no big deal if lost
-TALER_CACHE_HOME = $TALER_HOME/.cache/taler/
[taler]
-# Currency supported by the exchange (can only be one)
CURRENCY = EUR
-
-[taler-exchange-secmod-rsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
+CURRENCY_ROUND_UNIT = EUR:0.01
[taler-exchange-secmod-eddsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
-# Reduce from 12 weeks to ensure we have multiple
-DURATION = 14 days
-
-[auditor]
-BASE_URL = "http://localhost:8083/"
-
-# HTTP port the auditor listens to
-PORT = 8083
+OVERLAP_DURATION = 1 s
+DURATION = 30 s
+LOOKAHEAD_SIGN = 20 s
[exchange]
-# HTTP port the exchange listens to
+AML_THRESHOLD = EUR:1000000
PORT = 8081
-
-# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-
-# How to access our database
DB = postgres
-
-# Base URL of the exchange. Must be set to a URL where the
-# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
-
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"
@@ -56,43 +27,32 @@ CONFIG = "postgres:///talercheck"
CONFIG = "postgres:///talercheck"
[exchange-account-1]
-PAYTO_URI = payto://x-taler-bank/localhost/42
+PAYTO_URI = "payto://x-taler-bank/localhost/42?receiver-name=42"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
[exchange-accountcredentials-1]
-WIRE_GATEWAY_URL = "http://localhost:9082/42/"
+WIRE_GATEWAY_URL = "http://localhost:9082/accounts/42/taler-wire-gateway/"
+
+[admin-accountcredentials-1]
+WIRE_GATEWAY_URL = "http://localhost:9082/accounts/42/taler-wire-gateway/"
[exchange-account-2]
-PAYTO_URI = payto://x-taler-bank/localhost/2
+PAYTO_URI = "payto://x-taler-bank/localhost/2?receiver-name=2"
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
[exchange-accountcredentials-2]
-WIRE_GATEWAY_URL = "http://localhost:9082/2/"
+WIRE_GATEWAY_URL = "http://localhost:9082/accounts/2/taler-wire-gateway/"
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
-# Authentication information for basic authentication
-TALER_BANK_AUTH_METHOD = "basic"
-USERNAME = user
-PASSWORD = pass
+[admin-accountcredentials-2]
+WIRE_GATEWAY_URL = "http://localhost:9082/accounts/2/taler-wire-gateway/"
+WIRE_GATEWAY_AUTH_METHOD = basic
+USERNAME = Exchange
+PASSWORD = x
[bank]
HTTP_PORT=8082
-
-[taler-exchange-secmod-rsa]
-OVERLAP_DURATION = 1 s
-LOOKAHEAD_SIGN = 20 s
-
-[taler-exchange-secmod-eddsa]
-OVERLAP_DURATION = 1 s
-DURATION = 30 s
-LOOKAHEAD_SIGN = 20 s
-
-[coin_eur_1]
-value = EUR:1
-duration_withdraw = 5 s
-duration_spend = 6 s
-duration_legal = 7 s
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
diff --git a/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json b/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json
deleted file mode 100644
index 21a7500b4..000000000
--- a/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "payto_uri": "payto://x-taler-bank/localhost/2",
- "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R"
-} \ No newline at end of file
diff --git a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv b/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv
deleted file mode 100644
index 394926938..000000000
--- a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv
+++ /dev/null
@@ -1 +0,0 @@
-pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ \ No newline at end of file
diff --git a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv
deleted file mode 100644
index 394926938..000000000
--- a/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv
+++ /dev/null
@@ -1 +0,0 @@
-pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ \ No newline at end of file
diff --git a/src/testing/test_exchange_api_overlapping_keys_bug.c b/src/testing/test_exchange_api_overlapping_keys_bug.c
index 74039cce4..33b547a37 100644
--- a/src/testing/test_exchange_api_overlapping_keys_bug.c
+++ b/src/testing/test_exchange_api_overlapping_keys_bug.c
@@ -31,6 +31,7 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@@ -40,12 +41,12 @@
* 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"
+static char *config_file;
/**
- * Exchange configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
+static struct TALER_TESTING_Credentials cred;
/**
@@ -59,26 +60,32 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/2",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
- CONFIG_FILE),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 1),
- TALER_TESTING_cmd_check_keys ("first-download",
- 1),
- /* Causes GET /keys?last_denom_issue=0 */
- TALER_TESTING_cmd_check_keys_with_last_denom ("second-download",
- 1,
- "zero"),
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_get_exchange ("get-exchange-1",
+ cred.cfg,
+ "get-exchange",
+ true,
+ true),
+ TALER_TESTING_cmd_get_exchange ("get-exchange-2",
+ cred.cfg,
+ NULL,
+ true,
+ true),
TALER_TESTING_cmd_end ()
};
+ (void) cls;
TALER_TESTING_run (is,
commands);
}
@@ -88,40 +95,25 @@ int
main (int argc,
char *const *argv)
{
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-exchange-api-overlapping-keys-bug",
- "DEBUG", NULL);
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- GNUNET_YES,
- &ec))
+ (void) argc;
{
- 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;
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api_keys_cherry_picking-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
}
- return 0;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c
index 62be6a0e3..92e36a30a 100644
--- a/src/testing/test_exchange_api_revocation.c
+++ b/src/testing/test_exchange_api_revocation.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014--2020 Taler Systems SA
+ Copyright (C) 2014--2023 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
@@ -29,6 +29,7 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@@ -38,17 +39,12 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
-#define CONFIG_FILE "test_exchange_api.conf"
+static char *config_file;
/**
- * Exchange configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
+static struct TALER_TESTING_Credentials cred;
/**
@@ -62,51 +58,55 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command revocation[] = {
- TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/2",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
- CONFIG_FILE),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 1),
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
/**
* Fill reserve with EUR:10.02, as withdraw fee is 1 ct per
* config.
*/
TALER_TESTING_cmd_admin_add_incoming ("create-reserve-1",
"EUR:10.02",
- &bc.exchange_auth,
- bc.user42_payto),
+ &cred.ba,
+ cred.user42_payto),
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
"EUR:10.02",
- bc.user42_payto,
- bc.exchange_payto,
+ cred.user42_payto,
+ cred.exchange_payto,
"create-reserve-1"),
/**
* Run wire-watch to trigger the reserve creation.
*/
- TALER_TESTING_cmd_exec_wirewatch ("wirewatch-4",
- CONFIG_FILE),
+ TALER_TESTING_cmd_exec_wirewatch2 ("wirewatch-4",
+ config_file,
+ "exchange-account-2"),
/* Withdraw a 5 EUR coin, at fee of 1 ct */
TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1",
"create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/* Withdraw another 5 EUR coin, at fee of 1 ct */
TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-2",
"create-reserve-1",
"EUR:5",
+ 0, /* age restriction off */
MHD_HTTP_OK),
/* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
* (merchant would receive EUR:0.99 due to 1 ct deposit fee) *///
TALER_TESTING_cmd_deposit ("deposit-partial",
"withdraw-revocation-coin-1",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
@@ -115,14 +115,15 @@ run (void *cls,
TALER_TESTING_cmd_deposit ("deposit-full",
"withdraw-revocation-coin-2",
0,
- bc.user42_payto,
+ cred.user42_payto,
"{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:5",
MHD_HTTP_OK),
/**
* Melt SOME of the rest of the coin's value
- * (EUR:3.17 = 3x EUR:1.03 + 7x EUR:0.13) */
+ * (EUR:3.17 = 3x EUR:1.03 + 7x EUR:0.13)
+ */
TALER_TESTING_cmd_melt ("refresh-melt-1",
"withdraw-revocation-coin-1",
MHD_HTTP_OK,
@@ -134,64 +135,63 @@ run (void *cls,
"refresh-melt-1",
MHD_HTTP_OK),
/* Try to recoup before it's allowed */
- TALER_TESTING_cmd_recoup ("recoup-not-allowed",
- MHD_HTTP_GONE,
- "refresh-reveal-1#0",
- "refresh-melt-1",
- NULL),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-not-allowed",
+ MHD_HTTP_GONE,
+ "refresh-reveal-1#0",
+ "refresh-melt-1",
+ "EUR:0.1"),
/* Make refreshed coin invalid */
TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",
MHD_HTTP_OK,
"refresh-melt-1",
- CONFIG_FILE),
+ config_file),
/* Also make fully spent coin invalid (should be same denom) */
TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",
MHD_HTTP_OK,
"withdraw-revocation-coin-2",
- CONFIG_FILE),
+ config_file),
/* Refund fully spent coin (which should fail) */
TALER_TESTING_cmd_recoup ("recoup-fully-spent",
MHD_HTTP_CONFLICT,
"withdraw-revocation-coin-2",
- NULL,
- NULL),
+ "EUR:0.1"),
/* Refund coin to original coin */
- TALER_TESTING_cmd_recoup ("recoup-1a",
- MHD_HTTP_OK,
- "refresh-reveal-1#0",
- "refresh-melt-1",
- NULL),
- TALER_TESTING_cmd_recoup ("recoup-1b",
- MHD_HTTP_OK,
- "refresh-reveal-1#1",
- "refresh-melt-1",
- NULL),
- TALER_TESTING_cmd_recoup ("recoup-1c",
- MHD_HTTP_OK,
- "refresh-reveal-1#2",
- "refresh-melt-1",
- NULL),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1a",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#0",
+ "refresh-melt-1",
+ "EUR:1"),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1b",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#1",
+ "refresh-melt-1",
+ "EUR:1"),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1c",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#2",
+ "refresh-melt-1",
+ "EUR:1"),
/* Repeat recoup to test idempotency */
- TALER_TESTING_cmd_recoup ("recoup-1c",
- MHD_HTTP_OK,
- "refresh-reveal-1#2",
- "refresh-melt-1",
- NULL),
- TALER_TESTING_cmd_recoup ("recoup-1c",
- MHD_HTTP_OK,
- "refresh-reveal-1#2",
- "refresh-melt-1",
- NULL),
- TALER_TESTING_cmd_recoup ("recoup-1c",
- MHD_HTTP_OK,
- "refresh-reveal-1#2",
- "refresh-melt-1",
- NULL),
- TALER_TESTING_cmd_recoup ("recoup-1c",
- MHD_HTTP_OK,
- "refresh-reveal-1#2",
- "refresh-melt-1",
- NULL),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1c",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#2",
+ "refresh-melt-1",
+ "EUR:1"),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1c",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#2",
+ "refresh-melt-1",
+ "EUR:1"),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1c",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#2",
+ "refresh-melt-1",
+ "EUR:1"),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-1c",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#2",
+ "refresh-melt-1",
+ "EUR:1"),
/* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */
/* Melt original coin AGAIN, but only create one 0.1 EUR coin;
This costs EUR:0.03 in refresh and EUR:01 in withdraw fees,
@@ -211,24 +211,23 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-3-EUR:0.1",
MHD_HTTP_OK,
"refresh-reveal-2",
- CONFIG_FILE),
+ config_file),
/* Revoke also original coin denomination */
TALER_TESTING_cmd_revoke ("revoke-4-EUR:5",
MHD_HTTP_OK,
"withdraw-revocation-coin-1",
- CONFIG_FILE),
+ config_file),
/* Refund coin EUR:0.1 to original coin, creating zombie! */
- TALER_TESTING_cmd_recoup ("recoup-2",
- MHD_HTTP_OK,
- "refresh-reveal-2",
- "refresh-melt-2",
- NULL),
+ TALER_TESTING_cmd_recoup_refresh ("recoup-2",
+ MHD_HTTP_OK,
+ "refresh-reveal-2",
+ "refresh-melt-2",
+ "EUR:0.1"),
/* Due to recoup, original coin is now at EUR:3.79 */
/* Refund original (now zombie) coin to reserve */
TALER_TESTING_cmd_recoup ("recoup-3",
MHD_HTTP_OK,
"withdraw-revocation-coin-1",
- NULL,
"EUR:3.79"),
/* Check the money is back with the reserve */
TALER_TESTING_cmd_status ("recoup-reserve-status-1",
@@ -238,9 +237,9 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
- TALER_TESTING_run_with_fakebank (is,
- revocation,
- bc.exchange_auth.wire_gateway_url);
+ (void) cls;
+ TALER_TESTING_run (is,
+ revocation);
}
@@ -248,47 +247,25 @@ int
main (int argc,
char *const *argv)
{
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-exchange-api-revocation",
- "INFO",
- NULL);
- /* Check fakebank port is available and get config */
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "exchange-account-2",
- &bc))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- GNUNET_YES,
- &ec))
+ (void) argc;
{
- 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;
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
}
- return 0;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_exchange_api_twisted-cs.conf b/src/testing/test_exchange_api_twisted-cs.conf
new file mode 100644
index 000000000..ae953e732
--- /dev/null
+++ b/src/testing/test_exchange_api_twisted-cs.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+@INLINE@ test_exchange_api-cs.conf
+@INLINE@ test_exchange_api-twisted.conf
+
diff --git a/src/testing/test_exchange_api_twisted-rsa.conf b/src/testing/test_exchange_api_twisted-rsa.conf
new file mode 100644
index 000000000..3fd8f4ff1
--- /dev/null
+++ b/src/testing/test_exchange_api_twisted-rsa.conf
@@ -0,0 +1,4 @@
+# This file is in the public domain.
+@INLINE@ test_exchange_api-rsa.conf
+@INLINE@ test_exchange_api-twisted.conf
+
diff --git a/src/testing/test_exchange_api_twisted.c b/src/testing/test_exchange_api_twisted.c
index 818b54deb..75ffe1f15 100644
--- a/src/testing/test_exchange_api_twisted.c
+++ b/src/testing/test_exchange_api_twisted.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -29,6 +29,7 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@@ -40,22 +41,17 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
-#define CONFIG_FILE "test_exchange_api_twisted.conf"
+static char *config_file;
/**
- * (real) Twister URL. Used at startup time to check if it runs.
- */
-static char *twister_url;
-
-/**
- * Exchange configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
+static struct TALER_TESTING_Credentials cred;
/**
- * Bank configuration data.
+ * (real) Twister URL. Used at startup time to check if it runs.
*/
-static struct TALER_TESTING_BankConfiguration bc;
+static char *twister_url;
/**
* Twister process.
@@ -72,8 +68,9 @@ static struct GNUNET_OS_Process *twisterd;
static struct TALER_TESTING_Command
CMD_EXEC_WIREWATCH (const char *label)
{
- return TALER_TESTING_cmd_exec_wirewatch (label,
- CONFIG_FILE);
+ return TALER_TESTING_cmd_exec_wirewatch2 (label,
+ config_file,
+ "exchange-account-2");
}
@@ -91,8 +88,8 @@ CMD_TRANSFER_TO_EXCHANGE (const char *label,
{
return TALER_TESTING_cmd_admin_add_incoming (label,
amount,
- &bc.exchange_auth,
- bc.user42_payto);
+ &cred.ba,
+ cred.user42_payto);
}
@@ -111,8 +108,9 @@ run (void *cls,
* response from a refresh-reveal operation.
*/
struct TALER_TESTING_Command refresh_409_conflict[] = {
- CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve",
- "EUR:5.01"),
+ CMD_TRANSFER_TO_EXCHANGE (
+ "refresh-create-reserve",
+ "EUR:5.01"),
/**
* Make previous command effective.
*/
@@ -120,33 +118,38 @@ run (void *cls,
/**
* Withdraw EUR:5.
*/
- TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin",
- "refresh-create-reserve",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit ("refresh-deposit-partial",
- "refresh-withdraw-coin",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\
- \"value\":\"EUR:1\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount (
+ "refresh-withdraw-coin",
+ "refresh-create-reserve",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit (
+ "refresh-deposit-partial",
+ "refresh-withdraw-coin",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
/**
* Melt the rest of the coin's value
* (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
- TALER_TESTING_cmd_melt ("refresh-melt",
- "refresh-withdraw-coin",
- MHD_HTTP_OK,
- NULL),
+ TALER_TESTING_cmd_melt (
+ "refresh-melt",
+ "refresh-withdraw-coin",
+ MHD_HTTP_OK,
+ NULL),
/* Trigger 409 Conflict. */
- TALER_TESTING_cmd_flip_upload ("flip-upload",
- CONFIG_FILE,
- "transfer_privs.0"),
- TALER_TESTING_cmd_refresh_reveal ("refresh-(flipped-)reveal",
- "refresh-melt",
- MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_flip_upload (
+ "flip-upload",
+ config_file,
+ "transfer_privs.0"),
+ TALER_TESTING_cmd_refresh_reveal (
+ "refresh-(flipped-)reveal",
+ "refresh-melt",
+ MHD_HTTP_CONFLICT),
TALER_TESTING_cmd_end ()
};
@@ -155,50 +158,53 @@ run (void *cls,
* NOTE: not all CMDs actually need the twister,
* so it may be better to move those into the "main"
* lib test suite.
- */struct TALER_TESTING_Command refund[] = {
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1",
- "EUR:5.01"),
+ */
+ struct TALER_TESTING_Command refund[] = {
+ CMD_TRANSFER_TO_EXCHANGE (
+ "create-reserve-r1",
+ "EUR:5.01"),
CMD_EXEC_WIREWATCH ("wirewatch-r1"),
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
- "create-reserve-r1",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit ("deposit-refund-1",
- "withdraw-coin-r1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\","
- "\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_MINUTES,
- "EUR:5",
- MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount (
+ "withdraw-coin-r1",
+ "create-reserve-r1",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit (
+ "deposit-refund-1",
+ "withdraw-coin-r1",
+ 0,
+ cred.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_MINUTES,
+ "EUR:5",
+ MHD_HTTP_OK),
TALER_TESTING_cmd_refund ("refund-currency-mismatch",
MHD_HTTP_BAD_REQUEST,
"USD:5",
"deposit-refund-1"),
TALER_TESTING_cmd_flip_upload ("flip-upload",
- CONFIG_FILE,
+ config_file,
"merchant_sig"),
TALER_TESTING_cmd_refund ("refund-bad-sig",
MHD_HTTP_FORBIDDEN,
"EUR:5",
"deposit-refund-1"),
-
/* This next deposit CMD is only used to provide a
* good merchant signature to the next (failing) refund
* operations. */
- TALER_TESTING_cmd_deposit ("deposit-refund-to-fail",
- "withdraw-coin-r1",
- 0, /* coin index. */
- bc.user42_payto,
- /* This parameter will make any comparison about
- h_contract_terms fail, when /refund will be handled.
- So in other words, this is h_contract mismatch. */
- "{\"items\":[{\"name\":\"ice skate\","
- "\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_MINUTES,
- "EUR:5",
- MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_deposit (
+ "deposit-refund-to-fail",
+ "withdraw-coin-r1",
+ 0, /* coin index. */
+ cred.user42_payto,
+ /* This parameter will make any comparison about
+ h_contract_terms fail, when /refund will be handled.
+ So in other words, this is h_contract mismatch. */
+ "{\"items\":[{\"name\":\"ice skate\",\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_MINUTES,
+ "EUR:5",
+ MHD_HTTP_CONFLICT),
TALER_TESTING_cmd_refund ("refund-deposit-not-found",
MHD_HTTP_NOT_FOUND,
"EUR:5",
@@ -210,15 +216,17 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
+#if 0
/**
* Test that we don't get errors when the keys from the exchange
* are out of date.
*/
struct TALER_TESTING_Command expired_keys[] = {
- TALER_TESTING_cmd_modify_header_dl ("modify-expiration",
- CONFIG_FILE,
- MHD_HTTP_HEADER_EXPIRES,
- "Wed, 19 Jan 586524 08:01:49 GMT"),
+ TALER_TESTING_cmd_modify_header_dl (
+ "modify-expiration",
+ config_file,
+ MHD_HTTP_HEADER_EXPIRES,
+ "Wed, 19 Jan 586524 08:01:49 GMT"),
TALER_TESTING_cmd_check_keys_pull_all_keys (
"check-keys-expiration-0",
2),
@@ -228,41 +236,52 @@ run (void *cls,
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r2",
"EUR:55.01"),
CMD_EXEC_WIREWATCH ("wirewatch-r2"),
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r2",
- "create-reserve-r2",
- "EUR:5",
- MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount (
+ "withdraw-coin-r2",
+ "create-reserve-r2",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
TALER_TESTING_cmd_end ()
};
+#endif
struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/2",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
- CONFIG_FILE),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 1),
- TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict",
- refresh_409_conflict),
- TALER_TESTING_cmd_batch ("refund",
- refund),
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_batch (
+ "refresh-reveal-409-conflict",
+ refresh_409_conflict),
+ TALER_TESTING_cmd_batch (
+ "refund",
+ refund),
+#if 0
TALER_TESTING_cmd_batch ("expired-keys",
expired_keys),
+#endif
TALER_TESTING_cmd_end ()
};
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
+ (void) cls;
+ TALER_TESTING_run (is,
+ commands);
}
/**
* Kill, wait, and destroy convenience function.
*
- * @param process process to purge.
+ * @param[in] process process to purge.
*/
static void
purge_process (struct GNUNET_OS_Process *process)
@@ -280,47 +299,35 @@ main (int argc,
{
int ret;
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-exchange-api-twisted",
- "DEBUG",
- NULL);
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "exchange-account-2",
- &bc))
- return 77;
- if (NULL == (twister_url = TALER_TWISTER_prepare_twister
- (CONFIG_FILE)))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- GNUNET_YES,
- &ec))
+ (void) argc;
{
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (NULL == (twisterd = TALER_TWISTER_run_twister (CONFIG_FILE)))
- return 77;
- ret = TALER_TESTING_setup_with_exchange (&run,
- NULL,
- CONFIG_FILE);
- purge_process (twisterd);
- GNUNET_free (twister_url);
+ char *cipher;
- if (GNUNET_OK != ret)
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api_twisted-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
}
- return 0;
+ /* FIXME: introduce commands for twister! */
+ twister_url = TALER_TWISTER_prepare_twister (config_file);
+ if (NULL == twister_url)
+ return 77;
+ twisterd = TALER_TWISTER_run_twister (config_file);
+ if (NULL == twisterd)
+ return 77;
+ ret = TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
+ purge_process (twisterd);
+ GNUNET_free (twister_url);
+ return ret;
}
diff --git a/src/testing/test_exchange_api_twisted.conf b/src/testing/test_exchange_api_twisted.conf
deleted file mode 100644
index a41cfd43c..000000000
--- a/src/testing/test_exchange_api_twisted.conf
+++ /dev/null
@@ -1,150 +0,0 @@
-# This file is in the public domain.
-[PATHS]
-# Persistent data storage for the testcase
-TALER_TEST_HOME = test_exchange_api_home/
-TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
-
-[taler-exchange-secmod-rsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
-
-[taler-exchange-secmod-eddsa]
-# Reduce from 1 year to speed up test
-LOOKAHEAD_SIGN = 24 days
-# Reduce from 12 weeks to ensure we have multiple
-DURATION = 14 days
-
-[taler]
-# Currency supported by the exchange (can only be one)
-CURRENCY = EUR
-CURRENCY_ROUND_UNIT = EUR:0.01
-
-[exchange]
-# HTTP port the exchange listens to
-PORT = 8081
-
-# Master public key used to sign the exchange's various keys
-MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-
-# How to access our database
-DB = postgres
-
-# Base URL of the exchange ('S PROXY). This URL is where the
-# twister listens at, so that it will be able to get all the
-# connection addressed to the exchange. In fact, the presence
-# of the twister is 100% transparent to the test case, as it
-# only seeks the exchange/BASE_URL URL to connect to the exchange.
-BASE_URL = "http://localhost:8888/"
-
-[exchangedb-postgres]
-CONFIG = "postgres:///talercheck"
-
-[auditor]
-BASE_URL = "http://localhost:8083/"
-PORT = 8083
-
-[auditordb-postgres]
-CONFIG = "postgres:///talercheck"
-
-[exchange-account-1]
-# What is the URL of our account?
-PAYTO_URI = "payto://x-taler-bank/localhost/42"
-
-[exchange-accountcredentials-1]
-WIRE_GATEWAY_URL = "http://localhost:9081/42/"
-WIRE_GATEWAY_AUTH_METHOD = NONE
-
-[exchange-account-2]
-PAYTO_URI = payto://x-taler-bank/localhost/2
-ENABLE_DEBIT = YES
-ENABLE_CREDIT = YES
-
-[exchange-accountcredentials-2]
-WIRE_GATEWAY_URL = "http://localhost:8082/2/"
-WIRE_GATEWAY_AUTH_METHOD = BASIC
-USERNAME = user
-PASSWORD = pass
-
-[bank]
-HTTP_PORT = 8082
-
-[twister]
-# HTTP listen port for twister
-HTTP_PORT = 8888
-SERVE = tcp
-
-# HTTP Destination for twister. The test-Webserver needs
-# to listen on the port used here. Note: no trailing '/'!
-DESTINATION_BASE_URL = "http://localhost:8081"
-
-# Control port for TCP
-# PORT = 8889
-HOSTNAME = localhost
-ACCEPT_FROM = 127.0.0.1;
-ACCEPT_FROM6 = ::1;
-
-# Control port for UNIX
-UNIXPATH = /tmp/taler-service-twister.sock
-UNIX_MATCH_UID = NO
-UNIX_MATCH_GID = YES
-
-# Launching of twister by ARM
-# BINARY = taler-service-twister
-# AUTOSTART = NO
-# FORCESTART = NO
-
-
-[coin_eur_ct_1]
-value = EUR:0.01
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.00
-fee_deposit = EUR:0.00
-fee_refresh = EUR:0.01
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_ct_10]
-value = EUR:0.10
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_1]
-value = EUR:1
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_5]
-value = EUR:5
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
-
-[coin_eur_10]
-value = EUR:10
-duration_withdraw = 7 days
-duration_spend = 2 years
-duration_legal = 3 years
-fee_withdraw = EUR:0.01
-fee_deposit = EUR:0.01
-fee_refresh = EUR:0.03
-fee_refund = EUR:0.01
-rsa_keysize = 1024
diff --git a/src/testing/test_exchange_management_api.c b/src/testing/test_exchange_management_api.c
index 0cf968237..7cce61b55 100644
--- a/src/testing/test_exchange_management_api.c
+++ b/src/testing/test_exchange_management_api.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020 Taler Systems SA
+ Copyright (C) 2020-2023 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
@@ -25,6 +25,7 @@
#include "taler_util.h"
#include "taler_exchange_service.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_testing_lib.h"
@@ -32,18 +33,12 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
-#define CONFIG_FILE "test_exchange_api.conf"
-
+static char *config_file;
/**
- * Exchange configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
+static struct TALER_TESTING_Credentials cred;
/**
@@ -57,10 +52,21 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command commands[] = {
- /* this currently fails, because the
- auditor is already added by the test setup logic */
- TALER_TESTING_cmd_auditor_del ("del-auditor-NOT-FOUND",
- MHD_HTTP_NOT_FOUND,
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-u", "exchange-account-2",
+ "-ae",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_get_auditor ("get-auditor",
+ cred.cfg,
+ true),
+ TALER_TESTING_cmd_auditor_del ("del-auditor-FROM-SETUP",
+ MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_auditor_add ("add-auditor-BAD-SIG",
MHD_HTTP_FORBIDDEN,
@@ -111,43 +117,51 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/42",
+ "payto://x-taler-bank/localhost/42?receiver-name=42",
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_wire_add ("add-wire-account-idempotent",
- "payto://x-taler-bank/localhost/42",
+ "payto://x-taler-bank/localhost/42?receiver-name=42",
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_wire_add ("add-wire-account-another",
- "payto://x-taler-bank/localhost/43",
+ "payto://x-taler-bank/localhost/43?receiver-name=43",
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_wire_add ("add-wire-account-bad-signature",
- "payto://x-taler-bank/localhost/44",
+ "payto://x-taler-bank/localhost/44?receiver-name=44",
MHD_HTTP_FORBIDDEN,
true),
TALER_TESTING_cmd_wire_del ("del-wire-account-not-found",
- "payto://x-taler-bank/localhost/44",
+ "payto://x-taler-bank/localhost/44?receiver-name=44",
MHD_HTTP_NOT_FOUND,
false),
TALER_TESTING_cmd_wire_del ("del-wire-account-bad-signature",
- "payto://x-taler-bank/localhost/43",
+ "payto://x-taler-bank/localhost/43?receiver-name=43",
MHD_HTTP_FORBIDDEN,
true),
TALER_TESTING_cmd_wire_del ("del-wire-account-ok",
- "payto://x-taler-bank/localhost/43",
+ "payto://x-taler-bank/localhost/43?receiver-name=43",
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("download-future-keys",
- CONFIG_FILE),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 1),
+ config_file),
+ TALER_TESTING_cmd_get_exchange ("get-exchange-1",
+ cred.cfg,
+ "get-exchange",
+ true,
+ true),
+ TALER_TESTING_cmd_get_exchange ("get-exchange-2",
+ cred.cfg,
+ NULL,
+ true,
+ true),
TALER_TESTING_cmd_end ()
};
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
+ (void) cls;
+ TALER_TESTING_run (is,
+ commands);
}
@@ -155,47 +169,25 @@ 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-management-api",
- "INFO",
- NULL);
- /* Check fakebank port is available and get config */
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "exchange-account-2",
- &bc))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. 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,
- GNUNET_YES, /* reset DB? */
- &ec))
+ (void) argc;
{
- 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;
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
}
- return 0;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_exchange_p2p.c b/src/testing/test_exchange_p2p.c
new file mode 100644
index 000000000..093730ff2
--- /dev/null
+++ b/src/testing/test_exchange_p2p.c
@@ -0,0 +1,557 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014--2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/test_exchange_p2p.c
+ * @brief testcase to test exchange's P2P payments
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_attributes.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 <gnunet/gnunet_testing_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+#include "taler_extensions.h"
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+static char *config_file;
+
+/**
+ * Our credentials.
+ */
+struct TALER_TESTING_Credentials cred;
+
+/**
+ * Some tests behave differently when using CS as we cannot
+ * reuse the coin private key for different denominations
+ * due to the derivation of it with the /csr values. Hence
+ * some tests behave differently in CS mode, hence this
+ * flag.
+ */
+static bool uses_cs;
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_WIREWATCH(label) \
+ TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, "exchange-account-2")
+
+/**
+ * Execute the taler-exchange-aggregator, closer and transfer commands with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_sleep ("sleep-before-aggregator", 2), \
+ TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
+ TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
+
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ */
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+ TALER_TESTING_cmd_admin_add_incoming (label, amount, \
+ &cred.ba, \
+ cred.user42_payto)
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ * @param is interpreter we use to run commands
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ /**
+ * Test withdrawal plus spending.
+ */
+ struct TALER_TESTING_Command withdraw[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
+ "EUR:5.04"),
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-2",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_reserve_poll ("poll-reserve-1",
+ "create-reserve-1",
+ "EUR:5.04",
+ GNUNET_TIME_UNIT_MINUTES,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
+ "EUR:5.04",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-1"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-2",
+ "EUR:5.01",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-2"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-1"),
+ TALER_TESTING_cmd_reserve_poll_finish ("finish-poll-reserve-1",
+ GNUNET_TIME_UNIT_SECONDS,
+ "poll-reserve-1"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
+ "create-reserve-1",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
+ /**
+ * Check the reserve is depleted.
+ */
+ TALER_TESTING_cmd_status ("status-1",
+ "create-reserve-1",
+ "EUR:0.03",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command push[] = {
+ TALER_TESTING_cmd_purse_create_with_deposit (
+ "purse-with-deposit-for-delete",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true, /* upload contract */
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "withdraw-coin-1",
+ "EUR:1.01",
+ NULL),
+ TALER_TESTING_cmd_purse_delete (
+ "purse-with-deposit-delete",
+ MHD_HTTP_NO_CONTENT,
+ "purse-with-deposit-for-delete"),
+ TALER_TESTING_cmd_purse_create_with_deposit (
+ "purse-with-deposit",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:0.99\",\"summary\":\"ice cream\"}",
+ true, /* upload contract */
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "withdraw-coin-1",
+ "EUR:1.00",
+ NULL),
+ TALER_TESTING_cmd_purse_poll (
+ "push-poll-purse-before-merge",
+ MHD_HTTP_OK,
+ "purse-with-deposit",
+ "EUR:0.99",
+ true,
+ GNUNET_TIME_UNIT_MINUTES),
+ TALER_TESTING_cmd_contract_get (
+ "push-get-contract",
+ MHD_HTTP_OK,
+ true, /* for merge */
+ "purse-with-deposit"),
+ TALER_TESTING_cmd_purse_merge (
+ "purse-merge-into-reserve",
+ MHD_HTTP_OK,
+ "push-get-contract",
+ "create-reserve-1"),
+ TALER_TESTING_cmd_purse_poll_finish (
+ "push-merge-purse-poll-finish",
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "push-poll-purse-before-merge"),
+ TALER_TESTING_cmd_status (
+ "push-check-post-merge-reserve-balance-get",
+ "create-reserve-1",
+ "EUR:1.02",
+ MHD_HTTP_OK),
+ /* POST history doesn't yet support P2P transfers */
+ TALER_TESTING_cmd_reserve_history (
+ "push-check-post-merge-reserve-balance-post",
+ "create-reserve-1",
+ "EUR:1.02",
+ MHD_HTTP_OK),
+ /* Test conflicting merge */
+ TALER_TESTING_cmd_purse_merge (
+ "purse-merge-into-reserve",
+ MHD_HTTP_CONFLICT,
+ "push-get-contract",
+ "create-reserve-2"),
+
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command pull[] = {
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true /* upload contract */,
+ true /* pay purse fee */,
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "create-reserve-1"),
+ TALER_TESTING_cmd_contract_get (
+ "pull-get-contract",
+ MHD_HTTP_OK,
+ false, /* for deposit */
+ "purse-create-with-reserve"),
+ TALER_TESTING_cmd_purse_poll (
+ "pull-poll-purse-before-deposit",
+ MHD_HTTP_OK,
+ "purse-create-with-reserve",
+ "EUR:1",
+ false,
+ GNUNET_TIME_UNIT_MINUTES),
+ TALER_TESTING_cmd_purse_deposit_coins (
+ "purse-deposit-coins",
+ MHD_HTTP_OK,
+ 0 /* min age */,
+ "purse-create-with-reserve",
+ "withdraw-coin-1",
+ "EUR:1.01",
+ NULL),
+ TALER_TESTING_cmd_purse_poll_finish (
+ "pull-deposit-purse-poll-finish",
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "pull-poll-purse-before-deposit"),
+ TALER_TESTING_cmd_status (
+ "pull-check-post-merge-reserve-balance-get",
+ "create-reserve-1",
+ "EUR:2.02",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_reserve_history (
+ "push-check-post-merge-reserve-balance-post",
+ "create-reserve-1",
+ "EUR:2.02",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_purse_deposit_coins (
+ "purse-deposit-coins-idempotent",
+ MHD_HTTP_OK,
+ 0 /* min age */,
+ "purse-create-with-reserve",
+ "withdraw-coin-1",
+ "EUR:1.01",
+ NULL),
+ /* create 2nd purse for a deposit conflict */
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve-2",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:4\",\"summary\":\"beer\"}",
+ true /* upload contract */,
+ true /* pay purse fee */,
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "create-reserve-1"),
+ TALER_TESTING_cmd_purse_deposit_coins (
+ "purse-deposit-coins-conflict",
+ MHD_HTTP_CONFLICT,
+ 0 /* min age */,
+ "purse-create-with-reserve-2",
+ "withdraw-coin-1",
+ "EUR:4.01",
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command expire[] = {
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve-expire",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:2\",\"summary\":\"ice cream\"}",
+ true /* upload contract */,
+ true /* pay purse fee */,
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 1), /* expiration */
+ "create-reserve-1"),
+ TALER_TESTING_cmd_purse_poll (
+ "pull-poll-purse-before-expire",
+ MHD_HTTP_GONE,
+ "purse-create-with-reserve-expire",
+ "EUR:1",
+ false,
+ GNUNET_TIME_UNIT_MINUTES),
+ TALER_TESTING_cmd_purse_create_with_deposit (
+ "purse-with-deposit-expire",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true, /* upload contract */
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 1), /* expiration */
+ "withdraw-coin-1",
+ "EUR:1.01",
+ NULL),
+ TALER_TESTING_cmd_purse_poll (
+ "push-poll-purse-before-expire",
+ MHD_HTTP_GONE,
+ "purse-with-deposit-expire",
+ "EUR:1",
+ true,
+ GNUNET_TIME_UNIT_MINUTES),
+ /* This should fail, as too much of the coin
+ is already spend / in a purse */
+ TALER_TESTING_cmd_purse_create_with_deposit (
+ "purse-with-deposit-overspending",
+ MHD_HTTP_CONFLICT,
+ "{\"amount\":\"EUR:2\",\"summary\":\"ice cream\"}",
+ true, /* upload contract */
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 1), /* expiration */
+ "withdraw-coin-1",
+ "EUR:2.01",
+ NULL),
+ TALER_TESTING_cmd_sleep ("sleep",
+ 2 /* seconds */),
+ TALER_TESTING_cmd_exec_expire ("exec-expire",
+ config_file),
+ TALER_TESTING_cmd_purse_poll_finish (
+ "push-merge-purse-poll-finish-expire",
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 15),
+ "push-poll-purse-before-expire"),
+ TALER_TESTING_cmd_purse_poll_finish (
+ "pull-deposit-purse-poll-expire-finish",
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 15),
+ "pull-poll-purse-before-expire"),
+ /* coin was refunded, so now this should be OK */
+ /* This should fail, as too much of the coin
+ is already spend / in a purse */
+ TALER_TESTING_cmd_purse_create_with_deposit (
+ "purse-with-deposit-refunded",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:2\",\"summary\":\"ice cream\"}",
+ true, /* upload contract */
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 1), /* expiration */
+ "withdraw-coin-1",
+ "EUR:2.01",
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command reserves[] = {
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-100",
+ "EUR:1.04"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-100",
+ "EUR:1.04",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-100"),
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-101",
+ "EUR:1.04"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-101",
+ "EUR:1.04",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-101"),
+ CMD_EXEC_WIREWATCH ("wirewatch-100"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-100",
+ "create-reserve-100",
+ "EUR:1",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_reserve_open ("reserve-open-101-fail",
+ "create-reserve-101",
+ "EUR:0",
+ GNUNET_TIME_UNIT_YEARS,
+ 5, /* min purses */
+ MHD_HTTP_PAYMENT_REQUIRED,
+ NULL,
+ NULL),
+ TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok-a",
+ "create-reserve-101",
+ "EUR:0.01",
+ GNUNET_TIME_UNIT_MONTHS,
+ 1, /* min purses */
+ MHD_HTTP_OK,
+ NULL,
+ NULL),
+ TALER_TESTING_cmd_status ("status-101-open-paid",
+ "create-reserve-101",
+ "EUR:1.03",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_reserve_open ("reserve-open-101-ok-b",
+ "create-reserve-101",
+ "EUR:0",
+ GNUNET_TIME_UNIT_MONTHS,
+ 2, /* min purses */
+ MHD_HTTP_OK,
+ "withdraw-coin-100",
+ "EUR:0.03", /* 0.02 for the reserve open, 0.01 for deposit fee */
+ NULL,
+ NULL),
+ /* Use purse creation with purse quota here */
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve-101-a",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true /* upload contract */,
+ false /* pay purse fee */,
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "create-reserve-101"),
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve-101-b",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true /* upload contract */,
+ false /* pay purse fee */,
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "create-reserve-101"),
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve-101-fail",
+ MHD_HTTP_CONFLICT,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true /* upload contract */,
+ false /* pay purse fee */,
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "create-reserve-101"),
+ TALER_TESTING_cmd_reserve_get_attestable ("reserve-101-attestable",
+ "create-reserve-101",
+ MHD_HTTP_NOT_FOUND,
+ NULL),
+ TALER_TESTING_cmd_reserve_get_attestable ("reserve-101-attest",
+ "create-reserve-101",
+ MHD_HTTP_NOT_FOUND,
+ "nx-attribute-name",
+ NULL),
+ TALER_TESTING_cmd_oauth ("start-oauth-service",
+ 6666),
+ TALER_TESTING_cmd_reserve_close ("reserve-101-close-kyc",
+ "create-reserve-101",
+ /* 42b => not to origin */
+ "payto://x-taler-bank/localhost/42?receiver-name=42b",
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
+
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-close-pending",
+ "reserve-101-close-kyc",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-close-kyc",
+ "reserve-101-close-kyc",
+ "kyc-provider-test-oauth2",
+ "pass",
+ MHD_HTTP_SEE_OTHER),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-close-ok",
+ "reserve-101-close-kyc",
+ MHD_HTTP_NO_CONTENT),
+ /* Now it should pass */
+ TALER_TESTING_cmd_reserve_close ("reserve-101-close",
+ "create-reserve-101",
+ /* 42b => not to origin */
+ "payto://x-taler-bank/localhost/42?receiver-name=42b",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_exec_closer ("close-reserves-101",
+ config_file,
+ "EUR:1.02",
+ "EUR:0.01",
+ "create-reserve-101"),
+ TALER_TESTING_cmd_exec_transfer ("close-reserves-101-transfer",
+ config_file),
+ TALER_TESTING_cmd_status ("reserve-101-closed-status",
+ "create-reserve-101",
+ "EUR:0",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_file,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_batch ("withdraw",
+ withdraw),
+ TALER_TESTING_cmd_batch ("push",
+ push),
+ TALER_TESTING_cmd_batch ("pull",
+ pull),
+ TALER_TESTING_cmd_batch ("expire",
+ expire),
+ TALER_TESTING_cmd_batch ("reserves",
+ reserves),
+ /* End the suite. */
+ TALER_TESTING_cmd_end ()
+ };
+
+ (void) cls;
+ TALER_TESTING_run (is,
+ commands);
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ (void) argc;
+ {
+ char *cipher;
+
+ cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
+ GNUNET_assert (NULL != cipher);
+ uses_cs = (0 == strcmp (cipher, "cs"));
+ GNUNET_asprintf (&config_file,
+ "test_exchange_api-%s.conf",
+ cipher);
+ GNUNET_free (cipher);
+ }
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_file,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
+}
+
+
+/* end of test_exchange_p2p.c */
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
new file mode 100644
index 000000000..0844c5818
--- /dev/null
+++ b/src/testing/test_kyc_api.c
@@ -0,0 +1,581 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/test_kyc_api.c
+ * @brief testcase to test the KYC processes
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_attributes.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_kyc_api.conf"
+
+/**
+ * Our credentials.
+ */
+struct TALER_TESTING_Credentials cred;
+
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_WIREWATCH(label) \
+ TALER_TESTING_cmd_exec_wirewatch2 (label, CONFIG_FILE, "exchange-account-2")
+
+/**
+ * Execute the taler-exchange-aggregator, closer and transfer commands with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_sleep (label "-sleep", 1), \
+ TALER_TESTING_cmd_exec_aggregator_with_kyc (label, CONFIG_FILE), \
+ TALER_TESTING_cmd_exec_transfer (label, CONFIG_FILE)
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ */
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+ TALER_TESTING_cmd_admin_add_incoming (label, amount, \
+ &cred.ba, \
+ cred.user42_payto)
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command withdraw[] = {
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
+ "EUR:15.02"),
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "check-create-reserve-1",
+ "EUR:15.02",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "create-reserve-1"),
+ CMD_EXEC_WIREWATCH ("wirewatch-1"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-no-kyc",
+ "create-reserve-1",
+ "EUR:10",
+ 0, /* age restriction off */
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
+ "create-reserve-1",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+ /**
+ * Test withdraw with KYC.
+ */
+ struct TALER_TESTING_Command withdraw_kyc[] = {
+ CMD_EXEC_WIREWATCH ("wirewatch-1"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-lacking-kyc",
+ "create-reserve-1",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-withdraw",
+ "withdraw-coin-1-lacking-kyc",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc",
+ "withdraw-coin-1-lacking-kyc",
+ "kyc-provider-test-oauth2",
+ "pass",
+ MHD_HTTP_SEE_OTHER),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-with-kyc",
+ "create-reserve-1",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
+ /* Attestations above are bound to the originating *bank* account,
+ not to the reserve (!). Hence, they are NOT found here! */
+ TALER_TESTING_cmd_reserve_get_attestable ("reserve-get-attestable",
+ "create-reserve-1",
+ MHD_HTTP_NOT_FOUND,
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command spend[] = {
+ TALER_TESTING_cmd_deposit (
+ "deposit-simple",
+ "withdraw-coin-1",
+ 0,
+ cred.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_track_transaction (
+ "track-deposit",
+ "deposit-simple",
+ 0,
+ MHD_HTTP_ACCEPTED,
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command track[] = {
+ CMD_EXEC_AGGREGATOR ("run-aggregator-before-kyc"),
+ TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-no-kyc"),
+ TALER_TESTING_cmd_track_transaction (
+ "track-deposit-kyc-ready",
+ "deposit-simple",
+ 0,
+ MHD_HTTP_ACCEPTED,
+ NULL),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-deposit",
+ "track-deposit-kyc-ready",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc-no-service",
+ "track-deposit-kyc-ready",
+ "kyc-provider-test-oauth2",
+ "bad",
+ MHD_HTTP_BAD_GATEWAY),
+ TALER_TESTING_cmd_oauth ("start-oauth-service",
+ 6666),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc-fail",
+ "track-deposit-kyc-ready",
+ "kyc-provider-test-oauth2",
+ "bad",
+ MHD_HTTP_FORBIDDEN),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-deposit-again",
+ "track-deposit-kyc-ready",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-kyc-pass",
+ "track-deposit-kyc-ready",
+ "kyc-provider-test-oauth2",
+ "pass",
+ MHD_HTTP_SEE_OTHER),
+ CMD_EXEC_AGGREGATOR ("run-aggregator-after-kyc"),
+ TALER_TESTING_cmd_check_bank_transfer (
+ "check_bank_transfer-499c",
+ cred.exchange_url,
+ "EUR:4.98",
+ cred.exchange_payto,
+ cred.user43_payto),
+ TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command wallet_kyc[] = {
+ TALER_TESTING_cmd_wallet_kyc_get ("wallet-kyc-fail",
+ NULL,
+ "EUR:1000000",
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-wallet",
+ "wallet-kyc-fail",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("proof-wallet-kyc",
+ "wallet-kyc-fail",
+ "kyc-provider-test-oauth2",
+ "pass",
+ MHD_HTTP_SEE_OTHER),
+ TALER_TESTING_cmd_check_kyc_get ("wallet-kyc-check",
+ "wallet-kyc-fail",
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_reserve_get_attestable ("wallet-get-attestable",
+ "wallet-kyc-fail",
+ MHD_HTTP_OK,
+ TALER_ATTRIBUTE_FULL_NAME,
+ NULL),
+ TALER_TESTING_cmd_reserve_attest ("wallet-get-attest",
+ "wallet-kyc-fail",
+ MHD_HTTP_OK,
+ TALER_ATTRIBUTE_FULL_NAME,
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
+
+ /**
+ * Test withdrawal for P2P
+ */
+ struct TALER_TESTING_Command p2p_withdraw[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-1",
+ "EUR:5.04"),
+ CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-2",
+ "EUR:5.01"),
+ CMD_TRANSFER_TO_EXCHANGE ("p2p_create-reserve-3",
+ "EUR:0.03"),
+ TALER_TESTING_cmd_reserve_poll ("p2p_poll-reserve-1",
+ "p2p_create-reserve-1",
+ "EUR:5.04",
+ GNUNET_TIME_UNIT_MINUTES,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("p2p_check-create-reserve-1",
+ "EUR:5.04",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "p2p_create-reserve-1"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("p2p_check-create-reserve-2",
+ "EUR:5.01",
+ cred.user42_payto,
+ cred.exchange_payto,
+ "p2p_create-reserve-2"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("p2p_wirewatch-1"),
+ TALER_TESTING_cmd_reserve_poll_finish ("p2p_finish-poll-reserve-1",
+ GNUNET_TIME_UNIT_SECONDS,
+ "p2p_poll-reserve-1"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("p2p_withdraw-coin-1",
+ "p2p_create-reserve-1",
+ "EUR:5",
+ 0, /* age restriction off */
+ MHD_HTTP_OK),
+ /**
+ * Check the reserve is depleted.
+ */
+ TALER_TESTING_cmd_status ("p2p_status-1",
+ "p2p_create-reserve-1",
+ "EUR:0.03",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command push[] = {
+ TALER_TESTING_cmd_purse_create_with_deposit (
+ "purse-with-deposit",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true, /* upload contract */
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "p2p_withdraw-coin-1",
+ "EUR:1.01",
+ NULL),
+ TALER_TESTING_cmd_coin_history ("coin-history-purse-with-deposit",
+ "p2p_withdraw-coin-1#0",
+ "EUR:3.99",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_purse_poll (
+ "push-poll-purse-before-merge",
+ MHD_HTTP_OK,
+ "purse-with-deposit",
+ "EUR:1",
+ true,
+ GNUNET_TIME_UNIT_MINUTES),
+ TALER_TESTING_cmd_contract_get (
+ "push-get-contract",
+ MHD_HTTP_OK,
+ true, /* for merge */
+ "purse-with-deposit"),
+ TALER_TESTING_cmd_purse_merge (
+ "purse-merge-into-reserve",
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
+ "push-get-contract",
+ "p2p_create-reserve-1"),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-purse-merge",
+ "purse-merge-into-reserve",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc",
+ "purse-merge-into-reserve",
+ "kyc-provider-test-oauth2",
+ "pass",
+ MHD_HTTP_SEE_OTHER),
+ TALER_TESTING_cmd_purse_merge (
+ "purse-merge-into-reserve",
+ MHD_HTTP_OK,
+ "push-get-contract",
+ "p2p_create-reserve-1"),
+ TALER_TESTING_cmd_purse_poll_finish (
+ "push-merge-purse-poll-finish",
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "push-poll-purse-before-merge"),
+ TALER_TESTING_cmd_status (
+ "push-check-post-merge-reserve-balance-get",
+ "p2p_create-reserve-1",
+ "EUR:1.03",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_reserve_history (
+ "push-check-post-merge-reserve-balance-post",
+ "p2p_create-reserve-1",
+ "EUR:1.03",
+ MHD_HTTP_OK),
+
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command pull[] = {
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve",
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true /* upload contract */,
+ true /* pay purse fee */,
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "p2p_create-reserve-3"),
+ TALER_TESTING_cmd_check_kyc_get ("check-kyc-purse-create",
+ "purse-create-with-reserve",
+ MHD_HTTP_ACCEPTED),
+ TALER_TESTING_cmd_proof_kyc_oauth2 ("p2p_proof-kyc-pull",
+ "purse-create-with-reserve",
+ "kyc-provider-test-oauth2",
+ "pass",
+ MHD_HTTP_SEE_OTHER),
+ TALER_TESTING_cmd_purse_create_with_reserve (
+ "purse-create-with-reserve",
+ MHD_HTTP_OK,
+ "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}",
+ true /* upload contract */,
+ true /* pay purse fee */,
+ GNUNET_TIME_UNIT_MINUTES, /* expiration */
+ "p2p_create-reserve-3"),
+ TALER_TESTING_cmd_contract_get (
+ "pull-get-contract",
+ MHD_HTTP_OK,
+ false, /* for deposit */
+ "purse-create-with-reserve"),
+ TALER_TESTING_cmd_purse_poll (
+ "pull-poll-purse-before-deposit",
+ MHD_HTTP_OK,
+ "purse-create-with-reserve",
+ "EUR:1",
+ false,
+ GNUNET_TIME_UNIT_MINUTES),
+ TALER_TESTING_cmd_purse_deposit_coins (
+ "purse-deposit-coins",
+ MHD_HTTP_OK,
+ 0 /* min age */,
+ "purse-create-with-reserve",
+ "p2p_withdraw-coin-1",
+ "EUR:1.01",
+ NULL),
+ TALER_TESTING_cmd_coin_history ("coin-history-purse-pull-deposit",
+ "p2p_withdraw-coin-1#0",
+ "EUR:2.98",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_purse_poll_finish (
+ "pull-deposit-purse-poll-finish",
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "pull-poll-purse-before-deposit"),
+ TALER_TESTING_cmd_status (
+ "pull-check-post-merge-reserve-balance-get-2",
+ "p2p_create-reserve-3",
+ "EUR:1.03",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_reserve_history (
+ "push-check-post-merge-reserve-balance-post-2",
+ "p2p_create-reserve-3",
+ "EUR:1.03",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command aml[] = {
+ /* Trigger something upon which an AML officer could act */
+ TALER_TESTING_cmd_wallet_kyc_get ("wallet-trigger-kyc-for-aml",
+ NULL,
+ "EUR:1000",
+ MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS),
+ TALER_TESTING_cmd_set_officer ("create-aml-officer-1",
+ NULL,
+ "Peter Falk",
+ true,
+ false),
+ TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-normal",
+ "create-aml-officer-1",
+ TALER_AML_NORMAL,
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-pending",
+ "create-aml-officer-1",
+ TALER_AML_PENDING,
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_check_aml_decisions ("check-decisions-none-frozen",
+ "create-aml-officer-1",
+ TALER_AML_FROZEN,
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_sleep ("sleep-1a",
+ 1),
+ TALER_TESTING_cmd_set_officer ("create-aml-officer-1-disable",
+ "create-aml-officer-1",
+ "Peter Falk",
+ true,
+ true),
+ /* Test that we are not allowed to take AML decisions as our
+ AML staff account is on read-only */
+ TALER_TESTING_cmd_take_aml_decision ("aml-decide-while-disabled",
+ "create-aml-officer-1",
+ "wallet-trigger-kyc-for-aml",
+ "EUR:10000",
+ "party time",
+ TALER_AML_NORMAL,
+ NULL,
+ MHD_HTTP_FORBIDDEN),
+ /* Check that no decision was taken, but that we are allowed
+ to read this information */
+ TALER_TESTING_cmd_check_aml_decision ("check-aml-decision-empty",
+ "create-aml-officer-1",
+ "aml-decide-while-disabled",
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_sleep ("sleep-1b",
+ 1),
+ TALER_TESTING_cmd_set_officer ("create-aml-officer-1-enable",
+ "create-aml-officer-1",
+ "Peter Falk",
+ true,
+ false),
+ TALER_TESTING_cmd_take_aml_decision ("aml-decide",
+ "create-aml-officer-1",
+ "wallet-trigger-kyc-for-aml",
+ "EUR:10000",
+ "party time",
+ TALER_AML_NORMAL,
+ NULL,
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-normal",
+ "create-aml-officer-1",
+ TALER_AML_NORMAL,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_check_aml_decisions ("check-decisions-zero-frozen",
+ "create-aml-officer-1",
+ TALER_AML_FROZEN,
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_check_aml_decision ("check-aml-decision",
+ "create-aml-officer-1",
+ "aml-decide",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_sleep ("sleep-1c",
+ 1),
+ TALER_TESTING_cmd_take_aml_decision ("aml-decide-freeze",
+ "create-aml-officer-1",
+ "wallet-trigger-kyc-for-aml",
+ "EUR:1000",
+ "party over",
+ TALER_AML_FROZEN,
+ NULL,
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_check_aml_decisions ("check-decisions-one-frozen",
+ "create-aml-officer-1",
+ TALER_AML_FROZEN,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_check_aml_decisions ("check-decisions-zero-normal",
+ "create-aml-officer-1",
+ TALER_AML_NORMAL,
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_sleep ("sleep-1d",
+ 1),
+ TALER_TESTING_cmd_set_officer ("create-aml-officer-1-disable",
+ "create-aml-officer-1",
+ "Peter Falk",
+ false,
+ true),
+ /* Test that we are NOT allowed to read AML decisions now that
+ our AML staff account is disabled */
+ TALER_TESTING_cmd_check_aml_decision ("check-aml-decision-disabled",
+ "create-aml-officer-1",
+ "aml-decide",
+ MHD_HTTP_FORBIDDEN),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-2"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ CONFIG_FILE,
+ "-e",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
+ TALER_TESTING_cmd_batch ("withdraw",
+ withdraw),
+ TALER_TESTING_cmd_batch ("spend",
+ spend),
+ TALER_TESTING_cmd_batch ("track",
+ track),
+ TALER_TESTING_cmd_batch ("withdraw-kyc",
+ withdraw_kyc),
+ TALER_TESTING_cmd_batch ("wallet-kyc",
+ wallet_kyc),
+ TALER_TESTING_cmd_batch ("p2p_withdraw",
+ p2p_withdraw),
+ TALER_TESTING_cmd_batch ("push",
+ push),
+ TALER_TESTING_cmd_batch ("pull",
+ pull),
+ TALER_TESTING_cmd_batch ("aml",
+ aml),
+ TALER_TESTING_cmd_end ()
+ };
+
+ (void) cls;
+ TALER_TESTING_run (is,
+ commands);
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ (void) argc;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ CONFIG_FILE,
+ "exchange-account-2",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
+}
+
+
+/* end of test_kyc_api.c */
diff --git a/src/testing/test_kyc_api.conf b/src/testing/test_kyc_api.conf
new file mode 100644
index 000000000..b6bfdb055
--- /dev/null
+++ b/src/testing/test_kyc_api.conf
@@ -0,0 +1,42 @@
+# This file is in the public domain.
+#
+@INLINE@ coins-rsa.conf
+@INLINE@ test_exchange_api.conf
+
+[kyc-provider-test-oauth2]
+COST = 0
+LOGIC = oauth2
+USER_TYPE = INDIVIDUAL
+PROVIDED_CHECKS = DUMMY
+KYC_OAUTH2_VALIDITY = forever
+KYC_OAUTH2_TOKEN_URL = http://localhost:6666/oauth/v2/token
+KYC_OAUTH2_AUTHORIZE_URL = http://localhost:6666/oauth/v2/login
+KYC_OAUTH2_INFO_URL = http://localhost:6666/api/user/me
+KYC_OAUTH2_CLIENT_ID = taler-exchange
+KYC_OAUTH2_CLIENT_SECRET = exchange-secret
+KYC_OAUTH2_POST_URL = http://example.com/
+KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh
+# "{"full_name":"{{last_name}}, {{first_name}}"}"
+
+[kyc-legitimization-balance-high]
+OPERATION_TYPE = BALANCE
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:8
+
+[kyc-legitimization-deposit-any]
+OPERATION_TYPE = DEPOSIT
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:0
+TIMEFRAME = 1d
+
+[kyc-legitimization-withdraw]
+OPERATION_TYPE = WITHDRAW
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:10
+TIMEFRAME = 1d
+
+[kyc-legitimization-merge]
+OPERATION_TYPE = MERGE
+REQUIRED_CHECKS = DUMMY
+THRESHOLD = EUR:0
+TIMEFRAME = 1d
diff --git a/src/testing/test_taler_exchange_aggregator.c b/src/testing/test_taler_exchange_aggregator.c
index 684fe9697..2d7acc6dc 100644
--- a/src/testing/test_taler_exchange_aggregator.c
+++ b/src/testing/test_taler_exchange_aggregator.c
@@ -31,24 +31,9 @@
/**
- * Helper structure to keep exchange configuration values.
+ * Our credentials.
*/
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * Contains plugin.
- */
-static struct TALER_TESTING_DatabaseConnection dbc;
-
-/**
- * Return value from main().
- */
-static int result;
+struct TALER_TESTING_Credentials cred;
/**
* Name of the configuration file to use.
@@ -71,24 +56,6 @@ static char *config_filename;
/**
- * Function run on shutdown to unload the DB plugin.
- *
- * @param cls NULL
- */
-static void
-unload_db (void *cls)
-{
- (void) cls;
- if (NULL != dbc.plugin)
- {
- dbc.plugin->drop_tables (dbc.plugin->cls);
- TALER_EXCHANGEDB_plugin_unload (dbc.plugin);
- dbc.plugin = NULL;
- }
-}
-
-
-/**
* Collects all the tests.
*/
static void
@@ -96,11 +63,13 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command all[] = {
- TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
- config_filename,
- "EUR:0.01",
- "EUR:0.01"),
- // check no aggregation happens on a empty database
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-1"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_filename,
+ "-e",
+ NULL),
CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty-db",
config_filename),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
@@ -108,10 +77,10 @@ run (void *cls,
/* check aggregation happens on the simplest case:
one deposit into the database. */
TALER_TESTING_cmd_insert_deposit ("do-deposit-1",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
"EUR:0.1"),
@@ -119,27 +88,27 @@ run (void *cls,
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.89",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-1"),
/* check aggregation accumulates well. */
TALER_TESTING_cmd_insert_deposit ("do-deposit-2a",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
"EUR:0.1"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-2b",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
"EUR:0.1"),
@@ -148,34 +117,34 @@ run (void *cls,
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-2",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:1.79",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-2"),
/* check that different merchants stem different aggregations. */
TALER_TESTING_cmd_insert_deposit ("do-deposit-3a",
- &dbc,
+ cred.cfg,
"bob",
"4",
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
"EUR:0.1"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-3b",
- &dbc,
+ cred.cfg,
"bob",
"5",
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
"EUR:0.1"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-3c",
- &dbc,
+ cred.cfg,
"alice",
"4",
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
"EUR:0.1"),
@@ -183,38 +152,38 @@ run (void *cls,
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3a",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.89",
- bc.exchange_payto,
- "payto://x-taler-bank/localhost/4"),
+ cred.exchange_payto,
+ "payto://x-taler-bank/localhost/4?receiver-name=4"),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3b",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.89",
- bc.exchange_payto,
- "payto://x-taler-bank/localhost/4"),
+ cred.exchange_payto,
+ "payto://x-taler-bank/localhost/4?receiver-name=4"),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3c",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.89",
- bc.exchange_payto,
- "payto://x-taler-bank/localhost/5"),
+ cred.exchange_payto,
+ "payto://x-taler-bank/localhost/5?receiver-name=5"),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-3"),
/* checking that aggregator waits for the deadline. */
TALER_TESTING_cmd_insert_deposit ("do-deposit-4a",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
5),
"EUR:0.2",
"EUR:0.1"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-4b",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
5),
@@ -230,17 +199,17 @@ run (void *cls,
CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-4-delayed",
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-4",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.19",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
// test picking all deposits at earliest deadline
TALER_TESTING_cmd_insert_deposit ("do-deposit-5a",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
10),
@@ -248,10 +217,10 @@ run (void *cls,
"EUR:0.1"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-5b",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
5),
@@ -267,16 +236,16 @@ run (void *cls,
CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-5-delayed",
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-5",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.19",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
/* Test NEVER running 'tiny' unless they make up minimum unit */
TALER_TESTING_cmd_insert_deposit ("do-deposit-6a",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.102",
"EUR:0.1"),
@@ -285,18 +254,18 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_empty (
"expect-empty-transactions-after-6a-tiny"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-6b",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.102",
"EUR:0.1"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-6c",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.102",
"EUR:0.1"),
@@ -305,10 +274,10 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_empty (
"expect-empty-transactions-after-6c-tiny"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-6d",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.102",
"EUR:0.1"),
@@ -317,27 +286,27 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_empty (
"expect-empty-transactions-after-6d-tiny"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-6e",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.112",
"EUR:0.1"),
CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-6e",
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-6",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
/* Test profiteering if wire deadline is short */
TALER_TESTING_cmd_insert_deposit ("do-deposit-7a",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.109",
"EUR:0.1"),
@@ -346,44 +315,44 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_empty (
"expect-empty-transactions-after-7a-tiny"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-7b",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.119",
"EUR:0.1"),
CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-7-profit",
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
/* Now check profit was actually taken */
TALER_TESTING_cmd_insert_deposit ("do-deposit-7c",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.122",
"EUR:0.1"),
CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-7-loss",
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
/* Test that aggregation would happen fully if wire deadline is long */
TALER_TESTING_cmd_insert_deposit ("do-deposit-8a",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
5),
@@ -394,10 +363,10 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_empty (
"expect-empty-transactions-after-8a-tiny"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-8b",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
5),
@@ -410,27 +379,27 @@ run (void *cls,
/* now trigger aggregate with large transaction and short deadline */
TALER_TESTING_cmd_insert_deposit ("do-deposit-8c",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.122",
"EUR:0.1"),
CMD_EXEC_AGGREGATOR ("run-aggregator-deposit-8",
config_filename),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-8",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.03",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
/* Test aggregation with fees and rounding profits. */
TALER_TESTING_cmd_insert_deposit ("do-deposit-9a",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
5),
@@ -441,10 +410,10 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_empty (
"expect-empty-transactions-after-9a-tiny"),
TALER_TESTING_cmd_insert_deposit ("do-deposit-9b",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_relative_multiply
(GNUNET_TIME_UNIT_SECONDS,
5),
@@ -457,10 +426,10 @@ run (void *cls,
/* now trigger aggregate with large transaction and short deadline */
TALER_TESTING_cmd_insert_deposit ("do-deposit-9c",
- &dbc,
+ cred.cfg,
"bob",
USER42_ACCOUNT,
- GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_timestamp_get (),
GNUNET_TIME_UNIT_ZERO,
"EUR:0.112",
"EUR:0.1"),
@@ -468,49 +437,15 @@ run (void *cls,
config_filename),
/* 0.009 + 0.009 + 0.022 - 0.001 - 0.002 - 0.008 = 0.029 => 0.02 */
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-9",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
TALER_TESTING_cmd_end ()
};
- TALER_TESTING_run_with_fakebank (is,
- all,
- bc.exchange_auth.wire_gateway_url);
-}
-
-
-/**
- * Prepare database and launch the test.
- *
- * @param cls unused
- * @param is interpreter to use
- */
-static void
-prepare_database (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- dbc.plugin = TALER_EXCHANGEDB_plugin_load (is->cfg);
- if (NULL == dbc.plugin)
- {
- GNUNET_break (0);
- result = 77;
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- dbc.plugin->preflight (dbc.plugin->cls))
- {
- GNUNET_break (0);
- result = 77;
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_SCHEDULER_add_shutdown (&unload_db,
- NULL);
- run (NULL,
- is);
+ TALER_TESTING_run (is,
+ all);
}
@@ -519,7 +454,6 @@ main (int argc,
char *const argv[])
{
const char *plugin_name;
- char *testname;
if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
{
@@ -527,52 +461,17 @@ main (int argc,
return -1;
}
plugin_name++;
- (void) GNUNET_asprintf (&testname,
- "test-taler-exchange-aggregator-%s",
- plugin_name);
(void) GNUNET_asprintf (&config_filename,
- "%s.conf",
- testname);
-
- GNUNET_log_setup ("test_taler_exchange_aggregator",
- "DEBUG",
- NULL);
-
- /* these might get in the way */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
-
- TALER_TESTING_cleanup_files (config_filename);
-
- if (GNUNET_OK !=
- TALER_TESTING_prepare_exchange (config_filename,
- GNUNET_YES,
- &ec))
- {
- TALER_LOG_WARNING ("Could not prepare the exchange.\n");
- return 77;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (config_filename,
- "exchange-account-1",
- &bc))
- {
- TALER_LOG_WARNING ("Could not prepare the fakebank\n");
- return 77;
- }
- result = GNUNET_OK;
- if (GNUNET_OK !=
- TALER_TESTING_setup_with_exchange (&prepare_database,
- NULL,
- config_filename))
- {
- TALER_LOG_WARNING ("Could not prepare database for tests.\n");
- return result;
- }
- GNUNET_free (config_filename);
- GNUNET_free (testname);
- return GNUNET_OK == result ? 0 : 1;
+ "test-taler-exchange-aggregator-%s.conf",
+ plugin_name);
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_filename,
+ "exchange-account-1",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json b/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json
deleted file mode 100644
index 21a7500b4..000000000
--- a/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "payto_uri": "payto://x-taler-bank/localhost/2",
- "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R"
-} \ No newline at end of file
diff --git a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv b/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv
deleted file mode 100644
index 394926938..000000000
--- a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv
+++ /dev/null
@@ -1 +0,0 @@
-pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ \ No newline at end of file
diff --git a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv
deleted file mode 100644
index 394926938..000000000
--- a/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv
+++ /dev/null
@@ -1 +0,0 @@
-pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ \ No newline at end of file
diff --git a/src/testing/test_taler_exchange_wirewatch.c b/src/testing/test_taler_exchange_wirewatch.c
index 8477e628e..86b616456 100644
--- a/src/testing/test_taler_exchange_wirewatch.c
+++ b/src/testing/test_taler_exchange_wirewatch.c
@@ -34,14 +34,9 @@
/**
- * Bank configuration data.
+ * Our credentials.
*/
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * Helper structure to keep exchange configuration values.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
+static struct TALER_TESTING_Credentials cred;
/**
* Name of the configuration file to use.
@@ -66,8 +61,8 @@ transfer_to_exchange (const char *label,
{
return TALER_TESTING_cmd_admin_add_incoming (label,
amount,
- &bc.exchange_auth,
- bc.user42_payto);
+ &cred.ba,
+ cred.user42_payto);
}
@@ -82,21 +77,19 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command all[] = {
- TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
- config_filename,
- "EUR:0.01",
- "EUR:0.01"),
- TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_wire_add ("add-wire-account",
- "payto://x-taler-bank/localhost/2",
- MHD_HTTP_NO_CONTENT,
- false),
- TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
- config_filename),
- TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 1),
+ TALER_TESTING_cmd_run_fakebank ("run-fakebank",
+ cred.cfg,
+ "exchange-account-1"),
+ TALER_TESTING_cmd_system_start ("start-taler",
+ config_filename,
+ "-e",
+ "-u", "exchange-account-1",
+ NULL),
+ TALER_TESTING_cmd_get_exchange ("get-exchange",
+ cred.cfg,
+ NULL,
+ true,
+ true),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty"),
TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty",
@@ -111,8 +104,8 @@ run (void *cls,
TALER_TESTING_cmd_check_bank_admin_transfer (
"clear-good-transfer-to-the-exchange",
"EUR:5",
- bc.user42_payto, // debit
- bc.exchange_payto, // credit
+ cred.user42_payto, // debit
+ cred.exchange_payto, // credit
"run-transfer-good-to-exchange"),
TALER_TESTING_cmd_exec_closer ("run-closer-non-expired-reserve",
@@ -135,17 +128,17 @@ run (void *cls,
CMD_EXEC_AGGREGATOR ("run-closer-on-expired-reserve"),
TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1",
- ec.exchange_url,
+ cred.exchange_url,
"EUR:4.99",
- bc.exchange_payto,
- bc.user42_payto),
+ cred.exchange_payto,
+ cred.user42_payto),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-2"),
TALER_TESTING_cmd_end ()
};
- TALER_TESTING_run_with_fakebank (is,
- all,
- bc.exchange_auth.wire_gateway_url);
+ (void) cls;
+ TALER_TESTING_run (is,
+ all);
}
@@ -153,68 +146,29 @@ int
main (int argc,
char *const argv[])
{
- const char *plugin_name;
-
- /* these might get in the way */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test_taler_exchange_wirewatch",
- "DEBUG",
- NULL);
-
- if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
+ (void) argc;
{
- GNUNET_break (0);
- return -1;
- }
- plugin_name++;
- {
- char *testname;
-
- GNUNET_asprintf (&testname,
- "test-taler-exchange-wirewatch-%s",
- plugin_name);
+ const char *plugin_name;
+
+ plugin_name = strrchr (argv[0], (int) '-');
+ if (NULL == plugin_name)
+ {
+ GNUNET_break (0);
+ return -1;
+ }
+ plugin_name++;
GNUNET_asprintf (&config_filename,
- "%s.conf",
- testname);
- GNUNET_free (testname);
- }
- /* check database is working */
- {
- struct GNUNET_PQ_Context *conn;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- conn = GNUNET_PQ_connect ("postgres:///talercheck",
- NULL,
- es,
- NULL);
- if (NULL == conn)
- return 77;
- GNUNET_PQ_disconnect (conn);
- }
-
- TALER_TESTING_cleanup_files (config_filename);
- if (GNUNET_OK !=
- TALER_TESTING_prepare_exchange (config_filename,
- GNUNET_YES,
- &ec))
- {
- TALER_LOG_INFO ("Could not prepare the exchange\n");
- return 77;
+ "test-taler-exchange-wirewatch-%s.conf",
+ plugin_name);
}
-
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (config_filename,
- "exchange-account-1",
- &bc))
- return 77;
-
- return (GNUNET_OK ==
- TALER_TESTING_setup_with_exchange (&run,
- NULL,
- config_filename)) ? 0 : 1;
+ return TALER_TESTING_main (argv,
+ "INFO",
+ config_filename,
+ "exchange-account-1",
+ TALER_TESTING_BS_FAKEBANK,
+ &cred,
+ &run,
+ NULL);
}
diff --git a/src/testing/testing_api_cmd_age_withdraw.c b/src/testing/testing_api_cmd_age_withdraw.c
new file mode 100644
index 000000000..6ad22809e
--- /dev/null
+++ b/src/testing/testing_api_cmd_age_withdraw.c
@@ -0,0 +1,756 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_age_withdraw.c
+ * @brief implements the age-withdraw command
+ * @author Özgür Kesim
+ */
+
+#include "platform.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_common.h>
+#include <microhttpd.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_extensions.h"
+#include "taler_testing_lib.h"
+
+/*
+ * The output state of coin
+ */
+struct CoinOutputState
+{
+
+ /**
+ * The calculated details during "age-withdraw", for the selected coin.
+ */
+ struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails details;
+
+ /**
+ * The (wanted) value of the coin, MUST be the same as input.denom_pub.value;
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Reserve history entry that corresponds to this coin.
+ * Will be of type #TALER_EXCHANGE_RTT_AGEWITHDRAWAL.
+ */
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
+};
+
+/**
+ * State for a "age withdraw" CMD:
+ */
+
+struct AgeWithdrawState
+{
+
+ /**
+ * Interpreter state (during command)
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * The age-withdraw handle
+ */
+ struct TALER_EXCHANGE_AgeWithdrawHandle *handle;
+
+ /**
+ * Exchange base URL. Only used as offered trait.
+ */
+ char *exchange_url;
+
+ /**
+ * URI of the reserve we are withdrawing from.
+ */
+ char *reserve_payto_uri;
+
+ /**
+ * Private key of the reserve we are withdrawing from.
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Public key of the reserve we are withdrawing from.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Which reserve should we withdraw from?
+ */
+ const char *reserve_reference;
+
+ /**
+ * Expected HTTP response code to the request.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Age mask
+ */
+ struct TALER_AgeMask mask;
+
+ /**
+ * The maximum age we commit to
+ */
+ uint8_t max_age;
+
+ /**
+ * Number of coins to withdraw
+ */
+ size_t num_coins;
+
+ /**
+ * The @e num_coins input that is provided to the
+ * `TALER_EXCHANGE_age_withdraw` API.
+ * Each contains kappa secrets, from which we will have
+ * to disclose kappa-1 in a subsequent age-withdraw-reveal operation.
+ */
+ struct TALER_EXCHANGE_AgeWithdrawCoinInput *coin_inputs;
+
+ /**
+ * The output state of @e num_coins coins, calculated during the
+ * "age-withdraw" operation.
+ */
+ struct CoinOutputState *coin_outputs;
+
+ /**
+ * The index returned by the exchange for the "age-withdraw" operation,
+ * of the kappa coin candidates that we do not disclose and keep.
+ */
+ uint8_t noreveal_index;
+
+ /**
+ * The blinded hashes of the non-revealed (to keep) @e num_coins coins.
+ */
+ const struct TALER_BlindedCoinHashP *blinded_coin_hs;
+
+ /**
+ * The hash of the commitment, needed for the reveal step.
+ */
+ struct TALER_AgeWithdrawCommitmentHashP h_commitment;
+
+ /**
+ * Set to the KYC requirement payto hash *if* the exchange replied with a
+ * request for KYC.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC.
+ */
+ uint64_t requirement_row;
+
+};
+
+/**
+ * Callback for the "age-withdraw" ooperation; It checks that the response
+ * code is expected and store the exchange signature in the state.
+ *
+ * @param cls Closure of type `struct AgeWithdrawState *`
+ * @param response Response details
+ */
+static void
+age_withdraw_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_AgeWithdrawResponse *response)
+{
+ struct AgeWithdrawState *aws = cls;
+ struct TALER_TESTING_Interpreter *is = aws->is;
+
+ aws->handle = NULL;
+ if (aws->expected_response_code != response->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status_with_body (is,
+ response->hr.http_status,
+ aws->expected_response_code,
+ response->hr.reply);
+ return;
+ }
+
+ switch (response->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ aws->noreveal_index = response->details.ok.noreveal_index;
+ aws->h_commitment = response->details.ok.h_commitment;
+
+ GNUNET_assert (aws->num_coins == response->details.ok.num_coins);
+ for (size_t n = 0; n < aws->num_coins; n++)
+ {
+ aws->coin_outputs[n].details = response->details.ok.coin_details[n];
+ TALER_age_commitment_proof_deep_copy (
+ &response->details.ok.coin_details[n].age_commitment_proof,
+ &aws->coin_outputs[n].details.age_commitment_proof);
+ }
+ aws->blinded_coin_hs = response->details.ok.blinded_coin_hs;
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ case MHD_HTTP_NOT_FOUND:
+ case MHD_HTTP_GONE:
+ /* nothing to check */
+ break;
+ case MHD_HTTP_CONFLICT:
+ /* TODO[oec]: Add this to the response-type and handle it here */
+ break;
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ default:
+ /* Unsupported status code (by test harness) */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "test command for age-withdraw not support status code %u, body:\n"
+ ">>%s<<\n",
+ response->hr.http_status,
+ json_dumps (response->hr.reply, JSON_INDENT (2)));
+ GNUNET_break (0);
+ break;
+ }
+
+ /* We are done with this command, pick the next one */
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command for age-withdraw.
+ */
+static void
+age_withdraw_run (
+ void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AgeWithdrawState *aws = cls;
+ struct TALER_EXCHANGE_Keys *keys = TALER_TESTING_get_keys (is);
+ const struct TALER_ReservePrivateKeyP *rp;
+ const struct TALER_TESTING_Command *create_reserve;
+ const struct TALER_EXCHANGE_DenomPublicKey *dpk;
+
+ aws->is = is;
+
+ /* Prepare the reserve related data */
+ create_reserve
+ = TALER_TESTING_interpreter_lookup_command (
+ is,
+ aws->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,
+ &rp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL == aws->exchange_url)
+ aws->exchange_url
+ = GNUNET_strdup (TALER_TESTING_get_exchange_url (is));
+ aws->reserve_priv = *rp;
+ GNUNET_CRYPTO_eddsa_key_get_public (&aws->reserve_priv.eddsa_priv,
+ &aws->reserve_pub.eddsa_pub);
+ aws->reserve_payto_uri
+ = TALER_reserve_make_payto (aws->exchange_url,
+ &aws->reserve_pub);
+
+ aws->coin_inputs = GNUNET_new_array (
+ aws->num_coins,
+ struct TALER_EXCHANGE_AgeWithdrawCoinInput);
+
+ for (unsigned int i = 0; i<aws->num_coins; i++)
+ {
+ struct TALER_EXCHANGE_AgeWithdrawCoinInput *input = &aws->coin_inputs[i];
+ struct CoinOutputState *cos = &aws->coin_outputs[i];
+
+ /* randomly create the secrets for the kappa coin-candidates */
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &input->secrets,
+ sizeof(input->secrets));
+ /* Find denomination */
+ dpk = TALER_TESTING_find_pk (keys,
+ &cos->amount,
+ true); /* _always_ use denominations with age-striction */
+ if (NULL == dpk)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to determine denomination key for amount at %s\n",
+ (NULL != cmd) ? cmd->label : "<retried command>");
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ /* We copy the denomination key, as re-querying /keys
+ * would free the old one. */
+ input->denom_pub = TALER_EXCHANGE_copy_denomination_key (dpk);
+ cos->reserve_history.type = TALER_EXCHANGE_RTT_AGEWITHDRAWAL;
+ GNUNET_assert (0 <=
+ TALER_amount_add (&cos->reserve_history.amount,
+ &cos->amount,
+ &input->denom_pub->fees.withdraw));
+ cos->reserve_history.details.withdraw.fee = input->denom_pub->fees.withdraw;
+ }
+
+ /* Execute the age-withdraw protocol */
+ aws->handle =
+ TALER_EXCHANGE_age_withdraw (
+ TALER_TESTING_interpreter_get_context (is),
+ keys,
+ TALER_TESTING_get_exchange_url (is),
+ rp,
+ aws->num_coins,
+ aws->coin_inputs,
+ aws->max_age,
+ &age_withdraw_cb,
+ aws);
+
+ if (NULL == aws->handle)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "age withdraw" CMD, and possibly cancel a
+ * pending operation thereof
+ *
+ * @param cls Closure of type `struct AgeWithdrawState`
+ * @param cmd The command being freed.
+ */
+static void
+age_withdraw_cleanup (
+ void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AgeWithdrawState *aws = cls;
+
+ if (NULL != aws->handle)
+ {
+ TALER_TESTING_command_incomplete (aws->is,
+ cmd->label);
+ TALER_EXCHANGE_age_withdraw_cancel (aws->handle);
+ aws->handle = NULL;
+ }
+
+ if (NULL != aws->coin_inputs)
+ {
+ for (size_t n = 0; n < aws->num_coins; n++)
+ {
+ struct TALER_EXCHANGE_AgeWithdrawCoinInput *in = &aws->coin_inputs[n];
+ struct CoinOutputState *out = &aws->coin_outputs[n];
+
+ if (NULL != in && NULL != in->denom_pub)
+ {
+ TALER_EXCHANGE_destroy_denomination_key (in->denom_pub);
+ in->denom_pub = NULL;
+ }
+ if (NULL != out)
+ TALER_age_commitment_proof_free (&out->details.age_commitment_proof);
+ }
+ GNUNET_free (aws->coin_inputs);
+ }
+ GNUNET_free (aws->coin_outputs);
+ GNUNET_free (aws->exchange_url);
+ GNUNET_free (aws->reserve_payto_uri);
+ GNUNET_free (aws);
+}
+
+
+/**
+ * Offer internal data of a "age withdraw" CMD state to other commands.
+ *
+ * @param cls Closure of type `struct AgeWithdrawState`
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param idx index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+age_withdraw_traits (
+ void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int idx)
+{
+ struct AgeWithdrawState *aws = cls;
+ uint8_t k = aws->noreveal_index;
+ struct TALER_EXCHANGE_AgeWithdrawCoinInput *in = &aws->coin_inputs[idx];
+ struct CoinOutputState *out = &aws->coin_outputs[idx];
+ struct TALER_EXCHANGE_AgeWithdrawCoinPrivateDetails *details =
+ &aws->coin_outputs[idx].details;
+ struct TALER_TESTING_Trait traits[] = {
+ /* history entry MUST be first due to response code logic below! */
+ TALER_TESTING_make_trait_reserve_history (idx,
+ &out->reserve_history),
+ TALER_TESTING_make_trait_denom_pub (idx,
+ in->denom_pub),
+ TALER_TESTING_make_trait_reserve_priv (&aws->reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (&aws->reserve_pub),
+ TALER_TESTING_make_trait_amounts (idx,
+ &out->amount),
+ /* TODO[oec]: add legal requirement to response and handle it here, as well
+ TALER_TESTING_make_trait_legi_requirement_row (&aws->requirement_row),
+ TALER_TESTING_make_trait_h_payto (&aws->h_payto),
+ */
+ TALER_TESTING_make_trait_h_blinded_coin (idx,
+ &aws->blinded_coin_hs[idx]),
+ TALER_TESTING_make_trait_payto_uri (aws->reserve_payto_uri),
+ TALER_TESTING_make_trait_exchange_url (aws->exchange_url),
+ TALER_TESTING_make_trait_coin_priv (idx,
+ &details->coin_priv),
+ TALER_TESTING_make_trait_planchet_secrets (idx,
+ &in->secrets[k]),
+ TALER_TESTING_make_trait_blinding_key (idx,
+ &details->blinding_key),
+ TALER_TESTING_make_trait_exchange_wd_value (idx,
+ &details->alg_values),
+ TALER_TESTING_make_trait_age_commitment_proof (
+ idx,
+ &details->age_commitment_proof),
+ TALER_TESTING_make_trait_h_age_commitment (
+ idx,
+ &details->h_age_commitment),
+ };
+
+ if (idx >= aws->num_coins)
+ return GNUNET_NO;
+
+ return TALER_TESTING_get_trait ((aws->expected_response_code == MHD_HTTP_OK)
+ ? &traits[0] /* we have reserve history */
+ : &traits[1], /* skip reserve history */
+ ret,
+ trait,
+ idx);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_age_withdraw (const char *label,
+ const char *reserve_reference,
+ uint8_t max_age,
+ unsigned int expected_response_code,
+ const char *amount,
+ ...)
+{
+ struct AgeWithdrawState *aws;
+ unsigned int cnt;
+ va_list ap;
+
+ aws = GNUNET_new (struct AgeWithdrawState);
+ aws->reserve_reference = reserve_reference;
+ aws->expected_response_code = expected_response_code;
+ aws->mask = TALER_extensions_get_age_restriction_mask ();
+ aws->max_age = TALER_get_lowest_age (&aws->mask, max_age);
+
+ cnt = 1;
+ va_start (ap, amount);
+ while (NULL != (va_arg (ap, const char *)))
+ cnt++;
+ aws->num_coins = cnt;
+ aws->coin_outputs = GNUNET_new_array (cnt,
+ struct CoinOutputState);
+ va_end (ap);
+ va_start (ap, amount);
+
+ for (unsigned int i = 0; i<aws->num_coins; i++)
+ {
+ struct CoinOutputState *out = &aws->coin_outputs[i];
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &out->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %s\n",
+ amount,
+ label);
+ GNUNET_assert (0);
+ }
+ /* move on to next vararg! */
+ amount = va_arg (ap, const char *);
+ }
+
+ GNUNET_assert (NULL == amount);
+ va_end (ap);
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = aws,
+ .label = label,
+ .run = &age_withdraw_run,
+ .cleanup = &age_withdraw_cleanup,
+ .traits = &age_withdraw_traits,
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * The state for the age-withdraw-reveal operation
+ */
+struct AgeWithdrawRevealState
+{
+ /**
+ * The reference to the CMD resembling the previous call to age-withdraw
+ */
+ const char *age_withdraw_reference;
+
+ /**
+ * The state to the previous age-withdraw command
+ */
+ const struct AgeWithdrawState *aws;
+
+ /**
+ * The expected response code from the call to the
+ * age-withdraw-reveal operation
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state (during command)
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * The handle to the reveal-operation
+ */
+ struct TALER_EXCHANGE_AgeWithdrawRevealHandle *handle;
+
+
+ /**
+ * Number of coins, extracted form the age withdraw command
+ */
+ size_t num_coins;
+
+ /**
+ * The signatures of the @e num_coins coins returned
+ */
+ struct TALER_DenominationSignature *denom_sigs;
+
+};
+
+/*
+ * Callback for the reveal response
+ *
+ * @param cls Closure of type `struct AgeWithdrawRevealState`
+ * @param awr The response
+ */
+static void
+age_withdraw_reveal_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_AgeWithdrawRevealResponse *response)
+{
+ struct AgeWithdrawRevealState *awrs = cls;
+ struct TALER_TESTING_Interpreter *is = awrs->is;
+
+ awrs->handle = NULL;
+ if (awrs->expected_response_code != response->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status_with_body (is,
+ response->hr.http_status,
+ awrs->expected_response_code,
+ response->hr.reply);
+ return;
+ }
+ switch (response->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ {
+ const struct AgeWithdrawState *aws = awrs->aws;
+ GNUNET_assert (awrs->num_coins == response->details.ok.num_sigs);
+ awrs->denom_sigs = GNUNET_new_array (awrs->num_coins,
+ struct TALER_DenominationSignature);
+ for (size_t n = 0; n < awrs->num_coins; n++)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_denom_sig_unblind (
+ &awrs->denom_sigs[n],
+ &response->details.ok.blinded_denom_sigs[n],
+ &aws->coin_outputs[n].details.blinding_key,
+ &aws->coin_outputs[n].details.h_coin_pub,
+ &aws->coin_outputs[n].details.alg_values,
+ &aws->coin_inputs[n].denom_pub->key));
+ TALER_denom_sig_free (&awrs->denom_sigs[n]);
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "age-withdraw reveal success!\n");
+ GNUNET_free (awrs->denom_sigs);
+ }
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ case MHD_HTTP_FORBIDDEN:
+ /* nothing to check */
+ break;
+ /* TODO[oec]: handle more cases !? */
+ default:
+ /* Unsupported status code (by test harness) */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Age withdraw reveal test command does not support status code %u\n",
+ response->hr.http_status);
+ GNUNET_break (0);
+ break;
+ }
+
+ /* We are done with this command, pick the next one */
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command for age-withdraw-reveal
+ */
+static void
+age_withdraw_reveal_run (
+ void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AgeWithdrawRevealState *awrs = cls;
+ const struct TALER_TESTING_Command *age_withdraw_cmd;
+ const struct AgeWithdrawState *aws;
+
+ (void) cmd;
+ awrs->is = is;
+
+ /*
+ * Get the command and state for the previous call to "age witdraw"
+ */
+ age_withdraw_cmd =
+ TALER_TESTING_interpreter_lookup_command (is,
+ awrs->age_withdraw_reference);
+ if (NULL == age_withdraw_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (age_withdraw_cmd->run == age_withdraw_run);
+ aws = age_withdraw_cmd->cls;
+ awrs->aws = aws;
+ awrs->num_coins = aws->num_coins;
+
+ awrs->handle =
+ TALER_EXCHANGE_age_withdraw_reveal (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ aws->num_coins,
+ aws->coin_inputs,
+ aws->noreveal_index,
+ &aws->h_commitment,
+ &aws->reserve_pub,
+ age_withdraw_reveal_cb,
+ awrs);
+}
+
+
+/**
+ * Free the state of a "age-withdraw-reveal" CMD, and possibly
+ * cancel a pending operation thereof
+ *
+ * @param cls Closure of type `struct AgeWithdrawRevealState`
+ * @param cmd The command being freed.
+ */
+static void
+age_withdraw_reveal_cleanup (
+ void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AgeWithdrawRevealState *awrs = cls;
+
+ if (NULL != awrs->handle)
+ {
+ TALER_TESTING_command_incomplete (awrs->is,
+ cmd->label);
+ TALER_EXCHANGE_age_withdraw_reveal_cancel (awrs->handle);
+ awrs->handle = NULL;
+ }
+ GNUNET_free (awrs->denom_sigs);
+ awrs->denom_sigs = NULL;
+ GNUNET_free (awrs);
+}
+
+
+/**
+ * Offer internal data of a "age withdraw reveal" CMD state to other commands.
+ *
+ * @param cls Closure of they `struct AgeWithdrawRevealState`
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param idx index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+age_withdraw_reveal_traits (
+ void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int idx)
+{
+ struct AgeWithdrawRevealState *awrs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_denom_sig (idx,
+ &awrs->denom_sigs[idx]),
+ /* FIXME: shall we provide the traits from the previous
+ * call to "age withdraw" as well? */
+ };
+
+ if (idx >= awrs->num_coins)
+ return GNUNET_NO;
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ idx);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_age_withdraw_reveal (
+ const char *label,
+ const char *age_withdraw_reference,
+ unsigned int expected_response_code)
+{
+ struct AgeWithdrawRevealState *awrs =
+ GNUNET_new (struct AgeWithdrawRevealState);
+
+ awrs->age_withdraw_reference = age_withdraw_reference;
+ awrs->expected_response_code = expected_response_code;
+
+ struct TALER_TESTING_Command cmd = {
+ .cls = awrs,
+ .label = label,
+ .run = age_withdraw_reveal_run,
+ .cleanup = age_withdraw_reveal_cleanup,
+ .traits = age_withdraw_reveal_traits,
+ };
+
+ return cmd;
+}
+
+
+/* end of testing_api_cmd_age_withdraw.c */
diff --git a/src/testing/testing_api_cmd_auditor_add.c b/src/testing/testing_api_cmd_auditor_add.c
index 2c59f4194..ac9c2c8fb 100644
--- a/src/testing/testing_api_cmd_auditor_add.c
+++ b/src/testing/testing_api_cmd_auditor_add.c
@@ -18,7 +18,7 @@
*/
/**
* @file testing/testing_api_cmd_auditor_add.c
- * @brief command for testing /auditor_add.
+ * @brief command for testing auditor_add
* @author Christian Grothoff
*/
#include "platform.h"
@@ -62,27 +62,22 @@ struct AuditorAddState
* if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
+ * @param aer response details
*/
static void
-auditor_add_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+auditor_add_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_ManagementAuditorEnableResponse *aer)
{
struct AuditorAddState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &aer->hr;
ds->dh = NULL;
if (ds->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ds->is);
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ ds->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (ds->is);
@@ -102,13 +97,45 @@ auditor_add_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct AuditorAddState *ds = cls;
- struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp now;
struct TALER_MasterSignatureP master_sig;
+ const struct TALER_AuditorPublicKeyP *auditor_pub;
+ const struct TALER_TESTING_Command *auditor_cmd;
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const char *exchange_url;
+ const char *auditor_url;
(void) cmd;
- now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
+ now = GNUNET_TIME_timestamp_get ();
ds->is = is;
+
+ auditor_cmd = TALER_TESTING_interpreter_get_command (is,
+ "auditor");
+ if (NULL == auditor_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_auditor_pub (auditor_cmd,
+ &auditor_pub));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_auditor_url (auditor_cmd,
+ &auditor_url));
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+
+
if (ds->bad_sig)
{
memset (&master_sig,
@@ -117,17 +144,22 @@ auditor_add_run (void *cls,
}
else
{
- TALER_exchange_offline_auditor_add_sign (&is->auditor_pub,
- is->auditor_url,
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
+ TALER_exchange_offline_auditor_add_sign (auditor_pub,
+ auditor_url,
now,
- &is->master_priv,
+ master_priv,
&master_sig);
}
ds->dh = TALER_EXCHANGE_management_enable_auditor (
- is->ctx,
- is->exchange_url,
- &is->auditor_pub,
- is->auditor_url,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ auditor_pub,
+ auditor_url,
"test-case auditor", /* human-readable auditor name */
now,
&master_sig,
@@ -157,10 +189,8 @@ auditor_add_cleanup (void *cls,
if (NULL != ds->dh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ds->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
TALER_EXCHANGE_management_enable_auditor_cancel (ds->dh);
ds->dh = NULL;
}
@@ -168,26 +198,6 @@ auditor_add_cleanup (void *cls,
}
-/**
- * Offer internal data from a "auditor_add" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-auditor_add_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- return GNUNET_NO;
-}
-
-
struct TALER_TESTING_Command
TALER_TESTING_cmd_auditor_add (const char *label,
unsigned int expected_http_status,
@@ -203,8 +213,7 @@ TALER_TESTING_cmd_auditor_add (const char *label,
.cls = ds,
.label = label,
.run = &auditor_add_run,
- .cleanup = &auditor_add_cleanup,
- .traits = &auditor_add_traits
+ .cleanup = &auditor_add_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_auditor_add_denom_sig.c b/src/testing/testing_api_cmd_auditor_add_denom_sig.c
index efa4a9d76..6b7776896 100644
--- a/src/testing/testing_api_cmd_auditor_add_denom_sig.c
+++ b/src/testing/testing_api_cmd_auditor_add_denom_sig.c
@@ -67,27 +67,22 @@ struct AuditorAddDenomSigState
* if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
+ * @param adr response details
*/
static void
-denom_sig_add_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+denom_sig_add_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_AuditorAddDenominationResponse *adr)
{
struct AuditorAddDenomSigState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr;
ds->dh = NULL;
if (ds->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ds->is);
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ ds->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (ds->is);
@@ -108,8 +103,13 @@ auditor_add_run (void *cls,
{
struct AuditorAddDenomSigState *ds = cls;
struct TALER_AuditorSignatureP auditor_sig;
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_DenominationHashP h_denom_pub;
const struct TALER_EXCHANGE_DenomPublicKey *dk;
+ const struct TALER_AuditorPublicKeyP *auditor_pub;
+ const struct TALER_TESTING_Command *auditor_cmd;
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const char *exchange_url;
+ const char *auditor_url;
(void) cmd;
/* Get denom pub from trait */
@@ -118,7 +118,6 @@ auditor_add_run (void *cls,
denom_cmd = TALER_TESTING_interpreter_lookup_command (is,
ds->denom_ref);
-
if (NULL == denom_cmd)
{
GNUNET_break (0);
@@ -131,6 +130,31 @@ auditor_add_run (void *cls,
&dk));
}
ds->is = is;
+ auditor_cmd = TALER_TESTING_interpreter_get_command (is,
+ "auditor");
+ if (NULL == auditor_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_auditor_pub (auditor_cmd,
+ &auditor_pub));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_auditor_url (auditor_cmd,
+ &auditor_url));
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
if (ds->bad_sig)
{
memset (&auditor_sig,
@@ -139,31 +163,33 @@ auditor_add_run (void *cls,
}
else
{
- struct TALER_MasterPublicKeyP master_pub;
+ const struct TALER_MasterPublicKeyP *master_pub;
+ const struct TALER_AuditorPrivateKeyP *auditor_priv;
- GNUNET_CRYPTO_eddsa_key_get_public (&is->master_priv.eddsa_priv,
- &master_pub.eddsa_pub);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_pub (exchange_cmd,
+ &master_pub));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_auditor_priv (auditor_cmd,
+ &auditor_priv));
TALER_auditor_denom_validity_sign (
- is->auditor_url,
+ auditor_url,
&dk->h_key,
- &master_pub,
+ master_pub,
dk->valid_from,
dk->withdraw_valid_until,
dk->expire_deposit,
dk->expire_legal,
&dk->value,
- &dk->fee_withdraw,
- &dk->fee_deposit,
- &dk->fee_refresh,
- &dk->fee_refund,
- &is->auditor_priv,
+ &dk->fees,
+ auditor_priv,
&auditor_sig);
}
ds->dh = TALER_EXCHANGE_add_auditor_denomination (
- is->ctx,
- is->exchange_url,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
&h_denom_pub,
- &is->auditor_pub,
+ auditor_pub,
&auditor_sig,
&denom_sig_add_cb,
ds);
@@ -191,10 +217,8 @@ auditor_add_cleanup (void *cls,
if (NULL != ds->dh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ds->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
TALER_EXCHANGE_add_auditor_denomination_cancel (ds->dh);
ds->dh = NULL;
}
@@ -202,26 +226,6 @@ auditor_add_cleanup (void *cls,
}
-/**
- * Offer internal data from a "auditor_add" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-auditor_add_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- return GNUNET_NO;
-}
-
-
struct TALER_TESTING_Command
TALER_TESTING_cmd_auditor_add_denom_sig (const char *label,
unsigned int expected_http_status,
@@ -239,8 +243,7 @@ TALER_TESTING_cmd_auditor_add_denom_sig (const char *label,
.cls = ds,
.label = label,
.run = &auditor_add_run,
- .cleanup = &auditor_add_cleanup,
- .traits = &auditor_add_traits
+ .cleanup = &auditor_add_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_auditor_del.c b/src/testing/testing_api_cmd_auditor_del.c
index 71525a10e..8256bc1c7 100644
--- a/src/testing/testing_api_cmd_auditor_del.c
+++ b/src/testing/testing_api_cmd_auditor_del.c
@@ -62,27 +62,23 @@ struct AuditorDelState
* if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
+ * @param adr response details
*/
static void
-auditor_del_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+auditor_del_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_ManagementAuditorDisableResponse *adr)
+
{
struct AuditorDelState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr;
ds->dh = NULL;
if (ds->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ds->is);
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ ds->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (ds->is);
@@ -103,12 +99,37 @@ auditor_del_run (void *cls,
{
struct AuditorDelState *ds = cls;
struct TALER_MasterSignatureP master_sig;
- struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp now;
+ const struct TALER_AuditorPublicKeyP *auditor_pub;
+ const struct TALER_TESTING_Command *auditor_cmd;
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const char *exchange_url;
(void) cmd;
- now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
+ now = GNUNET_TIME_timestamp_get ();
ds->is = is;
+ auditor_cmd = TALER_TESTING_interpreter_get_command (is,
+ "auditor");
+ if (NULL == auditor_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_auditor_pub (auditor_cmd,
+ &auditor_pub));
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
if (ds->bad_sig)
{
memset (&master_sig,
@@ -117,15 +138,20 @@ auditor_del_run (void *cls,
}
else
{
- TALER_exchange_offline_auditor_del_sign (&is->auditor_pub,
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
+ TALER_exchange_offline_auditor_del_sign (auditor_pub,
now,
- &is->master_priv,
+ master_priv,
&master_sig);
}
ds->dh = TALER_EXCHANGE_management_disable_auditor (
- is->ctx,
- is->exchange_url,
- &is->auditor_pub,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ auditor_pub,
now,
&master_sig,
&auditor_del_cb,
@@ -154,10 +180,8 @@ auditor_del_cleanup (void *cls,
if (NULL != ds->dh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ds->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
TALER_EXCHANGE_management_disable_auditor_cancel (ds->dh);
ds->dh = NULL;
}
@@ -165,26 +189,6 @@ auditor_del_cleanup (void *cls,
}
-/**
- * Offer internal data from a "auditor_del" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-auditor_del_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- return GNUNET_NO;
-}
-
-
struct TALER_TESTING_Command
TALER_TESTING_cmd_auditor_del (const char *label,
unsigned int expected_http_status,
@@ -200,8 +204,7 @@ TALER_TESTING_cmd_auditor_del (const char *label,
.cls = ds,
.label = label,
.run = &auditor_del_run,
- .cleanup = &auditor_del_cleanup,
- .traits = &auditor_del_traits
+ .cleanup = &auditor_del_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
index f40d78c88..9477a5d7e 100644
--- a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
+++ b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
+ Copyright (C) 2018-2023 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
@@ -59,9 +59,9 @@ struct DepositConfirmationState
const char *amount_without_fee;
/**
- * Which coin of the @e deposit_reference should we confirm.
+ * How many coins were there in the @e deposit_reference?
*/
- unsigned int coin_index;
+ unsigned int num_coins;
/**
* DepositConfirmation handle while operation is running.
@@ -69,11 +69,6 @@ struct DepositConfirmationState
struct TALER_AUDITOR_DepositConfirmationHandle *dc;
/**
- * Auditor connection.
- */
- struct TALER_AUDITOR_Handle *auditor;
-
- /**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
@@ -125,8 +120,7 @@ do_retry (void *cls)
struct DepositConfirmationState *dcs = cls;
dcs->retry_task = NULL;
- dcs->is->commands[dcs->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (dcs->is);
deposit_confirmation_run (dcs,
NULL,
dcs->is);
@@ -138,13 +132,15 @@ do_retry (void *cls)
* to check if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
+ * @param dcr response details
*/
static void
-deposit_confirmation_cb (void *cls,
- const struct TALER_AUDITOR_HttpResponse *hr)
+deposit_confirmation_cb (
+ void *cls,
+ const struct TALER_AUDITOR_DepositConfirmationResponse *dcr)
{
struct DepositConfirmationState *dcs = cls;
+ const struct TALER_AUDITOR_HttpResponse *hr = &dcr->hr;
dcs->dc = NULL;
if (dcs->expected_response_code != hr->http_status)
@@ -166,21 +162,16 @@ deposit_confirmation_cb (void *cls,
else
dcs->backoff = GNUNET_TIME_randomized_backoff (dcs->backoff,
MAX_BACKOFF);
- dcs->is->commands[dcs->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (dcs->is);
dcs->retry_task = GNUNET_SCHEDULER_add_delayed (dcs->backoff,
&do_retry,
dcs);
return;
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- dcs->is->commands[dcs->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply, stderr, 0);
- TALER_TESTING_interpreter_fail (dcs->is);
+ TALER_TESTING_unexpected_status (dcs->is,
+ hr->http_status,
+ dcs->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (dcs->is);
@@ -199,28 +190,54 @@ deposit_confirmation_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
+ static struct TALER_ExtensionPolicyHashP no_h_policy;
struct DepositConfirmationState *dcs = cls;
const struct TALER_TESTING_Command *deposit_cmd;
- struct GNUNET_HashCode h_wire;
- struct GNUNET_HashCode h_contract_terms;
- const struct GNUNET_TIME_Absolute *exchange_timestamp = NULL;
- struct GNUNET_TIME_Absolute timestamp;
- struct GNUNET_TIME_Absolute refund_deadline;
+ struct TALER_MerchantWireHashP h_wire;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ const struct GNUNET_TIME_Timestamp *exchange_timestamp = NULL;
+ struct GNUNET_TIME_Timestamp timestamp;
+ const struct GNUNET_TIME_Timestamp *wire_deadline;
+ struct GNUNET_TIME_Timestamp refund_deadline
+ = GNUNET_TIME_UNIT_ZERO_TS;
struct TALER_Amount amount_without_fee;
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pubs[dcs->num_coins];
+ const struct TALER_CoinSpendPublicKeyP *coin_pubps[dcs->num_coins];
+ const struct TALER_CoinSpendSignatureP *coin_sigps[dcs->num_coins];
const struct TALER_MerchantPrivateKeyP *merchant_priv;
struct TALER_MerchantPublicKeyP merchant_pub;
const struct TALER_ExchangePublicKeyP *exchange_pub;
const struct TALER_ExchangeSignatureP *exchange_sig;
const json_t *wire_details;
const json_t *contract_terms;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
const struct TALER_EXCHANGE_Keys *keys;
const struct TALER_EXCHANGE_SigningPublicKey *spk;
+ const char *auditor_url;
(void) cmd;
dcs->is = is;
GNUNET_assert (NULL != dcs->deposit_reference);
+ {
+ const struct TALER_TESTING_Command *auditor_cmd;
+
+ auditor_cmd
+ = TALER_TESTING_interpreter_get_command (is,
+ "auditor");
+ if (NULL == auditor_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_auditor_url (auditor_cmd,
+ &auditor_url))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
deposit_cmd
= TALER_TESTING_interpreter_lookup_command (is,
dcs->deposit_reference);
@@ -233,25 +250,28 @@ deposit_confirmation_run (void *cls,
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_exchange_pub (deposit_cmd,
- dcs->coin_index,
+ 0,
&exchange_pub));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_exchange_sig (deposit_cmd,
- dcs->coin_index,
+ 0,
&exchange_sig));
GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_absolute_time (deposit_cmd,
- dcs->coin_index,
- &exchange_timestamp));
+ TALER_TESTING_get_trait_timestamp (deposit_cmd,
+ 0,
+ &exchange_timestamp));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_wire_deadline (deposit_cmd,
+ 0,
+ &wire_deadline));
GNUNET_assert (NULL != exchange_timestamp);
- keys = TALER_EXCHANGE_get_keys (dcs->is->exchange);
+ keys = TALER_TESTING_get_keys (is);
GNUNET_assert (NULL != keys);
spk = TALER_EXCHANGE_get_signing_key_info (keys,
exchange_pub);
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_contract_terms (deposit_cmd,
- dcs->coin_index,
&contract_terms));
/* Very unlikely to fail */
GNUNET_assert (NULL != contract_terms);
@@ -260,30 +280,44 @@ deposit_confirmation_run (void *cls,
&h_contract_terms));
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_wire_details (deposit_cmd,
- dcs->coin_index,
&wire_details));
GNUNET_assert (GNUNET_OK ==
TALER_JSON_merchant_wire_signature_hash (wire_details,
&h_wire));
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_coin_priv (deposit_cmd,
- dcs->coin_index,
- &coin_priv));
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
+
+ for (unsigned int i = 0; i<dcs->num_coins; i++)
+ {
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_coin_priv (deposit_cmd,
+ i,
+ &coin_priv));
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pubs[i].eddsa_pub);
+ coin_pubps[i] = &coin_pubs[i];
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_coin_sig (deposit_cmd,
+ i,
+ &coin_sigps[i]));
+ }
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_merchant_priv (deposit_cmd,
- dcs->coin_index,
&merchant_priv));
GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
&merchant_pub.eddsa_pub);
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (dcs->amount_without_fee,
&amount_without_fee));
- /* timestamp is mandatory */
{
struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_absolute_time ("timestamp", &timestamp),
+ /* timestamp is mandatory */
+ GNUNET_JSON_spec_timestamp ("timestamp",
+ &timestamp),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_timestamp ("refund_deadline",
+ &refund_deadline),
+ NULL),
GNUNET_JSON_spec_end ()
};
@@ -296,39 +330,32 @@ deposit_confirmation_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
- }
- /* refund deadline is optional, defaults to zero */
- {
- struct GNUNET_JSON_Specification spec[] = {
- TALER_JSON_spec_absolute_time ("refund_deadline", &refund_deadline),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (contract_terms,
- spec,
- NULL, NULL))
- {
+ if (GNUNET_TIME_absolute_is_zero (refund_deadline.abs_time))
refund_deadline = timestamp;
- }
}
- dcs->dc = TALER_AUDITOR_deposit_confirmation (dcs->auditor,
- &h_wire,
- &h_contract_terms,
- *exchange_timestamp,
- refund_deadline,
- &amount_without_fee,
- &coin_pub,
- &merchant_pub,
- exchange_pub,
- exchange_sig,
- &keys->master_pub,
- spk->valid_from,
- spk->valid_until,
- spk->valid_legal,
- &spk->master_sig,
- &deposit_confirmation_cb,
- dcs);
+ dcs->dc = TALER_AUDITOR_deposit_confirmation (
+ TALER_TESTING_interpreter_get_context (is),
+ auditor_url,
+ &h_wire,
+ &no_h_policy,
+ &h_contract_terms,
+ *exchange_timestamp,
+ *wire_deadline,
+ refund_deadline,
+ &amount_without_fee,
+ dcs->num_coins,
+ coin_pubps,
+ coin_sigps,
+ &merchant_pub,
+ exchange_pub,
+ exchange_sig,
+ &keys->master_pub,
+ spk->valid_from,
+ spk->valid_until,
+ spk->valid_legal,
+ &spk->master_sig,
+ &deposit_confirmation_cb,
+ dcs);
if (NULL == dcs->dc)
{
@@ -355,10 +382,8 @@ deposit_confirmation_cleanup (void *cls,
if (NULL != dcs->dc)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- dcs->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (dcs->is,
+ cmd->label);
TALER_AUDITOR_deposit_confirmation_cancel (dcs->dc);
dcs->dc = NULL;
}
@@ -371,61 +396,18 @@ deposit_confirmation_cleanup (void *cls,
}
-/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- *
- * @return #GNUNET_OK on success
- */
-static int
-deposit_confirmation_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- /* Must define this function because some callbacks
- * look for certain traits on _all_ the commands. */
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Create a "deposit-confirmation" command.
- *
- * @param label command label.
- * @param auditor auditor connection.
- * @param deposit_reference reference to any operation that can
- * provide a coin.
- * @param coin_index if @a deposit_reference offers an array of
- * coins, this parameter selects which one in that array.
- * This value is currently ignored, as only one-coin
- * deposits are implemented.
- * @param amount_without_fee deposited amount without the fee
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_deposit_confirmation (const char *label,
- struct TALER_AUDITOR_Handle *auditor,
const char *deposit_reference,
- unsigned int coin_index,
+ unsigned int num_coins,
const char *amount_without_fee,
unsigned int expected_response_code)
{
struct DepositConfirmationState *dcs;
dcs = GNUNET_new (struct DepositConfirmationState);
- dcs->auditor = auditor;
dcs->deposit_reference = deposit_reference;
- dcs->coin_index = coin_index;
+ dcs->num_coins = num_coins;
dcs->amount_without_fee = amount_without_fee;
dcs->expected_response_code = expected_response_code;
@@ -434,8 +416,7 @@ TALER_TESTING_cmd_deposit_confirmation (const char *label,
.cls = dcs,
.label = label,
.run = &deposit_confirmation_run,
- .cleanup = &deposit_confirmation_cleanup,
- .traits = &deposit_confirmation_traits
+ .cleanup = &deposit_confirmation_cleanup
};
return cmd;
@@ -443,13 +424,6 @@ TALER_TESTING_cmd_deposit_confirmation (const char *label,
}
-/**
- * Modify a deposit confirmation command to enable retries when we get
- * transient errors from the auditor.
- *
- * @param cmd a deposit confirmation command
- * @return the command with retries enabled
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_deposit_confirmation_with_retry (
struct TALER_TESTING_Command cmd)
diff --git a/src/testing/testing_api_cmd_auditor_exchanges.c b/src/testing/testing_api_cmd_auditor_exchanges.c
deleted file mode 100644
index 1e412b2d1..000000000
--- a/src/testing/testing_api_cmd_auditor_exchanges.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_auditor_exchanges.c
- * @brief command for testing /exchanges of the auditor
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_auditor_service.h"
-#include "taler_testing_lib.h"
-#include "taler_signatures.h"
-#include "backoff.h"
-
-/**
- * How long do we wait AT MOST when retrying?
- */
-#define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
- GNUNET_TIME_UNIT_MILLISECONDS, 100)
-
-
-/**
- * How often do we retry before giving up?
- */
-#define NUM_RETRIES 5
-
-
-/**
- * State for a "deposit confirmation" CMD.
- */
-struct ExchangesState
-{
-
- /**
- * Exchanges handle while operation is running.
- */
- struct TALER_AUDITOR_ListExchangesHandle *leh;
-
- /**
- * Auditor connection.
- */
- struct TALER_AUDITOR_Handle *auditor;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * URL of the exchange expected to be included in the response.
- */
- const char *exchange_url;
-
- /**
- * How often should we retry on (transient) failures?
- */
- unsigned int do_retry;
-
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-exchanges_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #exchanges_run.
- *
- * @param cls a `struct ExchangesState`
- */
-static void
-do_retry (void *cls)
-{
- struct ExchangesState *es = cls;
-
- es->retry_task = NULL;
- es->is->commands[es->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
- exchanges_run (es,
- NULL,
- es->is);
-}
-
-
-/**
- * Callback to analyze the /exchanges response.
- *
- * @param cls closure.
- * @param hr HTTP response details
- * @param num_exchanges length of the @a ei array
- * @param ei array with information about the exchanges
- */
-static void
-exchanges_cb (void *cls,
- const struct TALER_AUDITOR_HttpResponse *hr,
- unsigned int num_exchanges,
- const struct TALER_AUDITOR_ExchangeInfo *ei)
-{
- struct ExchangesState *es = cls;
-
- es->leh = NULL;
- if (es->expected_response_code != hr->http_status)
- {
- if (0 != es->do_retry)
- {
- es->do_retry--;
- if ( (0 == hr->http_status) ||
- (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying list exchanges failed with %u/%d\n",
- hr->http_status,
- (int) hr->ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
- es->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- es->backoff = GNUNET_TIME_randomized_backoff (es->backoff,
- MAX_BACKOFF);
- es->is->commands[es->is->ip].num_tries++;
- es->retry_task = GNUNET_SCHEDULER_add_delayed (es->backoff,
- &do_retry,
- es);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- es->is->commands[es->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (es->is);
- return;
- }
- if (NULL != es->exchange_url)
- {
- unsigned int found = GNUNET_NO;
-
- for (unsigned int i = 0;
- i<num_exchanges;
- i++)
- if (0 == strcmp (es->exchange_url,
- ei[i].exchange_url))
- found = GNUNET_YES;
- if (GNUNET_NO == found)
- {
- TALER_LOG_ERROR ("Exchange '%s' doesn't exist at this auditor\n",
- es->exchange_url);
- TALER_TESTING_interpreter_fail (es->is);
- return;
- }
-
- TALER_LOG_DEBUG ("Exchange '%s' exists at this auditor!\n",
- es->exchange_url);
- }
- TALER_TESTING_interpreter_next (es->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-exchanges_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct ExchangesState *es = cls;
-
- (void) cmd;
- es->is = is;
- es->leh = TALER_AUDITOR_list_exchanges
- (is->auditor,
- &exchanges_cb,
- es);
-
- if (NULL == es->leh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- return;
-}
-
-
-/**
- * Free the state of a "exchanges" CMD, and possibly cancel a
- * pending operation thereof.
- *
- * @param cls closure, a `struct ExchangesState`
- * @param cmd the command which is being cleaned up.
- */
-static void
-exchanges_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct ExchangesState *es = cls;
-
- if (NULL != es->leh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- es->is->ip,
- cmd->label);
- TALER_AUDITOR_list_exchanges_cancel (es->leh);
- es->leh = NULL;
- }
- if (NULL != es->retry_task)
- {
- GNUNET_SCHEDULER_cancel (es->retry_task);
- es->retry_task = NULL;
- }
- GNUNET_free (es);
-}
-
-
-/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- * @return #GNUNET_OK on success
- */
-static int
-exchanges_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- /* Must define this function because some callbacks
- * look for certain traits on _all_ the commands. */
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Create a "list exchanges" command.
- *
- * @param label command label.
- * @param auditor auditor connection.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exchanges (const char *label,
- struct TALER_AUDITOR_Handle *auditor,
- unsigned int expected_response_code)
-{
- struct ExchangesState *es;
-
- es = GNUNET_new (struct ExchangesState);
- es->auditor = auditor;
- es->expected_response_code = expected_response_code;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = es,
- .label = label,
- .run = &exchanges_run,
- .cleanup = &exchanges_cleanup,
- .traits = &exchanges_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Create a "list exchanges" command and check whether
- * a particular exchange belongs to the returned bundle.
- *
- * @param label command label.
- * @param expected_response_code expected HTTP response code.
- * @param exchange_url URL of the exchange supposed to
- * be included in the response.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exchanges_with_url (const char *label,
- unsigned int expected_response_code,
- const char *exchange_url)
-{
- struct ExchangesState *es;
-
- es = GNUNET_new (struct ExchangesState);
- es->expected_response_code = expected_response_code;
- es->exchange_url = exchange_url;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = es,
- .label = label,
- .run = &exchanges_run,
- .cleanup = &exchanges_cleanup,
- .traits = &exchanges_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify an exchanges command to enable retries when we get
- * transient errors from the auditor.
- *
- * @param cmd a deposit confirmation command
- * @return the command with retries enabled
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exchanges_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct ExchangesState *es;
-
- GNUNET_assert (&exchanges_run == cmd.run);
- es = cmd.cls;
- es->do_retry = NUM_RETRIES;
- return cmd;
-}
-
-
-/* end of testing_auditor_api_cmd_exchanges.c */
diff --git a/src/testing/testing_api_cmd_auditor_exec_auditor.c b/src/testing/testing_api_cmd_auditor_exec_auditor.c
index 06dfe91bf..588be43d8 100644
--- a/src/testing/testing_api_cmd_auditor_exec_auditor.c
+++ b/src/testing/testing_api_cmd_auditor_exec_auditor.c
@@ -68,6 +68,7 @@ auditor_run (void *cls,
"taler-auditor",
"taler-auditor",
"-c", ks->config_filename,
+ "-I",
NULL);
if (NULL == ks->auditor_proc)
{
@@ -115,7 +116,7 @@ auditor_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
auditor_traits (void *cls,
const void **ret,
const char *trait,
@@ -123,7 +124,7 @@ auditor_traits (void *cls,
{
struct AuditorState *ks = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &ks->auditor_proc),
+ TALER_TESTING_make_trait_process (&ks->auditor_proc),
TALER_TESTING_trait_end ()
};
@@ -134,13 +135,6 @@ auditor_traits (void *cls,
}
-/**
- * Make the "exec-auditor" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_exec_auditor (const char *label,
const char *config_filename)
diff --git a/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c b/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c
index c09ec2918..2ab5bda8b 100644
--- a/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c
+++ b/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c
@@ -124,7 +124,7 @@ auditor_dbinit_traits (void *cls,
{
struct AuditorDbinitState *ks = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &ks->auditor_dbinit_proc),
+ TALER_TESTING_make_trait_process (&ks->auditor_dbinit_proc),
TALER_TESTING_trait_end ()
};
@@ -135,13 +135,6 @@ auditor_dbinit_traits (void *cls,
}
-/**
- * Make the "exec-auditor-dbinit" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_exec_auditor_dbinit (const char *label,
const char *config_filename)
diff --git a/src/testing/testing_api_cmd_bank_admin_add_incoming.c b/src/testing/testing_api_cmd_bank_admin_add_incoming.c
index 28f907fda..5c031d0b3 100644
--- a/src/testing/testing_api_cmd_bank_admin_add_incoming.c
+++ b/src/testing/testing_api_cmd_bank_admin_add_incoming.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2021 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
@@ -107,7 +107,7 @@ struct AdminAddIncomingState
* the "sender_url" field is set to a 'const char *' and
* MUST NOT be free()'ed.
*/
- struct TALER_EXCHANGE_ReserveHistory reserve_history;
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
/**
* Set to the wire transfer's unique ID.
@@ -117,7 +117,7 @@ struct AdminAddIncomingState
/**
* Timestamp of the transaction (as returned from the bank).
*/
- struct GNUNET_TIME_Absolute timestamp;
+ struct GNUNET_TIME_Timestamp timestamp;
/**
* Merchant instance. Sometimes used to get the tip reserve
@@ -180,8 +180,7 @@ do_retry (void *cls)
struct AdminAddIncomingState *fts = cls;
fts->retry_task = NULL;
- fts->is->commands[fts->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (fts->is);
admin_add_incoming_run (fts,
NULL,
fts->is);
@@ -194,41 +193,54 @@ do_retry (void *cls)
* acceptable.
*
* @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
- * successful status request; 0 if the exchange's reply is
- * bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param serial_id unique ID of the wire transfer
- * @param timestamp time stamp of the transaction made.
- * @param json raw response
+ * @param air response details
*/
static void
confirmation_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t serial_id,
- struct GNUNET_TIME_Absolute timestamp,
- const json_t *json)
+ const struct TALER_BANK_AdminAddIncomingResponse *air)
{
struct AdminAddIncomingState *fts = cls;
struct TALER_TESTING_Interpreter *is = fts->is;
- (void) json;
- fts->reserve_history.details.in_details.timestamp = timestamp;
- fts->reserve_history.details.in_details.wire_reference = serial_id;
fts->aih = NULL;
- switch (http_status)
+ /**
+ * Test case not caring about the HTTP status code.
+ * That helps when Fakebank and Libeufin diverge in
+ * the response status code. An example is the
+ * /admin/add-incoming: libeufin return ALWAYS '200 OK'
+ * (see note below) whereas the Fakebank responds with
+ * '409 Conflict' upon a duplicate reserve public key.
+ *
+ * Note: this decision aims at avoiding to put Taler
+ * logic into the Sandbox; that's because banks DO allow
+ * their customers to wire the same subject multiple
+ * times. Hence, instead of triggering any error, libeufin
+ * bounces the payment back in the same way it does for
+ * malformed reserve public keys.
+ */
+ if (-1 == (int) fts->expected_http_status)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ if (air->http_status != fts->expected_http_status)
+ {
+ TALER_TESTING_unexpected_status (is,
+ air->http_status,
+ fts->expected_http_status);
+ return;
+ }
+ switch (air->http_status)
{
case MHD_HTTP_OK:
- if (fts->expected_http_status !=
- MHD_HTTP_OK)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- fts->serial_id = serial_id;
- fts->timestamp = timestamp;
+ fts->reserve_history.details.in_details.timestamp
+ = air->details.ok.timestamp;
+ fts->reserve_history.details.in_details.wire_reference
+ = air->details.ok.serial_id;
+ fts->serial_id
+ = air->details.ok.serial_id;
+ fts->timestamp
+ = air->details.ok.timestamp;
TALER_TESTING_interpreter_next (is);
return;
case MHD_HTTP_UNAUTHORIZED:
@@ -246,35 +258,28 @@ confirmation_cb (void *cls,
}
break;
case MHD_HTTP_CONFLICT:
- if (fts->expected_http_status !=
- MHD_HTTP_CONFLICT)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
TALER_TESTING_interpreter_next (is);
return;
default:
if (0 != fts->do_retry)
{
fts->do_retry--;
- if ( (0 == http_status) ||
- (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ if ( (0 == air->http_status) ||
+ (TALER_EC_GENERIC_DB_SOFT_FAILURE == air->ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == air->http_status) )
{
GNUNET_log (
GNUNET_ERROR_TYPE_INFO,
"Retrying fakebank transfer failed with %u/%d\n",
- http_status,
- (int) ec);
+ air->http_status,
+ (int) air->ec);
/* on DB conflicts, do not use backoff */
- if (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec)
+ if (TALER_EC_GENERIC_DB_SOFT_FAILURE == air->ec)
fts->backoff = GNUNET_TIME_UNIT_ZERO;
else
fts->backoff = GNUNET_TIME_randomized_backoff (fts->backoff,
MAX_BACKOFF);
- fts->is->commands[fts->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (fts->is);
fts->retry_task = GNUNET_SCHEDULER_add_delayed (
fts->backoff,
&do_retry,
@@ -287,8 +292,8 @@ confirmation_cb (void *cls,
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Fakebank returned HTTP status %u/%d\n",
- http_status,
- (int) ec);
+ air->http_status,
+ (int) air->ec);
TALER_TESTING_interpreter_fail (is);
}
@@ -309,6 +314,7 @@ admin_add_incoming_run (void *cls,
bool have_public = false;
(void) cmd;
+ fts->is = is;
/* Use reserve public key as subject */
if (NULL != fts->reserve_reference)
{
@@ -326,11 +332,9 @@ admin_add_incoming_run (void *cls,
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_priv (ref,
- 0,
&reserve_priv))
{
if (GNUNET_OK != TALER_TESTING_get_trait_reserve_pub (ref,
- 0,
&reserve_pub))
{
GNUNET_break (0);
@@ -361,7 +365,6 @@ admin_add_incoming_run (void *cls,
fts->reserve_history.amount = fts->amount;
fts->reserve_history.details.in_details.sender_url
= (char *) fts->payto_debit_account; /* remember to NOT free this one... */
- fts->is = is;
fts->aih
= TALER_BANK_admin_add_incoming (
TALER_TESTING_interpreter_get_context (is),
@@ -395,9 +398,8 @@ admin_add_incoming_cleanup (void *cls,
if (NULL != fts->aih)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %s did not complete\n",
- cmd->label);
+ TALER_TESTING_command_incomplete (fts->is,
+ cmd->label);
TALER_BANK_admin_add_incoming_cancel (fts->aih);
fts->aih = NULL;
}
@@ -420,13 +422,14 @@ admin_add_incoming_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
admin_add_incoming_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct AdminAddIncomingState *fts = cls;
+ static const char *void_uri = "payto://void/the-exchange";
if (MHD_HTTP_OK !=
fts->expected_http_status)
@@ -435,19 +438,17 @@ admin_add_incoming_traits (void *cls,
{
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_bank_row (&fts->serial_id),
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
- fts->payto_debit_account),
+ TALER_TESTING_make_trait_debit_payto_uri (fts->payto_debit_account),
+ TALER_TESTING_make_trait_payto_uri (fts->payto_debit_account),
/* Used as a marker, content does not matter */
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
- "payto://void/the-exchange"),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
- fts->exchange_credit_url),
- TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
- TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
- TALER_TESTING_make_trait_reserve_priv (0,
- &fts->reserve_priv),
- TALER_TESTING_make_trait_reserve_pub (0,
- &fts->reserve_pub),
+ TALER_TESTING_make_trait_credit_payto_uri (void_uri),
+ TALER_TESTING_make_trait_exchange_bank_account_url (
+ fts->exchange_credit_url),
+ TALER_TESTING_make_trait_amount (&fts->amount),
+ TALER_TESTING_make_trait_timestamp (0,
+ &fts->timestamp),
+ TALER_TESTING_make_trait_reserve_priv (&fts->reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (&fts->reserve_pub),
TALER_TESTING_make_trait_reserve_history (0,
&fts->reserve_history),
TALER_TESTING_trait_end ()
@@ -462,17 +463,15 @@ admin_add_incoming_traits (void *cls,
{
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_bank_row (&fts->serial_id),
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
- fts->payto_debit_account),
+ TALER_TESTING_make_trait_debit_payto_uri (fts->payto_debit_account),
/* Used as a marker, content does not matter */
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
- "payto://void/the-exchange"),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
- fts->exchange_credit_url),
- TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
- TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
- TALER_TESTING_make_trait_reserve_pub (0,
- &fts->reserve_pub),
+ TALER_TESTING_make_trait_credit_payto_uri (void_uri),
+ TALER_TESTING_make_trait_exchange_bank_account_url (
+ fts->exchange_credit_url),
+ TALER_TESTING_make_trait_amount (&fts->amount),
+ TALER_TESTING_make_trait_timestamp (0,
+ &fts->timestamp),
+ TALER_TESTING_make_trait_reserve_pub (&fts->reserve_pub),
TALER_TESTING_make_trait_reserve_history (0,
&fts->reserve_history),
TALER_TESTING_trait_end ()
@@ -543,11 +542,11 @@ make_command (const char *label,
struct TALER_TESTING_Command
-TALER_TESTING_cmd_admin_add_incoming (const char *label,
- const char *amount,
- const struct
- TALER_BANK_AuthenticationData *auth,
- const char *payto_debit_account)
+TALER_TESTING_cmd_admin_add_incoming (
+ const char *label,
+ const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account)
{
return make_command (label,
make_fts (amount,
diff --git a/src/testing/testing_api_cmd_bank_admin_check.c b/src/testing/testing_api_cmd_bank_admin_check.c
index 473f3f3f2..6406fe2c2 100644
--- a/src/testing/testing_api_cmd_bank_admin_check.c
+++ b/src/testing/testing_api_cmd_bank_admin_check.c
@@ -82,8 +82,30 @@ check_bank_admin_transfer_run (void *cls,
const char *credit_payto;
const struct TALER_ReservePublicKeyP *reserve_pub;
const struct TALER_TESTING_Command *cmd_ref;
+ struct TALER_FAKEBANK_Handle *fakebank;
(void) cmd;
+ {
+ const struct TALER_TESTING_Command *fakebank_cmd;
+
+ fakebank_cmd
+ = TALER_TESTING_interpreter_get_command (is,
+ "fakebank");
+ if (NULL == fakebank_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_fakebank (fakebank_cmd,
+ &fakebank))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
cmd_ref
= TALER_TESTING_interpreter_lookup_command (is,
bcs->reserve_pub_ref);
@@ -95,7 +117,6 @@ check_bank_admin_transfer_run (void *cls,
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_pub (cmd_ref,
- 0,
&reserve_pub))
{
GNUNET_break (0);
@@ -103,7 +124,6 @@ check_bank_admin_transfer_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
- TALER_LOG_INFO ("Deposit reference NOT given\n");
debit_payto = bcs->debit_payto;
credit_payto = bcs->credit_payto;
if (GNUNET_OK !=
@@ -111,9 +131,9 @@ check_bank_admin_transfer_run (void *cls,
&amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
+ "Failed to parse amount `%s' at %s\n",
bcs->amount,
- is->ip);
+ TALER_TESTING_interpreter_get_current_label (is));
TALER_TESTING_interpreter_fail (is);
return;
}
@@ -124,7 +144,7 @@ check_bank_admin_transfer_run (void *cls,
debit_payto,
debit_account);
if (GNUNET_OK !=
- TALER_FAKEBANK_check_credit (is->fakebank,
+ TALER_FAKEBANK_check_credit (fakebank,
&amount,
debit_account,
credit_account,
@@ -160,33 +180,6 @@ check_bank_admin_transfer_cleanup (void *cls,
/**
- * Offer internal data from a "bank admin check" CMD state.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-check_bank_admin_transfer_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_trait_end ()
- };
-
- (void) cls;
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
* Make a "bank check" CMD. It checks whether a particular wire transfer to
* the exchange (credit) has been made or not.
*
@@ -217,8 +210,7 @@ TALER_TESTING_cmd_check_bank_admin_transfer
.label = label,
.cls = bcs,
.run = &check_bank_admin_transfer_run,
- .cleanup = &check_bank_admin_transfer_cleanup,
- .traits = &check_bank_admin_transfer_traits
+ .cleanup = &check_bank_admin_transfer_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_bank_check.c b/src/testing/testing_api_cmd_bank_check.c
index c01bc709f..77d120e09 100644
--- a/src/testing/testing_api_cmd_bank_check.c
+++ b/src/testing/testing_api_cmd_bank_check.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2022 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
@@ -74,6 +74,7 @@ struct BankCheckState
const char *deposit_reference;
};
+
/**
* Run the command.
*
@@ -93,8 +94,30 @@ check_bank_transfer_run (void *cls,
const char *exchange_base_url;
const char *debit_payto;
const char *credit_payto;
+ struct TALER_FAKEBANK_Handle *fakebank;
(void) cmd;
+ {
+ const struct TALER_TESTING_Command *fakebank_cmd;
+
+ fakebank_cmd
+ = TALER_TESTING_interpreter_get_command (is,
+ "fakebank");
+ if (NULL == fakebank_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_fakebank (fakebank_cmd,
+ &fakebank))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
if (NULL == bcs->deposit_reference)
{
TALER_LOG_INFO ("Deposit reference NOT given\n");
@@ -107,9 +130,9 @@ check_bank_transfer_run (void *cls,
&amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
+ "Failed to parse amount `%s' at %s\n",
bcs->amount,
- is->ip);
+ TALER_TESTING_interpreter_get_current_label (is));
TALER_TESTING_interpreter_fail (is);
return;
}
@@ -130,41 +153,32 @@ check_bank_transfer_run (void *cls,
if (NULL == deposit_cmd)
TALER_TESTING_FAIL (is);
if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (deposit_cmd,
- 0,
- &amount_ptr)) ||
+ TALER_TESTING_get_trait_amount (deposit_cmd,
+ &amount_ptr)) ||
(GNUNET_OK !=
- TALER_TESTING_get_trait_payto (deposit_cmd,
- TALER_TESTING_PT_DEBIT,
- &debit_payto)) ||
+ TALER_TESTING_get_trait_debit_payto_uri (deposit_cmd,
+ &debit_payto)) ||
(GNUNET_OK !=
- TALER_TESTING_get_trait_payto (deposit_cmd,
- TALER_TESTING_PT_CREDIT,
- &credit_payto)) ||
+ TALER_TESTING_get_trait_credit_payto_uri (deposit_cmd,
+ &credit_payto)) ||
(GNUNET_OK !=
- TALER_TESTING_get_trait_url (deposit_cmd,
- TALER_TESTING_UT_EXCHANGE_BASE_URL,
- &exchange_base_url)) )
+ TALER_TESTING_get_trait_exchange_url (deposit_cmd,
+ &exchange_base_url)) )
TALER_TESTING_FAIL (is);
amount = *amount_ptr;
}
-
-
debit_account = TALER_xtalerbank_account_from_payto (debit_payto);
credit_account = TALER_xtalerbank_account_from_payto (credit_payto);
-
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"converted debit_payto (%s) to debit_account (%s)\n",
debit_payto,
debit_account);
-
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"converted credit_payto (%s) to credit_account (%s)\n",
credit_payto,
credit_account);
-
if (GNUNET_OK !=
- TALER_FAKEBANK_check_debit (is->fakebank,
+ TALER_FAKEBANK_check_debit (fakebank,
&amount,
debit_account,
credit_account,
@@ -209,7 +223,7 @@ check_bank_transfer_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
check_bank_transfer_traits (void *cls,
const void **ret,
const char *trait,
@@ -218,10 +232,9 @@ check_bank_transfer_traits (void *cls,
struct BankCheckState *bcs = cls;
struct TALER_WireTransferIdentifierRawP *wtid_ptr = &bcs->wtid;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_wtid (0,
- wtid_ptr),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- bcs->exchange_base_url),
+ TALER_TESTING_make_trait_wtid (wtid_ptr),
+ TALER_TESTING_make_trait_exchange_url (
+ bcs->exchange_base_url),
TALER_TESTING_trait_end ()
};
@@ -232,19 +245,6 @@ check_bank_transfer_traits (void *cls,
}
-/**
- * Make a "bank check" CMD. It checks whether a
- * particular wire transfer has been made or not.
- *
- * @param label the command label.
- * @param exchange_base_url base url of the exchange involved in
- * the wire transfer.
- * @param amount the amount expected to be transferred.
- * @param debit_payto the account that gave money.
- * @param credit_payto the account that received money.
- *
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_check_bank_transfer (const char *label,
const char *exchange_base_url,
@@ -274,19 +274,9 @@ TALER_TESTING_cmd_check_bank_transfer (const char *label,
}
-/**
- * Define a "bank check" CMD that takes the input
- * data from another CMD that offers it.
- *
- * @param label command label.
- * @param deposit_reference reference to a CMD that is
- * able to provide the "check bank transfer" operation
- * input data.
- * @return the command.
- */
struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_bank_transfer_with_ref
- (const char *label,
+TALER_TESTING_cmd_check_bank_transfer_with_ref (
+ const char *label,
const char *deposit_reference)
{
struct BankCheckState *bcs;
diff --git a/src/testing/testing_api_cmd_bank_check_empty.c b/src/testing/testing_api_cmd_bank_check_empty.c
index 84976b0b5..60f00fbb4 100644
--- a/src/testing/testing_api_cmd_bank_check_empty.c
+++ b/src/testing/testing_api_cmd_bank_check_empty.c
@@ -58,9 +58,33 @@ check_bank_empty_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
+ struct TALER_FAKEBANK_Handle *fakebank;
+
(void) cls;
(void) cmd;
- if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank))
+ {
+ const struct TALER_TESTING_Command *fakebank_cmd;
+
+ fakebank_cmd
+ = TALER_TESTING_interpreter_get_command (is,
+ "fakebank");
+ if (NULL == fakebank_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_fakebank (fakebank_cmd,
+ &fakebank))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ if (GNUNET_OK !=
+ TALER_FAKEBANK_check_empty (fakebank))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
diff --git a/src/testing/testing_api_cmd_bank_history_credit.c b/src/testing/testing_api_cmd_bank_history_credit.c
index c052b55fb..956e6c857 100644
--- a/src/testing/testing_api_cmd_bank_history_credit.c
+++ b/src/testing/testing_api_cmd_bank_history_credit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2021 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
@@ -83,6 +83,11 @@ struct HistoryState
struct TALER_BANK_CreditHistoryHandle *hh;
/**
+ * The interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
* Authentication data for the operation.
*/
struct TALER_BANK_AuthenticationData auth;
@@ -93,10 +98,10 @@ struct HistoryState
uint64_t results_obtained;
/**
- * Set to GNUNET_YES if the callback detects something
+ * Set to true if the callback detects something
* unexpected.
*/
- int failed;
+ bool failed;
/**
* Expected history.
@@ -112,32 +117,6 @@ struct HistoryState
/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- *
- * @return #GNUNET_OK on success
- */
-static int
-history_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- /* Must define this function because some callbacks
- * look for certain traits on _all_ the commands. */
- return GNUNET_SYSERR;
-}
-
-
-/**
* Log which history we expected. Called when an error occurs.
*
* @param h what we expected.
@@ -170,38 +149,161 @@ print_expected (struct History *h,
/**
+ * Closure for command_cb().
+ */
+struct IteratorContext
+{
+ /**
+ * Array of history items to return.
+ */
+ struct History *h;
+
+ /**
+ * Set to the row ID from where on we should actually process history items,
+ * or NULL if we should process all of them.
+ */
+ const uint64_t *row_id_start;
+
+ /**
+ * History state we are working on.
+ */
+ struct HistoryState *hs;
+
+ /**
+ * Current length of the @e h array.
+ */
+ unsigned int total;
+
+ /**
+ * Current write position in @e h array.
+ */
+ unsigned int pos;
+
+ /**
+ * Ok equals True whenever a starting row_id was provided AND was found
+ * among the CMDs, OR no starting row was given in the first place.
+ */
+ bool ok;
+
+};
+
+
+/**
+ * Helper function of build_history() that expands
+ * the history for each relevant command encountered.
+ *
+ * @param[in,out] cls our `struct IteratorContext`
+ * @param cmd a command to process
+ */
+static void
+command_cb (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct IteratorContext *ic = cls;
+ struct HistoryState *hs = ic->hs;
+ const uint64_t *row_id;
+ const char *credit_account;
+ const char *debit_account;
+ const struct TALER_Amount *amount;
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+ const char *exchange_credit_url;
+
+ /**
+ * The following command allows us to skip over those CMDs
+ * that do not offer a "row_id" trait. Such skipped CMDs are
+ * not interesting for building a history.
+ */
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_bank_row (cmd,
+ &row_id)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_credit_payto_uri (cmd,
+ &credit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_debit_payto_uri (cmd,
+ &debit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount (cmd,
+ &amount)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (cmd,
+ &reserve_pub)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_exchange_bank_account_url (
+ cmd,
+ &exchange_credit_url)) )
+ return; // Not an interesting event
+
+ /**
+ * Is the interesting event a match with regard to
+ * the row_id value? If yes, store this condition
+ * to the state and analyze the next CMDs.
+ */
+ if ( (NULL != ic->row_id_start) &&
+ (*(ic->row_id_start) == *row_id) &&
+ (! ic->ok) )
+ {
+ ic->ok = true;
+ return;
+ }
+ /**
+ * The interesting event didn't match the wanted
+ * row_id value, analyze the next CMDs. Note: this
+ * branch is relevant only when row_id WAS given.
+ */
+ if (! ic->ok)
+ return;
+ if (0 != strcasecmp (hs->account_url,
+ exchange_credit_url))
+ return; // Account mismatch
+ if (ic->total >= GNUNET_MAX (hs->num_results,
+ -hs->num_results) )
+ {
+ TALER_LOG_DEBUG ("Hit history limit\n");
+ return;
+ }
+ TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
+ debit_account,
+ credit_account,
+ hs->account_url);
+ /* found matching record, make sure we have room */
+ if (ic->pos == ic->total)
+ GNUNET_array_grow (ic->h,
+ ic->total,
+ ic->pos * 2);
+ ic->h[ic->pos].url = GNUNET_strdup (debit_account);
+ ic->h[ic->pos].details.debit_account_uri = ic->h[ic->pos].url;
+ ic->h[ic->pos].details.amount = *amount;
+ ic->h[ic->pos].row_id = *row_id;
+ ic->h[ic->pos].details.reserve_pub = *reserve_pub;
+ ic->pos++;
+}
+
+
+/**
* This function constructs the list of history elements that
* interest the account number of the caller. It has two main
* loops: the first to figure out how many history elements have
* to be allocated, and the second to actually populate every
* element.
*
- * @param is interpreter state (supposedly having the
- * current CMD pointing at a "history" CMD).
+ * @param hs history state
* @param[out] rh history array to initialize.
* @return number of entries in @a rh.
*/
static unsigned int
-build_history (struct TALER_TESTING_Interpreter *is,
+build_history (struct HistoryState *hs,
struct History **rh)
{
- struct HistoryState *hs = is->commands[is->ip].cls;
- unsigned int total;
- unsigned int pos;
- struct History *h;
- const struct TALER_TESTING_Command *add_incoming_cmd;
- int inc;
- unsigned int start;
- unsigned int end;
-
- /* @var turns GNUNET_YES whenever either no 'start' value was
- * given for the history query, or the given value is found
- * in the list of all the CMDs. *///
- int ok;
- const uint64_t *row_id_start = NULL;
+ struct TALER_TESTING_Interpreter *is = hs->is;
+ struct IteratorContext ic = {
+ .hs = hs
+ };
if (NULL != hs->start_row_reference)
{
+ const struct TALER_TESTING_Command *add_incoming_cmd;
+
TALER_LOG_INFO ("`%s': start row given via reference `%s'\n",
TALER_TESTING_interpreter_get_current_label (is),
hs->start_row_reference);
@@ -210,124 +312,92 @@ build_history (struct TALER_TESTING_Interpreter *is,
hs->start_row_reference);
GNUNET_assert (NULL != add_incoming_cmd);
GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_uint64 (add_incoming_cmd,
- 0,
- &row_id_start));
+ TALER_TESTING_get_trait_row (add_incoming_cmd,
+ &ic.row_id_start));
}
+ ic.ok = false;
+ if (NULL == ic.row_id_start)
+ ic.ok = true;
+ GNUNET_array_grow (ic.h,
+ ic.total,
+ 4);
GNUNET_assert (0 != hs->num_results);
- if (0 == is->ip)
- {
- TALER_LOG_DEBUG ("Checking history at FIRST transaction (EMPTY)\n");
- *rh = NULL;
- return 0;
- }
+ TALER_TESTING_iterate (is,
+ hs->num_results > 0,
+ &command_cb,
+ &ic);
+ GNUNET_assert (ic.ok);
+ GNUNET_array_grow (ic.h,
+ ic.total,
+ ic.pos);
+ if (0 == ic.pos)
+ TALER_LOG_DEBUG ("Empty credit history computed\n");
+ *rh = ic.h;
+ return ic.pos;
+}
+
- if (hs->num_results > 0)
+/**
+ * Normalize IBAN-based payto URI in @a in.
+ *
+ * @param in input payto://-URI to normalize
+ * @return normalized IBAN for the test
+ */
+static char *
+normalize (const char *in)
+{
+ char *npt;
+ const char *q = strchr (in,
+ '?');
+ const char *mptr;
+ const char *bic;
+ const char *iban;
+
+ if (NULL == q)
+ npt = GNUNET_strdup (in);
+ else
+ npt = GNUNET_strndup (in,
+ q - in);
+ if (0 != strncasecmp (npt,
+ "payto://",
+ strlen ("payto://")))
{
- inc = 1; /* _inc_rement */
- start = 0;
- end = is->ip - 1;
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Invalid payto: %s\n",
+ npt);
+ GNUNET_free (npt);
+ return NULL;
}
- else
+ mptr = npt + strlen ("payto://");
+ bic = strchr (mptr, '/');
+ if (NULL == bic)
{
- inc = -1;
- start = is->ip - 1;
- end = 0;
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Invalid payto: %s\n",
+ npt);
+ GNUNET_free (npt);
+ return NULL;
}
-
- ok = GNUNET_NO;
- if (NULL == row_id_start)
- ok = GNUNET_YES;
- h = NULL;
- total = 0;
- GNUNET_array_grow (h,
- total,
- 4);
- pos = 0;
- for (unsigned int off = start; off != end + inc; off += inc)
+ bic++;
+ iban = strchr (bic, '/');
+ if (NULL != iban)
{
- const struct TALER_TESTING_Command *cmd = &is->commands[off];
- const uint64_t *row_id;
- const char *credit_account;
- const char *debit_account;
- const struct TALER_Amount *amount;
- const struct TALER_ReservePublicKeyP *reserve_pub;
- const char *exchange_credit_url;
-
- /* The following command allows us to skip over those CMDs
- * that do not offer a "row_id" trait. Such skipped CMDs are
- * not interesting for building a history. *///
- if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_bank_row (cmd,
- &row_id)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_CREDIT,
- &credit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_DEBIT,
- &debit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (cmd,
- 0,
- &amount)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (cmd,
- 0,
- &reserve_pub)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_url (cmd,
- TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
- &exchange_credit_url)) )
- continue; /* not an interesting event */
- /* Seek "/history/incoming" starting row. */
- if ( (NULL != row_id_start) &&
- (*row_id_start == *row_id) &&
- (GNUNET_NO == ok) )
- {
- /* Until here, nothing counted. */
- ok = GNUNET_YES;
- continue;
- }
- /* when 'start' was _not_ given, then ok == GNUNET_YES */
- if (GNUNET_NO == ok)
- continue; /* skip until we find the marker */
- if (0 != strcasecmp (hs->account_url,
- exchange_credit_url))
- continue; /* account mismatch */
- if (total >= GNUNET_MAX (hs->num_results,
- -hs->num_results) )
- {
- TALER_LOG_DEBUG ("Hit history limit\n");
- break;
- }
- TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
- debit_account,
- credit_account,
- hs->account_url);
- /* found matching record, make sure we have room */
- if (pos == total)
- GNUNET_array_grow (h,
- total,
- pos * 2);
- h[pos].url = GNUNET_strdup (debit_account);
- h[pos].details.debit_account_uri = h[pos].url;
- h[pos].details.amount = *amount;
- h[pos].row_id = *row_id;
- h[pos].details.reserve_pub = *reserve_pub;
- h[pos].details.credit_account_uri = exchange_credit_url;
- pos++;
+ /* need to remove bic */
+ char *n;
+
+ iban++;
+ GNUNET_asprintf (&n,
+ "payto://%.*s/%s",
+ (int) ((bic - mptr) - 1),
+ mptr,
+ iban);
+ GNUNET_free (npt);
+ npt = n;
}
- GNUNET_assert (GNUNET_YES == ok);
- GNUNET_array_grow (h,
- total,
- pos);
- if (0 == pos)
- TALER_LOG_DEBUG ("Empty credit history computed\n");
- *rh = h;
- return total;
+ return npt;
}
@@ -342,12 +412,15 @@ build_history (struct TALER_TESTING_Interpreter *is,
* @param details the expected transaction details.
* @return #GNUNET_OK if the transaction is what we expect.
*/
-static int
+static enum GNUNET_GenericReturnValue
check_result (struct History *h,
unsigned int total,
unsigned int off,
const struct TALER_BANK_CreditDetails *details)
{
+ char *u1;
+ char *u2;
+
if (off >= total)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -360,25 +433,42 @@ check_result (struct History *h,
off);
return GNUNET_SYSERR;
}
+ u1 = normalize (h[off].details.debit_account_uri);
+ if (NULL == u1)
+ return GNUNET_SYSERR;
+ u2 = normalize (details->debit_account_uri);
+ if (NULL == u2)
+ {
+ GNUNET_free (u1);
+ return GNUNET_SYSERR;
+ }
if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub,
&details->reserve_pub)) ||
(0 != TALER_amount_cmp (&h[off].details.amount,
&details->amount)) ||
- (0 != strcasecmp (h[off].details.debit_account_uri,
- details->debit_account_uri)) )
+ (0 != strcasecmp (u1,
+ u2)) )
{
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "expected debit_account_uri: %s\n",
- details->debit_account_uri);
+ "expected debit_account_uri: %s with %s for %s\n",
+ u1,
+ TALER_amount2s (&h[off].details.amount),
+ TALER_B2S (&h[off].details.reserve_pub));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "actual debit_account_uri: %s\n",
- h[off].details.debit_account_uri);
+ "actual debit_account_uri: %s with %s for %s\n",
+ u2,
+ TALER_amount2s (&details->amount),
+ TALER_B2S (&details->reserve_pub));
print_expected (h,
total,
off);
+ GNUNET_free (u1);
+ GNUNET_free (u2);
return GNUNET_SYSERR;
}
+ GNUNET_free (u1);
+ GNUNET_free (u2);
return GNUNET_OK;
}
@@ -391,89 +481,86 @@ check_result (struct History *h,
* finally check it against what the bank returned.
*
* @param cls closure.
- * @param http_status HTTP response code, #MHD_HTTP_OK (200)
- * for successful status request 0 if the bank's reply is
- * bogus (fails to follow the protocol),
- * #MHD_HTTP_NO_CONTENT if there are no more results; on
- * success the last callback is always of this status
- * (even if `abs(num_results)` were already returned).
- * @param ec taler status code.
- * @param row_id monotonically increasing counter corresponding to
- * the transaction.
- * @param details details about the wire transfer.
- * @param json detailed response from the HTTPD, or NULL if
- * reply was not in JSON.
- * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
+ * @param chr http response details
*/
-static int
+static void
history_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t row_id,
- const struct TALER_BANK_CreditDetails *details,
- const json_t *json)
+ const struct TALER_BANK_CreditHistoryResponse *chr)
{
- struct TALER_TESTING_Interpreter *is = cls;
- struct HistoryState *hs = is->commands[is->ip].cls;
+ struct HistoryState *hs = cls;
+ struct TALER_TESTING_Interpreter *is = hs->is;
- (void) row_id;
- if (NULL == details)
+ hs->hh = NULL;
+ switch (chr->http_status)
{
- hs->hh = NULL;
- if ( (hs->results_obtained != hs->total) ||
- (GNUNET_YES == hs->failed) ||
- (MHD_HTTP_NO_CONTENT != http_status) )
+ case 0:
+ GNUNET_break (0);
+ goto error;
+ case MHD_HTTP_OK:
+ for (unsigned int i = 0; i<chr->details.ok.details_length; i++)
{
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected history of length %u, got %llu;"
- " HTTP status code: %u/%d, failed: %d\n",
- hs->total,
- (unsigned long long) hs->results_obtained,
- http_status,
- (int) ec,
- hs->failed);
- print_expected (hs->h,
- hs->total,
- UINT_MAX);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
+ const struct TALER_BANK_CreditDetails *cd =
+ &chr->details.ok.details[i];
+
+ /* check current element */
+ if (GNUNET_OK !=
+ check_result (hs->h,
+ hs->total,
+ hs->results_obtained,
+ cd))
+ {
+ GNUNET_break (0);
+ json_dumpf (chr->response,
+ stderr,
+ JSON_COMPACT);
+ hs->failed = true;
+ hs->hh = NULL;
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ hs->results_obtained++;
}
TALER_TESTING_interpreter_next (is);
- return GNUNET_OK;
- }
- if (MHD_HTTP_OK != http_status)
- {
+ return;
+ case MHD_HTTP_NO_CONTENT:
+ if (0 == hs->total)
+ {
+ /* not found is OK for empty history */
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_break (0);
+ goto error;
+ case MHD_HTTP_NOT_FOUND:
+ if (0 == hs->total)
+ {
+ /* not found is OK for empty history */
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_break (0);
+ goto error;
+ default:
hs->hh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unwanted response code from /history/incoming: %u\n",
- http_status);
+ chr->http_status);
TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
- }
-
- /* check current element */
- if (GNUNET_OK != check_result (hs->h,
- hs->total,
- hs->results_obtained,
- details))
- {
- char *acc;
-
- GNUNET_break (0);
- acc = json_dumps (json,
- JSON_COMPACT);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Result %u was `%s'\n",
- (unsigned int) hs->results_obtained++,
- acc);
- if (NULL != acc)
- free (acc);
- hs->failed = GNUNET_YES;
- return GNUNET_SYSERR;
+ return;
}
- hs->results_obtained++;
- return GNUNET_OK;
+error:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history of length %u, got %llu;"
+ " HTTP status code: %u/%d, failed: %d\n",
+ hs->total,
+ (unsigned long long) hs->results_obtained,
+ chr->http_status,
+ (int) chr->ec,
+ hs->failed ? 1 : 0);
+ print_expected (hs->h,
+ hs->total,
+ UINT_MAX);
+ TALER_TESTING_interpreter_fail (is);
}
@@ -494,36 +581,37 @@ history_run (void *cls,
const uint64_t *row_ptr;
(void) cmd;
+ hs->is = is;
/* Get row_id from trait. */
if (NULL != hs->start_row_reference)
{
const struct TALER_TESTING_Command *history_cmd;
- history_cmd = TALER_TESTING_interpreter_lookup_command
- (is, hs->start_row_reference);
-
+ history_cmd = TALER_TESTING_interpreter_lookup_command (
+ is,
+ hs->start_row_reference);
if (NULL == history_cmd)
TALER_TESTING_FAIL (is);
if (GNUNET_OK !=
- TALER_TESTING_get_trait_uint64 (history_cmd,
- 0,
- &row_ptr))
+ TALER_TESTING_get_trait_row (history_cmd,
+ &row_ptr))
TALER_TESTING_FAIL (is);
else
row_id = *row_ptr;
TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
(unsigned long long) row_id);
}
- hs->total = build_history (is,
+ hs->total = build_history (hs,
&hs->h);
- hs->hh = TALER_BANK_credit_history (is->ctx,
- &hs->auth,
- row_id,
- hs->num_results,
- GNUNET_TIME_UNIT_ZERO,
- &history_cb,
- is);
+ hs->hh = TALER_BANK_credit_history (
+ TALER_TESTING_interpreter_get_context (is),
+ &hs->auth,
+ row_id,
+ hs->num_results,
+ GNUNET_TIME_UNIT_ZERO,
+ &history_cb,
+ hs);
GNUNET_assert (NULL != hs->hh);
}
@@ -544,7 +632,8 @@ history_cleanup (void *cls,
(void) cmd;
if (NULL != hs->hh)
{
- TALER_LOG_WARNING ("/history/incoming did not complete\n");
+ TALER_TESTING_command_incomplete (hs->is,
+ cmd->label);
TALER_BANK_credit_history_cancel (hs->hh);
}
GNUNET_free (hs->account_url);
@@ -574,8 +663,7 @@ TALER_TESTING_cmd_bank_credits (
.label = label,
.cls = hs,
.run = &history_run,
- .cleanup = &history_cleanup,
- .traits = &history_traits
+ .cleanup = &history_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_bank_history_debit.c b/src/testing/testing_api_cmd_bank_history_debit.c
index 779facee8..1cb7320fa 100644
--- a/src/testing/testing_api_cmd_bank_history_debit.c
+++ b/src/testing/testing_api_cmd_bank_history_debit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2021 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
@@ -92,6 +92,11 @@ struct HistoryState
struct TALER_BANK_DebitHistoryHandle *hh;
/**
+ * Our interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
* Expected number of results (= rows).
*/
uint64_t results_obtained;
@@ -116,32 +121,6 @@ struct HistoryState
/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- *
- * @return #GNUNET_OK on success
- */
-static int
-history_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- /* Must define this function because some callbacks
- * look for certain traits on _all_ the commands. */
- return GNUNET_SYSERR;
-}
-
-
-/**
* Log which history we expected. Called when an error occurs.
*
* @param h what we expected.
@@ -173,169 +152,248 @@ print_expected (struct History *h,
/**
+ * Closure for command_cb().
+ */
+struct IteratorContext
+{
+ /**
+ * Array of history items to return.
+ */
+ struct History *h;
+
+ /**
+ * Set to the row ID from where on we should actually process history items,
+ * or NULL if we should process all of them.
+ */
+ const uint64_t *row_id_start;
+
+ /**
+ * History state we are working on.
+ */
+ struct HistoryState *hs;
+
+ /**
+ * Current length of the @e h array.
+ */
+ unsigned int total;
+
+ /**
+ * Current write position in @e h array.
+ */
+ unsigned int pos;
+
+ /**
+ * Ok equals True whenever a starting row_id was provided AND was found
+ * among the CMDs, OR no starting row was given in the first place.
+ */
+ bool ok;
+
+};
+
+
+/**
+ * Helper function of build_history() that expands
+ * the history for each relevant command encountered.
+ *
+ * @param[in,out] cls our `struct IteratorContext`
+ * @param cmd a command to process
+ */
+static void
+command_cb (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct IteratorContext *ic = cls;
+ struct HistoryState *hs = ic->hs;
+
+ const uint64_t *row_id;
+ const char *debit_account;
+ const char *credit_account;
+ const struct TALER_Amount *amount;
+ const struct TALER_WireTransferIdentifierRawP *wtid;
+ const char *exchange_base_url;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking if command %s is relevant for debit history\n",
+ cmd->label);
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_bank_row (cmd,
+ &row_id)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_debit_payto_uri (cmd,
+ &debit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_credit_payto_uri (cmd,
+ &credit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount (cmd,
+ &amount)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_wtid (cmd,
+ &wtid)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_exchange_url (cmd,
+ &exchange_base_url)) )
+ return; /* not an event we care about */
+ /* Seek "/history/outgoing" starting row. */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Command %s is relevant for debit history!\n",
+ cmd->label);
+ if ( (NULL != ic->row_id_start) &&
+ (*(ic->row_id_start) == *row_id) &&
+ (! ic->ok) )
+ {
+ /* Until here, nothing counted. */
+ ic->ok = true;
+ return;
+ }
+ /* when 'start' was _not_ given, then ok == GNUNET_YES */
+ if (! ic->ok)
+ return; /* skip until we find the marker */
+ if (ic->total >= GNUNET_MAX (hs->num_results,
+ -hs->num_results) )
+ {
+ TALER_LOG_DEBUG ("Hit history limit\n");
+ return;
+ }
+ TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
+ debit_account,
+ credit_account,
+ hs->account_url);
+ /* found matching record, make sure we have room */
+ if (ic->pos == ic->total)
+ GNUNET_array_grow (ic->h,
+ ic->total,
+ ic->pos * 2);
+ ic->h[ic->pos].c_url = GNUNET_strdup (credit_account);
+ ic->h[ic->pos].d_url = GNUNET_strdup (debit_account);
+ ic->h[ic->pos].details.credit_account_uri = ic->h[ic->pos].c_url;
+ ic->h[ic->pos].details.amount = *amount;
+ ic->h[ic->pos].row_id = *row_id;
+ ic->h[ic->pos].details.wtid = *wtid;
+ ic->h[ic->pos].details.exchange_base_url = exchange_base_url;
+ ic->pos++;
+}
+
+
+/**
* This function constructs the list of history elements that
* interest the account number of the caller. It has two main
* loops: the first to figure out how many history elements have
* to be allocated, and the second to actually populate every
* element.
*
- * @param is interpreter state (supposedly having the
- * current CMD pointing at a "history" CMD).
+ * @param hs history state command context
* @param[out] rh history array to initialize.
* @return number of entries in @a rh.
*/
static unsigned int
-build_history (struct TALER_TESTING_Interpreter *is,
+build_history (struct HistoryState *hs,
struct History **rh)
{
- struct HistoryState *hs = is->commands[is->ip].cls;
- unsigned int total;
- unsigned int pos;
- struct History *h;
- const struct TALER_TESTING_Command *add_incoming_cmd;
- int inc;
- int start;
- int end;
- /* #GNUNET_YES whenever either no 'start' value was given for the history
- * query, or the given value is found in the list of all the CMDs. */
- int ok;
- const uint64_t *row_id_start = NULL;
+ struct TALER_TESTING_Interpreter *is = hs->is;
+ struct IteratorContext ic = {
+ .hs = hs
+ };
if (NULL != hs->start_row_reference)
{
- TALER_LOG_INFO
- ("`%s': start row given via reference `%s'\n",
+ const struct TALER_TESTING_Command *add_incoming_cmd;
+
+ TALER_LOG_INFO (
+ "`%s': start row given via reference `%s'\n",
TALER_TESTING_interpreter_get_current_label (is),
hs->start_row_reference);
- add_incoming_cmd = TALER_TESTING_interpreter_lookup_command
- (is, hs->start_row_reference);
+ add_incoming_cmd = TALER_TESTING_interpreter_lookup_command (
+ is,
+ hs->start_row_reference);
GNUNET_assert (NULL != add_incoming_cmd);
GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_uint64 (add_incoming_cmd,
- 0,
- &row_id_start));
+ TALER_TESTING_get_trait_row (add_incoming_cmd,
+ &ic.row_id_start));
}
+ ic.ok = false;
+ if (NULL == ic.row_id_start)
+ ic.ok = true;
+ GNUNET_array_grow (ic.h,
+ ic.total,
+ 4);
GNUNET_assert (0 != hs->num_results);
- if (0 == is->ip)
- {
- TALER_LOG_DEBUG ("Checking history at first CMD..\n");
- *rh = NULL;
- return 0;
- }
+ TALER_TESTING_iterate (is,
+ hs->num_results > 0,
+ &command_cb,
+ &ic);
+ GNUNET_assert (ic.ok);
+ GNUNET_array_grow (ic.h,
+ ic.total,
+ ic.pos);
+ if (0 == ic.pos)
+ TALER_LOG_DEBUG ("Empty credit history computed\n");
+ *rh = ic.h;
+ return ic.pos;
+}
- /* AKA 'delta' */
- if (hs->num_results > 0)
- {
- inc = 1; /* _inc_rement: go forwards */
- start = 0;
- end = is->ip;
- }
+
+/**
+ * Normalize IBAN-based payto URI in @a in.
+ *
+ * @param in input payto://-URI to normalize
+ * @return normalized IBAN for the test
+ */
+static char *
+normalize (const char *in)
+{
+ char *npt;
+ const char *q = strchr (in,
+ '?');
+ const char *mptr;
+ const char *bic;
+ const char *iban;
+
+ if (NULL == q)
+ npt = GNUNET_strdup (in);
else
+ npt = GNUNET_strndup (in,
+ q - in);
+ if (0 != strncasecmp (npt,
+ "payto://",
+ strlen ("payto://")))
{
- inc = -1; /* decrement: we go backwards */
- start = is->ip - 1;
- end = -1; /* range is exclusive, do look at 0! */
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Invalid payto: %s\n",
+ npt);
+ GNUNET_free (npt);
+ return NULL;
}
-
- ok = GNUNET_NO;
- if (NULL == row_id_start)
- ok = GNUNET_YES;
- h = NULL;
- total = 0;
- GNUNET_array_grow (h,
- total,
- 4);
- pos = 0;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Checking commands %u to %u for debit history\n",
- start,
- end);
- for (int off = start; off != end; off += inc)
+ mptr = npt + strlen ("payto://");
+ bic = strchr (mptr, '/');
+ if (NULL == bic)
{
- const struct TALER_TESTING_Command *cmd = &is->commands[off];
- const uint64_t *row_id;
- const char *debit_account;
- const char *credit_account;
- const struct TALER_Amount *amount;
- const struct TALER_WireTransferIdentifierRawP *wtid;
- const char *exchange_base_url;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Checking if command %s is relevant for debit history\n",
- cmd->label);
- if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_bank_row (cmd,
- &row_id)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_DEBIT,
- &debit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_CREDIT,
- &credit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (cmd,
- 0,
- &amount)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_wtid (cmd,
- 0,
- &wtid)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_url (cmd,
- TALER_TESTING_UT_EXCHANGE_BASE_URL,
- &exchange_base_url)) )
- continue; /* not an event we care about */
- /* Seek "/history/outgoing" starting row. */
+ GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Command %s is relevant for debit history!\n",
- cmd->label);
- if ( (NULL != row_id_start) &&
- (*row_id_start == *row_id) &&
- (GNUNET_NO == ok) )
- {
- /* Until here, nothing counted. */
- ok = GNUNET_YES;
- continue;
- }
- /* when 'start' was _not_ given, then ok == GNUNET_YES */
- if (GNUNET_NO == ok)
- continue; /* skip until we find the marker */
- if (total >= GNUNET_MAX (hs->num_results,
- -hs->num_results) )
- {
- TALER_LOG_DEBUG ("Hit history limit\n");
- break;
- }
- TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
- debit_account,
- credit_account,
- hs->account_url);
- /* found matching record, make sure we have room */
- if (pos == total)
- GNUNET_array_grow (h,
- total,
- pos * 2);
- h[pos].c_url = GNUNET_strdup (credit_account);
- h[pos].d_url = GNUNET_strdup (debit_account);
- h[pos].details.credit_account_uri = h[pos].c_url;
- h[pos].details.debit_account_uri = h[pos].d_url;
- h[pos].details.amount = *amount;
- h[pos].row_id = *row_id;
- h[pos].details.wtid = *wtid;
- h[pos].details.exchange_base_url = exchange_base_url;
- pos++;
+ "Invalid payto: %s\n",
+ npt);
+ GNUNET_free (npt);
+ return NULL;
+ }
+ bic++;
+ iban = strchr (bic, '/');
+ if (NULL != iban)
+ {
+ /* need to remove bic */
+ char *n;
+
+ iban++;
+ GNUNET_asprintf (&n,
+ "payto://%.*s/%s",
+ (int) ((bic - mptr) - 1),
+ mptr,
+ iban);
+ GNUNET_free (npt);
+ npt = n;
}
- GNUNET_assert (GNUNET_YES == ok);
- GNUNET_array_grow (h,
- total,
- pos);
- if (0 == pos)
- TALER_LOG_DEBUG ("Empty debit history computed\n");
- *rh = h;
- return total;
+ return npt;
}
@@ -350,12 +408,15 @@ build_history (struct TALER_TESTING_Interpreter *is,
* @param details the expected transaction details.
* @return #GNUNET_OK if the transaction is what we expect.
*/
-static int
+static enum GNUNET_GenericReturnValue
check_result (struct History *h,
uint64_t total,
unsigned int off,
const struct TALER_BANK_DebitDetails *details)
{
+ char *u1;
+ char *u2;
+
if (off >= total)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -368,14 +429,33 @@ check_result (struct History *h,
off);
return GNUNET_SYSERR;
}
+ u1 = normalize (h[off].details.credit_account_uri);
+ if (NULL == u1)
+ return GNUNET_SYSERR;
+ u2 = normalize (details->credit_account_uri);
+ if (NULL == u2)
+ {
+ GNUNET_free (u1);
+ return GNUNET_SYSERR;
+ }
if ( (0 != GNUNET_memcmp (&h[off].details.wtid,
&details->wtid)) ||
(0 != TALER_amount_cmp (&h[off].details.amount,
&details->amount)) ||
- (0 != strcasecmp (h[off].details.credit_account_uri,
- details->credit_account_uri)) )
+ (0 != strcasecmp (u1,
+ u2)) )
{
GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "expected debit_account_uri: %s with %s for %s\n",
+ u1,
+ TALER_amount2s (&h[off].details.amount),
+ TALER_B2S (&h[off].details.wtid));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "actual debit_account_uri: %s with %s for %s\n",
+ u2,
+ TALER_amount2s (&details->amount),
+ TALER_B2S (&details->wtid));
print_expected (h,
total,
off);
@@ -393,89 +473,86 @@ check_result (struct History *h,
* finally check it against what the bank returned.
*
* @param cls closure.
- * @param http_status HTTP response code, #MHD_HTTP_OK (200)
- * for successful status request 0 if the bank's reply is
- * bogus (fails to follow the protocol),
- * #MHD_HTTP_NO_CONTENT if there are no more results; on
- * success the last callback is always of this status
- * (even if `abs(num_results)` were already returned).
- * @param ec taler status code.
- * @param row_id monotonically increasing counter corresponding to
- * the transaction.
- * @param details details about the wire transfer.
- * @param json detailed response from the HTTPD, or NULL if
- * reply was not in JSON.
- * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
+ * @param dhr http response details
*/
-static int
+static void
history_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t row_id,
- const struct TALER_BANK_DebitDetails *details,
- const json_t *json)
+ const struct TALER_BANK_DebitHistoryResponse *dhr)
{
- struct TALER_TESTING_Interpreter *is = cls;
- struct HistoryState *hs = is->commands[is->ip].cls;
+ struct HistoryState *hs = cls;
+ struct TALER_TESTING_Interpreter *is = hs->is;
- (void) row_id;
- if (NULL == details)
+ hs->hh = NULL;
+ switch (dhr->http_status)
{
- hs->hh = NULL;
- if ( (hs->results_obtained != hs->total) ||
- (GNUNET_YES == hs->failed) ||
- (MHD_HTTP_NO_CONTENT != http_status) )
+ case 0:
+ GNUNET_break (0);
+ goto error;
+ case MHD_HTTP_OK:
+ for (unsigned int i = 0; i<dhr->details.ok.details_length; i++)
{
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected history of length %u, got %llu;"
- " HTTP status code: %u/%d, failed: %d\n",
- hs->total,
- (unsigned long long) hs->results_obtained,
- http_status,
- (int) ec,
- hs->failed);
- print_expected (hs->h,
- hs->total,
- UINT_MAX);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
+ const struct TALER_BANK_DebitDetails *dd =
+ &dhr->details.ok.details[i];
+
+ /* check current element */
+ if (GNUNET_OK !=
+ check_result (hs->h,
+ hs->total,
+ hs->results_obtained,
+ dd))
+ {
+ GNUNET_break (0);
+ json_dumpf (dhr->response,
+ stderr,
+ JSON_COMPACT);
+ hs->failed = true;
+ hs->hh = NULL;
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ hs->results_obtained++;
}
TALER_TESTING_interpreter_next (is);
- return GNUNET_OK;
- }
- if (MHD_HTTP_OK != http_status)
- {
+ return;
+ case MHD_HTTP_NO_CONTENT:
+ if (0 == hs->total)
+ {
+ /* not found is OK for empty history */
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_break (0);
+ goto error;
+ case MHD_HTTP_NOT_FOUND:
+ if (0 == hs->total)
+ {
+ /* not found is OK for empty history */
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_break (0);
+ goto error;
+ default:
hs->hh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unwanted response code from /history/outgoing: %u\n",
- http_status);
+ "Unwanted response code from /history/incoming: %u\n",
+ dhr->http_status);
TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
+ return;
}
-
- /* check current element */
- if (GNUNET_OK != check_result (hs->h,
- hs->total,
- hs->results_obtained,
- details))
- {
- char *acc;
-
- GNUNET_break (0);
- acc = json_dumps (json,
- JSON_COMPACT);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Result %u was `%s'\n",
- (unsigned int) hs->results_obtained++,
- acc);
- if (NULL != acc)
- free (acc);
- hs->failed = GNUNET_YES;
- return GNUNET_SYSERR;
- }
- hs->results_obtained++;
- return GNUNET_OK;
+error:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history of length %u, got %llu;"
+ " HTTP status code: %u/%d, failed: %d\n",
+ hs->total,
+ (unsigned long long) hs->results_obtained,
+ dhr->http_status,
+ (int) dhr->ec,
+ hs->failed ? 1 : 0);
+ print_expected (hs->h,
+ hs->total,
+ UINT_MAX);
+ TALER_TESTING_interpreter_fail (is);
}
@@ -496,6 +573,7 @@ history_run (void *cls,
const uint64_t *row_ptr;
(void) cmd;
+ hs->is = is;
/* Get row_id from trait. */
if (NULL != hs->start_row_reference)
{
@@ -508,23 +586,24 @@ history_run (void *cls,
if (NULL == history_cmd)
TALER_TESTING_FAIL (is);
if (GNUNET_OK !=
- TALER_TESTING_get_trait_uint64 (history_cmd,
- 0,
- &row_ptr))
+ TALER_TESTING_get_trait_row (history_cmd,
+ &row_ptr))
TALER_TESTING_FAIL (is);
else
row_id = *row_ptr;
TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
(unsigned long long) row_id);
}
- hs->total = build_history (is, &hs->h);
- hs->hh = TALER_BANK_debit_history (is->ctx,
- &hs->auth,
- row_id,
- hs->num_results,
- GNUNET_TIME_UNIT_ZERO,
- &history_cb,
- is);
+ hs->total = build_history (hs,
+ &hs->h);
+ hs->hh = TALER_BANK_debit_history (
+ TALER_TESTING_interpreter_get_context (is),
+ &hs->auth,
+ row_id,
+ hs->num_results,
+ GNUNET_TIME_UNIT_ZERO,
+ &history_cb,
+ hs);
GNUNET_assert (NULL != hs->hh);
}
@@ -545,7 +624,8 @@ history_cleanup (void *cls,
(void) cmd;
if (NULL != hs->hh)
{
- TALER_LOG_WARNING ("/history/outgoing did not complete\n");
+ TALER_TESTING_command_incomplete (hs->is,
+ cmd->label);
TALER_BANK_debit_history_cancel (hs->hh);
}
for (unsigned int off = 0; off<hs->total; off++)
@@ -558,17 +638,6 @@ history_cleanup (void *cls,
}
-/**
- * Make a "history" CMD.
- *
- * @param label command label.
- * @param auth login data to use
- * @param start_row_reference reference to a command that can
- * offer a row identifier, to be used as the starting row
- * to accept in the result.
- * @param num_results how many rows we want in the result.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_debits (const char *label,
const struct TALER_BANK_AuthenticationData *auth,
@@ -588,8 +657,7 @@ TALER_TESTING_cmd_bank_debits (const char *label,
.label = label,
.cls = hs,
.run = &history_run,
- .cleanup = &history_cleanup,
- .traits = &history_traits
+ .cleanup = &history_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_bank_transfer.c b/src/testing/testing_api_cmd_bank_transfer.c
index 565d6e460..bfb29e120 100644
--- a/src/testing/testing_api_cmd_bank_transfer.c
+++ b/src/testing/testing_api_cmd_bank_transfer.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2021 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
@@ -97,7 +97,7 @@ struct TransferState
/**
* Timestamp of the transaction (as returned from the bank).
*/
- struct GNUNET_TIME_Absolute timestamp;
+ struct GNUNET_TIME_Timestamp timestamp;
/**
* Configuration filename. Used to get the tip reserve key
@@ -149,8 +149,7 @@ do_retry (void *cls)
struct TransferState *fts = cls;
fts->retry_task = NULL;
- fts->is->commands[fts->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (fts->is);
transfer_run (fts,
NULL,
fts->is);
@@ -163,43 +162,35 @@ do_retry (void *cls)
* acceptable.
*
* @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
- * successful status request; 0 if the exchange's reply is
- * bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param serial_id unique ID of the wire transfer
- * @param timestamp time stamp of the transaction made.
+ * @param tr response details
*/
static void
confirmation_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t serial_id,
- struct GNUNET_TIME_Absolute timestamp)
+ const struct TALER_BANK_TransferResponse *tr)
{
struct TransferState *fts = cls;
struct TALER_TESTING_Interpreter *is = fts->is;
fts->weh = NULL;
- if (MHD_HTTP_OK != http_status)
+ if (MHD_HTTP_OK != tr->http_status)
{
if (0 != fts->do_retry)
{
fts->do_retry--;
- if ( (0 == http_status) ||
- (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ if ( (0 == tr->http_status) ||
+ (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == tr->http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Retrying transfer failed with %u/%d\n",
- http_status,
- (int) ec);
+ tr->http_status,
+ (int) tr->ec);
/* on DB conflicts, do not use backoff */
- if (TALER_EC_GENERIC_DB_SOFT_FAILURE == ec)
+ if (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec)
fts->backoff = GNUNET_TIME_UNIT_ZERO;
else
fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
- fts->is->commands[fts->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (fts->is);
fts->retry_task
= GNUNET_SCHEDULER_add_delayed (fts->backoff,
&do_retry,
@@ -207,17 +198,14 @@ confirmation_cb (void *cls,
return;
}
}
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Bank returned HTTP status %u/%d\n",
- http_status,
- (int) ec);
- TALER_TESTING_interpreter_fail (is);
+ TALER_TESTING_unexpected_status (is,
+ tr->http_status,
+ MHD_HTTP_OK);
return;
}
- fts->serial_id = serial_id;
- fts->timestamp = timestamp;
+ fts->serial_id = tr->details.ok.row_id;
+ fts->timestamp = tr->details.ok.timestamp;
TALER_TESTING_interpreter_next (is);
}
@@ -284,9 +272,8 @@ transfer_cleanup (void *cls,
if (NULL != fts->weh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %s did not complete\n",
- cmd->label);
+ TALER_TESTING_command_incomplete (fts->is,
+ cmd->label);
TALER_BANK_transfer_cancel (fts->weh);
fts->weh = NULL;
}
@@ -310,7 +297,7 @@ transfer_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
transfer_traits (void *cls,
const void **ret,
const char *trait,
@@ -318,17 +305,16 @@ transfer_traits (void *cls,
{
struct TransferState *fts = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- fts->exchange_base_url),
+ TALER_TESTING_make_trait_exchange_url (
+ fts->exchange_base_url),
TALER_TESTING_make_trait_bank_row (&fts->serial_id),
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
- fts->payto_credit_account),
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
- fts->payto_debit_account),
- TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
- TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
- TALER_TESTING_make_trait_wtid (0,
- &fts->wtid),
+ TALER_TESTING_make_trait_credit_payto_uri (
+ fts->payto_credit_account),
+ TALER_TESTING_make_trait_debit_payto_uri (
+ fts->payto_debit_account),
+ TALER_TESTING_make_trait_amount (&fts->amount),
+ TALER_TESTING_make_trait_timestamp (0, &fts->timestamp),
+ TALER_TESTING_make_trait_wtid (&fts->wtid),
TALER_TESTING_trait_end ()
};
@@ -339,18 +325,6 @@ transfer_traits (void *cls,
}
-/**
- * Create transfer command.
- *
- * @param label command label.
- * @param amount amount to transfer.
- * @param auth authentication data to use
- * @param payto_debit_account which account sends money.
- * @param payto_credit_account which account receives money.
- * @param wtid wire transfer identifier to use
- * @param exchange_base_url exchange URL to use
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_transfer (const char *label,
const char *amount,
@@ -394,13 +368,6 @@ TALER_TESTING_cmd_transfer (const char *label,
}
-/**
- * Modify a transfer command to enable retries when the reserve is not yet
- * full or we get other transient errors from the bank.
- *
- * @param cmd a fakebank transfer command
- * @return the command with retries enabled
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_transfer_retry (struct TALER_TESTING_Command cmd)
{
diff --git a/src/testing/testing_api_cmd_batch.c b/src/testing/testing_api_cmd_batch.c
index ca23d7fd9..5bb7b974e 100644
--- a/src/testing/testing_api_cmd_batch.c
+++ b/src/testing/testing_api_cmd_batch.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -38,6 +38,11 @@ struct BatchState
struct TALER_TESTING_Command *batch;
/**
+ * My command (the batch command).
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
* Internal command pointer.
*/
unsigned int batch_ip;
@@ -58,6 +63,7 @@ batch_run (void *cls,
{
struct BatchState *bs = cls;
+ bs->cmd = cmd;
if (NULL != bs->batch[bs->batch_ip].label)
TALER_LOG_INFO ("Running batched command: %s\n",
bs->batch[bs->batch_ip].label);
@@ -97,8 +103,9 @@ batch_cleanup (void *cls,
for (unsigned int i = 0;
NULL != bs->batch[i].label;
i++)
- bs->batch[i].cleanup (bs->batch[i].cls,
- &bs->batch[i]);
+ if (NULL != bs->batch[i].cleanup)
+ bs->batch[i].cleanup (bs->batch[i].cls,
+ &bs->batch[i]);
GNUNET_free (bs->batch);
GNUNET_free (bs);
}
@@ -113,22 +120,15 @@ batch_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
batch_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
-#define CURRENT_CMD_INDEX 0
-#define BATCH_INDEX 1
-
struct BatchState *bs = cls;
-
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_cmd
- (CURRENT_CMD_INDEX, &bs->batch[bs->batch_ip]),
- TALER_TESTING_make_trait_cmd
- (BATCH_INDEX, bs->batch),
+ TALER_TESTING_make_trait_batch_cmds (bs->batch),
TALER_TESTING_trait_end ()
};
@@ -140,18 +140,6 @@ batch_traits (void *cls,
}
-/**
- * Create a "batch" command. Such command takes a
- * end_CMD-terminated array of CMDs and executed them.
- * Once it hits the end CMD, it passes the control
- * to the next top-level CMD, regardless of it being
- * another batch or ordinary CMD.
- *
- * @param label the command label.
- * @param batch array of CMDs to execute.
- *
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_batch (const char *label,
struct TALER_TESTING_Command *batch)
@@ -168,9 +156,9 @@ TALER_TESTING_cmd_batch (const char *label,
bs->batch = GNUNET_new_array (i + 1,
struct TALER_TESTING_Command);
- memcpy (bs->batch,
- batch,
- sizeof (struct TALER_TESTING_Command) * i);
+ GNUNET_memcpy (bs->batch,
+ batch,
+ sizeof (struct TALER_TESTING_Command) * i);
{
struct TALER_TESTING_Command cmd = {
.cls = bs,
@@ -185,44 +173,43 @@ TALER_TESTING_cmd_batch (const char *label,
}
-/**
- * Advance internal pointer to next command.
- *
- * @param is interpreter state.
- */
-void
-TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is)
+bool
+TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is,
+ void *cls)
{
- struct BatchState *bs = is->commands[is->ip].cls;
+ struct BatchState *bs = cls;
+ struct TALER_TESTING_Command *bcmd = &bs->batch[bs->batch_ip];
- if (NULL == bs->batch[bs->batch_ip].label)
+ if (NULL == bcmd->label)
{
- is->commands[is->ip].finish_time = GNUNET_TIME_absolute_get ();
- is->ip++;
- return;
+ /* This batch is done */
+ return true;
+ }
+ if (TALER_TESTING_cmd_is_batch (bcmd))
+ {
+ if (TALER_TESTING_cmd_batch_next (is,
+ bcmd->cls))
+ {
+ /* sub-batch is done */
+ bcmd->finish_time = GNUNET_TIME_absolute_get ();
+ bs->batch_ip++;
+ return false;
+ }
}
- bs->batch[bs->batch_ip].finish_time = GNUNET_TIME_absolute_get ();
+ /* Simple command is done */
+ bcmd->finish_time = GNUNET_TIME_absolute_get ();
bs->batch_ip++;
+ return false;
}
-/**
- * Test if this command is a batch command.
- *
- * @return false if not, true if it is a batch command
- */
-int
+bool
TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd)
{
return cmd->run == &batch_run;
}
-/**
- * Obtain what command the batch is at.
- *
- * @return cmd current batch command
- */
struct TALER_TESTING_Command *
TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd)
{
@@ -233,12 +220,6 @@ TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd)
}
-/**
- * Set what command the batch should be at.
- *
- * @param cmd current batch command
- * @param new_ip where to move the IP
- */
void
TALER_TESTING_cmd_batch_set_current (const struct TALER_TESTING_Command *cmd,
unsigned int new_ip)
diff --git a/src/testing/testing_api_cmd_batch_deposit.c b/src/testing/testing_api_cmd_batch_deposit.c
new file mode 100644
index 000000000..5139d3524
--- /dev/null
+++ b/src/testing/testing_api_cmd_batch_deposit.c
@@ -0,0 +1,656 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_batch_deposit.c
+ * @brief command for testing /batch-deposit.
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * How often do we retry before giving up?
+ */
+#define NUM_RETRIES 5
+
+/**
+ * How long do we wait AT MOST when retrying?
+ */
+#define MAX_BACKOFF GNUNET_TIME_relative_multiply ( \
+ GNUNET_TIME_UNIT_MILLISECONDS, 100)
+
+
+/**
+ * Information per coin in the batch.
+ */
+struct Coin
+{
+
+ /**
+ * Amount to deposit.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Deposit fee.
+ */
+ struct TALER_Amount deposit_fee;
+
+ /**
+ * Our coin signature.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
+ * Reference to any command that is able to provide a coin,
+ * possibly using $LABEL#$INDEX notation.
+ */
+ char *coin_reference;
+
+ /**
+ * Denomination public key of the coin.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+
+ /**
+ * The command being referenced.
+ */
+ const struct TALER_TESTING_Command *coin_cmd;
+
+ /**
+ * Expected entry in the coin history created by this
+ * coin.
+ */
+ struct TALER_EXCHANGE_CoinHistoryEntry che;
+
+ /**
+ * Index of the coin at @e coin_cmd.
+ */
+ unsigned int coin_idx;
+};
+
+
+/**
+ * State for a "batch deposit" CMD.
+ */
+struct BatchDepositState
+{
+
+ /**
+ * Refund deadline. Zero for no refunds.
+ */
+ struct GNUNET_TIME_Timestamp refund_deadline;
+
+ /**
+ * Wire deadline.
+ */
+ struct GNUNET_TIME_Timestamp wire_deadline;
+
+ /**
+ * Timestamp of the /deposit operation in the wallet (contract signing time).
+ */
+ struct GNUNET_TIME_Timestamp wallet_timestamp;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * When did the exchange receive the deposit?
+ */
+ struct GNUNET_TIME_Timestamp exchange_timestamp;
+
+ /**
+ * Signing key used by the exchange to sign the
+ * deposit confirmation.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * Set (by the interpreter) to a fresh private key. This
+ * key will be used to sign the deposit request.
+ */
+ struct TALER_MerchantPrivateKeyP merchant_priv;
+
+ /**
+ * Deposit handle while operation is running.
+ */
+ struct TALER_EXCHANGE_BatchDepositHandle *dh;
+
+ /**
+ * Array of coins to batch-deposit.
+ */
+ struct Coin *coins;
+
+ /**
+ * Wire details of who is depositing -- this would be merchant
+ * wire details in a normal scenario.
+ */
+ json_t *wire_details;
+
+ /**
+ * JSON string describing what a proposal is about.
+ */
+ json_t *contract_terms;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * Deposit confirmation signature from the exchange.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+ /**
+ * Reference to previous deposit operation.
+ * Only present if we're supposed to replay the previous deposit.
+ */
+ const char *deposit_reference;
+
+ /**
+ * If @e coin_reference refers to an operation that generated
+ * an array of coins, this value determines which coin to pick.
+ */
+ unsigned int num_coins;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Set to true if the /deposit succeeded
+ * and we now can provide the resulting traits.
+ */
+ bool deposit_succeeded;
+
+};
+
+
+/**
+ * Callback to analyze the /batch-deposit response, just used to check if the
+ * response code is acceptable.
+ *
+ * @param cls closure.
+ * @param dr deposit response details
+ */
+static void
+batch_deposit_cb (void *cls,
+ const struct TALER_EXCHANGE_BatchDepositResult *dr)
+{
+ struct BatchDepositState *ds = cls;
+
+ ds->dh = NULL;
+ if (ds->expected_response_code != dr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ dr->hr.http_status,
+ ds->expected_response_code);
+ return;
+ }
+ if (MHD_HTTP_OK == dr->hr.http_status)
+ {
+ ds->deposit_succeeded = GNUNET_YES;
+ ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
+ ds->exchange_pub = *dr->details.ok.exchange_pub;
+ ds->exchange_sig = *dr->details.ok.exchange_sig;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+batch_deposit_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct BatchDepositState *ds = cls;
+ const struct TALER_DenominationSignature *denom_pub_sig;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct TALER_PrivateContractHashP h_contract_terms;
+ enum TALER_ErrorCode ec;
+ struct TALER_WireSaltP wire_salt;
+ struct TALER_MerchantWireHashP h_wire;
+ const char *payto_uri;
+ struct TALER_EXCHANGE_CoinDepositDetail cdds[ds->num_coins];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("payto_uri",
+ &payto_uri),
+ GNUNET_JSON_spec_fixed_auto ("salt",
+ &wire_salt),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *exchange_url
+ = TALER_TESTING_get_exchange_url (is);
+
+ (void) cmd;
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ memset (cdds,
+ 0,
+ sizeof (cdds));
+ ds->is = is;
+ GNUNET_assert (NULL != ds->wire_details);
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (ds->wire_details,
+ spec,
+ NULL, NULL))
+ {
+ json_dumpf (ds->wire_details,
+ stderr,
+ JSON_INDENT (2));
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_JSON_contract_hash (ds->contract_terms,
+ &h_contract_terms))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
+ &h_wire));
+ if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time))
+ {
+ struct GNUNET_TIME_Relative refund_deadline;
+
+ refund_deadline
+ = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time);
+ ds->wire_deadline
+ =
+ GNUNET_TIME_relative_to_timestamp (
+ GNUNET_TIME_relative_multiply (refund_deadline,
+ 2));
+ }
+ else
+ {
+ ds->refund_deadline = ds->wallet_timestamp;
+ ds->wire_deadline = GNUNET_TIME_timestamp_get ();
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv,
+ &merchant_pub.eddsa_pub);
+
+ for (unsigned int i = 0; i<ds->num_coins; i++)
+ {
+ struct Coin *coin = &ds->coins[i];
+ struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i];
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
+
+ GNUNET_assert (NULL != coin->coin_reference);
+ cdd->amount = coin->amount;
+ coin->coin_cmd = TALER_TESTING_interpreter_lookup_command (
+ is,
+ coin->coin_reference);
+ if (NULL == coin->coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin->coin_cmd,
+ coin->coin_idx,
+ &coin_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_age_commitment_proof (coin->coin_cmd,
+ coin->coin_idx,
+ &age_commitment_proof))
+ ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (coin->coin_cmd,
+ coin->coin_idx,
+ &coin->denom_pub)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_sig (coin->coin_cmd,
+ coin->coin_idx,
+ &denom_pub_sig)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL != age_commitment_proof)
+ {
+ TALER_age_commitment_hash (&age_commitment_proof->commitment,
+ &cdd->h_age_commitment);
+ }
+ coin->deposit_fee = coin->denom_pub->fees.deposit;
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &cdd->coin_pub.eddsa_pub);
+ cdd->denom_sig = *denom_pub_sig;
+ cdd->h_denom_pub = coin->denom_pub->h_key;
+ TALER_wallet_deposit_sign (&coin->amount,
+ &coin->denom_pub->fees.deposit,
+ &h_wire,
+ &h_contract_terms,
+ NULL, /* wallet_data_hash */
+ &cdd->h_age_commitment,
+ NULL, /* hash of extensions */
+ &coin->denom_pub->h_key,
+ ds->wallet_timestamp,
+ &merchant_pub,
+ ds->refund_deadline,
+ coin_priv,
+ &cdd->coin_sig);
+ coin->coin_sig = cdd->coin_sig;
+ coin->che.type = TALER_EXCHANGE_CTT_DEPOSIT;
+ coin->che.amount = coin->amount;
+ coin->che.details.deposit.h_wire = h_wire;
+ coin->che.details.deposit.h_contract_terms = h_contract_terms;
+ coin->che.details.deposit.no_h_policy = true;
+ coin->che.details.deposit.no_wallet_data_hash = true;
+ coin->che.details.deposit.wallet_timestamp = ds->wallet_timestamp;
+ coin->che.details.deposit.merchant_pub = merchant_pub;
+ coin->che.details.deposit.refund_deadline = ds->refund_deadline;
+ coin->che.details.deposit.sig = cdd->coin_sig;
+ coin->che.details.deposit.no_hac = GNUNET_is_zero (&cdd->h_age_commitment);
+ coin->che.details.deposit.hac = cdd->h_age_commitment;
+ coin->che.details.deposit.deposit_fee = coin->denom_pub->fees.deposit;
+ }
+
+ GNUNET_assert (NULL == ds->dh);
+ {
+ struct TALER_EXCHANGE_DepositContractDetail dcd = {
+ .wire_deadline = ds->wire_deadline,
+ .merchant_payto_uri = payto_uri,
+ .wire_salt = wire_salt,
+ .h_contract_terms = h_contract_terms,
+ .policy_details = NULL /* FIXME #7270-OEC */,
+ .wallet_timestamp = ds->wallet_timestamp,
+ .merchant_pub = merchant_pub,
+ .refund_deadline = ds->refund_deadline
+ };
+
+ ds->dh = TALER_EXCHANGE_batch_deposit (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ TALER_TESTING_get_keys (is),
+ &dcd,
+ ds->num_coins,
+ cdds,
+ &batch_deposit_cb,
+ ds,
+ &ec);
+ }
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not create deposit with EC %d\n",
+ (int) ec);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "batch-deposit" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct BatchDepositState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+batch_deposit_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct BatchDepositState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_batch_deposit_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ if (NULL != ds->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (ds->retry_task);
+ ds->retry_task = NULL;
+ }
+ for (unsigned int i = 0; i<ds->num_coins; i++)
+ GNUNET_free (ds->coins[i].coin_reference);
+ GNUNET_free (ds->coins);
+ json_decref (ds->wire_details);
+ json_decref (ds->contract_terms);
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data from a "batch-deposit" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+batch_deposit_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct BatchDepositState *ds = cls;
+ const struct Coin *coin = &ds->coins[index];
+ /* Will point to coin cmd internals. */
+ const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
+ struct TALER_CoinSpendPublicKeyP coin_spent_pub;
+ const struct TALER_AgeCommitmentProof *age_commitment_proof;
+
+ if (index >= ds->num_coins)
+ {
+ GNUNET_break (0);
+ return GNUNET_NO;
+ }
+ if (NULL == coin->coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return GNUNET_NO;
+ }
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin->coin_cmd,
+ coin->coin_idx,
+ &coin_spent_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_age_commitment_proof (coin->coin_cmd,
+ coin->coin_idx,
+ &age_commitment_proof)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return GNUNET_NO;
+ }
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_spent_priv->eddsa_priv,
+ &coin_spent_pub.eddsa_pub);
+
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ /* First two traits are only available if
+ ds->traits is #GNUNET_YES */
+ TALER_TESTING_make_trait_exchange_pub (0,
+ &ds->exchange_pub),
+ TALER_TESTING_make_trait_exchange_sig (0,
+ &ds->exchange_sig),
+ /* These traits are always available */
+ TALER_TESTING_make_trait_wire_details (ds->wire_details),
+ TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
+ TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv),
+ TALER_TESTING_make_trait_age_commitment_proof (index,
+ age_commitment_proof),
+ TALER_TESTING_make_trait_coin_history (index,
+ &coin->che),
+ TALER_TESTING_make_trait_coin_pub (index,
+ &coin_spent_pub),
+ TALER_TESTING_make_trait_denom_pub (index,
+ coin->denom_pub),
+ TALER_TESTING_make_trait_coin_priv (index,
+ coin_spent_priv),
+ TALER_TESTING_make_trait_coin_sig (index,
+ &coin->coin_sig),
+ TALER_TESTING_make_trait_deposit_amount (index,
+ &coin->amount),
+ TALER_TESTING_make_trait_deposit_fee_amount (index,
+ &coin->deposit_fee),
+ TALER_TESTING_make_trait_timestamp (index,
+ &ds->exchange_timestamp),
+ TALER_TESTING_make_trait_wire_deadline (index,
+ &ds->wire_deadline),
+ TALER_TESTING_make_trait_refund_deadline (index,
+ &ds->refund_deadline),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait ((ds->deposit_succeeded)
+ ? traits
+ : &traits[2],
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_batch_deposit (const char *label,
+ const char *target_account_payto,
+ const char *contract_terms,
+ struct GNUNET_TIME_Relative refund_deadline,
+ unsigned int expected_response_code,
+ ...)
+{
+ struct BatchDepositState *ds;
+ va_list ap;
+ unsigned int num_coins = 0;
+ const char *ref;
+
+ va_start (ap,
+ expected_response_code);
+ while (NULL != (ref = va_arg (ap,
+ const char *)))
+ {
+ GNUNET_assert (NULL != va_arg (ap,
+ const char *));
+ num_coins++;
+ }
+ va_end (ap);
+
+ ds = GNUNET_new (struct BatchDepositState);
+ ds->num_coins = num_coins;
+ ds->coins = GNUNET_new_array (num_coins,
+ struct Coin);
+ num_coins = 0;
+ va_start (ap,
+ expected_response_code);
+ while (NULL != (ref = va_arg (ap,
+ const char *)))
+ {
+ struct Coin *coin = &ds->coins[num_coins++];
+ const char *amount = va_arg (ap,
+ const char *);
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_parse_coin_reference (ref,
+ &coin->coin_reference,
+ &coin->coin_idx));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (amount,
+ &coin->amount));
+ }
+ va_end (ap);
+
+ ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
+ GNUNET_assert (NULL != ds->wire_details);
+ ds->contract_terms = json_loads (contract_terms,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ GNUNET_CRYPTO_eddsa_key_create (&ds->merchant_priv.eddsa_priv);
+ if (NULL == ds->contract_terms)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse contract terms `%s' for CMD `%s'\n",
+ contract_terms,
+ label);
+ GNUNET_assert (0);
+ }
+ ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
+ GNUNET_assert (0 ==
+ json_object_set_new (ds->contract_terms,
+ "timestamp",
+ GNUNET_JSON_from_timestamp (
+ ds->wallet_timestamp)));
+ if (! GNUNET_TIME_relative_is_zero (refund_deadline))
+ {
+ ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
+ GNUNET_assert (0 ==
+ json_object_set_new (ds->contract_terms,
+ "refund_deadline",
+ GNUNET_JSON_from_timestamp (
+ ds->refund_deadline)));
+ }
+ ds->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &batch_deposit_run,
+ .cleanup = &batch_deposit_cleanup,
+ .traits = &batch_deposit_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_batch_deposit.c */
diff --git a/src/testing/testing_api_cmd_batch_withdraw.c b/src/testing/testing_api_cmd_batch_withdraw.c
new file mode 100644
index 000000000..1b056bdbb
--- /dev/null
+++ b/src/testing/testing_api_cmd_batch_withdraw.c
@@ -0,0 +1,557 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_batch_withdraw.c
+ * @brief implements the batch withdraw command
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <microhttpd.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_extensions.h"
+#include "taler_testing_lib.h"
+
+/**
+ * Information we track per withdrawn coin.
+ */
+struct CoinState
+{
+
+ /**
+ * String describing the denomination value we should withdraw.
+ * A corresponding denomination key must exist in the exchange's
+ * offerings. Can be NULL if @e pk is set instead.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * If @e amount is NULL, this specifies the denomination key to
+ * use. Otherwise, this will be set (by the interpreter) to the
+ * denomination PK matching @e amount.
+ */
+ struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+ /**
+ * Private key of the coin.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Public key of the coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Blinding key used during the operation.
+ */
+ union GNUNET_CRYPTO_BlindingSecretP bks;
+
+ /**
+ * Values contributed from the exchange during the
+ * withdraw protocol.
+ */
+ struct TALER_ExchangeWithdrawValues exchange_vals;
+
+ /**
+ * Set (by the interpreter) to the exchange's signature over the
+ * coin's public key.
+ */
+ struct TALER_DenominationSignature sig;
+
+ /**
+ * Private key material of the coin, set by the interpreter.
+ */
+ struct TALER_PlanchetMasterSecretP ps;
+
+ /**
+ * If age > 0, put here the corresponding age commitment with its proof and
+ * its hash, respectively.
+ */
+ struct TALER_AgeCommitmentProof age_commitment_proof;
+ struct TALER_AgeCommitmentHash h_age_commitment;
+
+ /**
+ * Reserve history entry that corresponds to this coin.
+ * Will be of type #TALER_EXCHANGE_RTT_WITHDRAWAL.
+ */
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
+
+
+};
+
+
+/**
+ * State for a "batch withdraw" CMD.
+ */
+struct BatchWithdrawState
+{
+
+ /**
+ * Which reserve should we withdraw from?
+ */
+ const char *reserve_reference;
+
+ /**
+ * Exchange base URL. Only used as offered trait.
+ */
+ char *exchange_url;
+
+ /**
+ * URI if the reserve we are withdrawing from.
+ */
+ char *reserve_payto_uri;
+
+ /**
+ * Private key of the reserve we are withdrawing from.
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Public key of the reserve we are withdrawing from.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Interpreter state (during command).
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Withdraw handle (while operation is running).
+ */
+ struct TALER_EXCHANGE_BatchWithdrawHandle *wsh;
+
+ /**
+ * Array of coin states.
+ */
+ struct CoinState *coins;
+
+ /**
+ * Set to the KYC requirement payto hash *if* the exchange replied with a
+ * request for KYC.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC.
+ */
+ uint64_t requirement_row;
+
+ /**
+ * Length of the @e coins array.
+ */
+ unsigned int num_coins;
+
+ /**
+ * Expected HTTP response code to the request.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * An age > 0 signifies age restriction is required.
+ * Same for all coins in the batch.
+ */
+ uint8_t age;
+
+ /**
+ * Force a conflict:
+ */
+ bool force_conflict;
+};
+
+
+/**
+ * "batch withdraw" operation callback; checks that the
+ * response code is expected and store the exchange signature
+ * in the state.
+ *
+ * @param cls closure.
+ * @param wr withdraw response details
+ */
+static void
+reserve_batch_withdraw_cb (void *cls,
+ const struct
+ TALER_EXCHANGE_BatchWithdrawResponse *wr)
+{
+ struct BatchWithdrawState *ws = cls;
+ struct TALER_TESTING_Interpreter *is = ws->is;
+
+ ws->wsh = NULL;
+ if (ws->expected_response_code != wr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status_with_body (is,
+ wr->hr.http_status,
+ ws->expected_response_code,
+ wr->hr.reply);
+ return;
+ }
+ switch (wr->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ for (unsigned int i = 0; i<ws->num_coins; i++)
+ {
+ struct CoinState *cs = &ws->coins[i];
+ const struct TALER_EXCHANGE_PrivateCoinDetails *pcd
+ = &wr->details.ok.coins[i];
+
+ TALER_denom_sig_copy (&cs->sig,
+ &pcd->sig);
+ cs->coin_priv = pcd->coin_priv;
+ GNUNET_CRYPTO_eddsa_key_get_public (&cs->coin_priv.eddsa_priv,
+ &cs->coin_pub.eddsa_pub);
+
+ cs->bks = pcd->bks;
+ TALER_denom_ewv_copy (&cs->exchange_vals,
+ &pcd->exchange_vals);
+ }
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ /* nothing to check */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* nothing to check */
+ break;
+ case MHD_HTTP_CONFLICT:
+ /* TODO[oec]: Check if age-requirement is the reason */
+ break;
+ case MHD_HTTP_GONE:
+ /* theoretically could check that the key was actually */
+ break;
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ /* nothing to check */
+ ws->requirement_row
+ = wr->details.unavailable_for_legal_reasons.requirement_row;
+ ws->h_payto
+ = wr->details.unavailable_for_legal_reasons.h_payto;
+ break;
+ default:
+ /* Unsupported status code (by test harness) */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Batch withdraw test command does not support status code %u\n",
+ wr->hr.http_status);
+ GNUNET_break (0);
+ break;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ */
+static void
+batch_withdraw_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct BatchWithdrawState *ws = cls;
+ const struct TALER_EXCHANGE_Keys *keys = TALER_TESTING_get_keys (is);
+ const struct TALER_ReservePrivateKeyP *rp;
+ const struct TALER_TESTING_Command *create_reserve;
+ const struct TALER_EXCHANGE_DenomPublicKey *dpk;
+ struct TALER_EXCHANGE_WithdrawCoinInput wcis[ws->num_coins];
+ struct TALER_PlanchetMasterSecretP conflict_ps = {0};
+ struct TALER_AgeMask mask = {0};
+
+ (void) cmd;
+ ws->is = is;
+ create_reserve
+ = TALER_TESTING_interpreter_lookup_command (
+ is,
+ ws->reserve_reference);
+
+ if (NULL == create_reserve)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (create_reserve,
+ &rp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL == ws->exchange_url)
+ ws->exchange_url
+ = GNUNET_strdup (TALER_TESTING_get_exchange_url (is));
+ ws->reserve_priv = *rp;
+ GNUNET_CRYPTO_eddsa_key_get_public (&ws->reserve_priv.eddsa_priv,
+ &ws->reserve_pub.eddsa_pub);
+ ws->reserve_payto_uri
+ = TALER_reserve_make_payto (ws->exchange_url,
+ &ws->reserve_pub);
+
+ if (0 < ws->age)
+ mask = TALER_extensions_get_age_restriction_mask ();
+
+ if (ws->force_conflict)
+ TALER_planchet_master_setup_random (&conflict_ps);
+
+ for (unsigned int i = 0; i<ws->num_coins; i++)
+ {
+ struct CoinState *cs = &ws->coins[i];
+ struct TALER_EXCHANGE_WithdrawCoinInput *wci = &wcis[i];
+
+ if (ws->force_conflict)
+ cs->ps = conflict_ps;
+ else
+ TALER_planchet_master_setup_random (&cs->ps);
+
+ if (0 < ws->age)
+ {
+ struct GNUNET_HashCode seed = {0};
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &seed,
+ sizeof(seed));
+ TALER_age_restriction_commit (&mask,
+ ws->age,
+ &seed,
+ &cs->age_commitment_proof);
+ TALER_age_commitment_hash (&cs->age_commitment_proof.commitment,
+ &cs->h_age_commitment);
+ }
+
+
+ dpk = TALER_TESTING_find_pk (keys,
+ &cs->amount,
+ ws->age > 0);
+ if (NULL == dpk)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to determine denomination key at %s\n",
+ (NULL != cmd) ? cmd->label : "<retried command>");
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ /* We copy the denomination key, as re-querying /keys
+ * would free the old one. */
+ cs->pk = TALER_EXCHANGE_copy_denomination_key (dpk);
+ cs->reserve_history.type = TALER_EXCHANGE_RTT_WITHDRAWAL;
+ GNUNET_assert (0 <=
+ TALER_amount_add (&cs->reserve_history.amount,
+ &cs->amount,
+ &cs->pk->fees.withdraw));
+ cs->reserve_history.details.withdraw.fee = cs->pk->fees.withdraw;
+
+ wci->pk = cs->pk;
+ wci->ps = &cs->ps;
+ wci->ach = &cs->h_age_commitment;
+ }
+ ws->wsh = TALER_EXCHANGE_batch_withdraw (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ keys,
+ rp,
+ ws->num_coins,
+ wcis,
+ &reserve_batch_withdraw_cb,
+ ws);
+ if (NULL == ws->wsh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "withdraw" CMD, and possibly cancel
+ * a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+batch_withdraw_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct BatchWithdrawState *ws = cls;
+
+ if (NULL != ws->wsh)
+ {
+ TALER_TESTING_command_incomplete (ws->is,
+ cmd->label);
+ TALER_EXCHANGE_batch_withdraw_cancel (ws->wsh);
+ ws->wsh = NULL;
+ }
+ for (unsigned int i = 0; i<ws->num_coins; i++)
+ {
+ struct CoinState *cs = &ws->coins[i];
+
+ TALER_denom_ewv_free (&cs->exchange_vals);
+ TALER_denom_sig_free (&cs->sig);
+ if (NULL != cs->pk)
+ {
+ TALER_EXCHANGE_destroy_denomination_key (cs->pk);
+ cs->pk = NULL;
+ }
+ if (0 < ws->age)
+ TALER_age_commitment_proof_free (&cs->age_commitment_proof);
+ }
+ GNUNET_free (ws->coins);
+ GNUNET_free (ws->exchange_url);
+ GNUNET_free (ws->reserve_payto_uri);
+ GNUNET_free (ws);
+}
+
+
+/**
+ * Offer internal data to a "withdraw" CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+batch_withdraw_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct BatchWithdrawState *ws = cls;
+ struct CoinState *cs = &ws->coins[index];
+ struct TALER_TESTING_Trait traits[] = {
+ /* history entry MUST be first due to response code logic below! */
+ TALER_TESTING_make_trait_reserve_history (index,
+ &cs->reserve_history),
+ TALER_TESTING_make_trait_coin_priv (index,
+ &cs->coin_priv),
+ TALER_TESTING_make_trait_coin_pub (index,
+ &cs->coin_pub),
+ TALER_TESTING_make_trait_planchet_secrets (index,
+ &cs->ps),
+ TALER_TESTING_make_trait_blinding_key (index,
+ &cs->bks),
+ TALER_TESTING_make_trait_exchange_wd_value (index,
+ &cs->exchange_vals),
+ TALER_TESTING_make_trait_denom_pub (index,
+ cs->pk),
+ TALER_TESTING_make_trait_denom_sig (index,
+ &cs->sig),
+ TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub),
+ TALER_TESTING_make_trait_amounts (index,
+ &cs->amount),
+ TALER_TESTING_make_trait_legi_requirement_row (&ws->requirement_row),
+ TALER_TESTING_make_trait_h_payto (&ws->h_payto),
+ TALER_TESTING_make_trait_payto_uri (ws->reserve_payto_uri),
+ TALER_TESTING_make_trait_exchange_url (ws->exchange_url),
+ TALER_TESTING_make_trait_age_commitment_proof (index,
+ ws->age > 0 ?
+ &cs->age_commitment_proof:
+ NULL),
+ TALER_TESTING_make_trait_h_age_commitment (index,
+ ws->age > 0 ?
+ &cs->h_age_commitment :
+ NULL),
+ TALER_TESTING_trait_end ()
+ };
+
+ if (index >= ws->num_coins)
+ return GNUNET_NO;
+ return TALER_TESTING_get_trait ((ws->expected_response_code == MHD_HTTP_OK)
+ ? &traits[0] /* we have reserve history */
+ : &traits[1], /* skip reserve history */
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_batch_withdraw_with_conflict (
+ const char *label,
+ const char *reserve_reference,
+ bool conflict,
+ uint8_t age,
+ unsigned int expected_response_code,
+ const char *amount,
+ ...)
+{
+ struct BatchWithdrawState *ws;
+ unsigned int cnt;
+ va_list ap;
+
+ ws = GNUNET_new (struct BatchWithdrawState);
+ ws->age = age;
+ ws->reserve_reference = reserve_reference;
+ ws->expected_response_code = expected_response_code;
+ ws->force_conflict = conflict;
+
+ cnt = 1;
+ va_start (ap,
+ amount);
+ while (NULL != (va_arg (ap,
+ const char *)))
+ cnt++;
+ ws->num_coins = cnt;
+ ws->coins = GNUNET_new_array (cnt,
+ struct CoinState);
+ va_end (ap);
+ va_start (ap,
+ amount);
+ for (unsigned int i = 0; i<ws->num_coins; i++)
+ {
+ struct CoinState *cs = &ws->coins[i];
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &cs->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %s\n",
+ amount,
+ label);
+ GNUNET_assert (0);
+ }
+ /* move on to next vararg! */
+ amount = va_arg (ap,
+ const char *);
+ }
+ GNUNET_assert (NULL == amount);
+ va_end (ap);
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &batch_withdraw_run,
+ .cleanup = &batch_withdraw_cleanup,
+ .traits = &batch_withdraw_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_batch_withdraw.c */
diff --git a/src/testing/testing_api_cmd_change_auth.c b/src/testing/testing_api_cmd_change_auth.c
deleted file mode 100644
index fdf5d3591..000000000
--- a/src/testing/testing_api_cmd_change_auth.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- This file is part of TALER
- (C) 2021 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_change_auth.c
- * @brief command(s) to change CURL context authorization header
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "authchange" CMD.
- */
-struct AuthchangeState
-{
-
- /**
- * What is the new authorization token to send?
- */
- const char *auth_token;
-};
-
-
-/**
- * No traits to offer, just provide a stub to be called when
- * some CMDs iterates through the list of all the commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the trait to return.
- * @return #GNUNET_OK on success.
- */
-static int
-authchange_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- return GNUNET_NO;
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-authchange_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct AuthchangeState *ss = cls;
-
- if (NULL != is->ctx)
- {
- GNUNET_CURL_fini (is->ctx);
- is->ctx = NULL;
- }
- if (NULL != is->rc)
- {
- GNUNET_CURL_gnunet_rc_destroy (is->rc);
- is->rc = NULL;
- }
- is->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
- &is->rc);
- GNUNET_CURL_enable_async_scope_header (is->ctx,
- "Taler-Correlation-Id");
- GNUNET_assert (NULL != is->ctx);
- is->rc = GNUNET_CURL_gnunet_rc_create (is->ctx);
- if (NULL != ss->auth_token)
- {
- char *authorization;
-
- GNUNET_asprintf (&authorization,
- "%s: %s",
- MHD_HTTP_HEADER_AUTHORIZATION,
- ss->auth_token);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CURL_append_header (is->ctx,
- authorization));
- GNUNET_free (authorization);
- }
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state from a "authchange" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-authchange_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct AuthchangeState *ss = cls;
-
- (void) cmd;
- GNUNET_free (ss);
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_set_authorization (const char *label,
- const char *auth_token)
-{
- struct AuthchangeState *ss;
-
- ss = GNUNET_new (struct AuthchangeState);
- ss->auth_token = auth_token;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ss,
- .label = label,
- .run = &authchange_run,
- .cleanup = &authchange_cleanup,
- .traits = &authchange_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_change_auth.c */
diff --git a/src/testing/testing_api_cmd_check_aml_decision.c b/src/testing/testing_api_cmd_check_aml_decision.c
new file mode 100644
index 000000000..fa0981e0d
--- /dev/null
+++ b/src/testing/testing_api_cmd_check_aml_decision.c
@@ -0,0 +1,270 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_check_aml_decision.c
+ * @brief command for testing /management/XXX
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "check_aml_decision" CMD.
+ */
+struct AmlCheckState
+{
+
+ /**
+ * Handle while operation is running.
+ */
+ struct TALER_EXCHANGE_LookupAmlDecision *dh;
+
+ /**
+ * Our interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Reference to command to previous set officer.
+ */
+ const char *ref_officer;
+
+ /**
+ * Reference to command to the previous set AML status operation.
+ */
+ const char *ref_operation;
+
+ /**
+ * Expected HTTP status.
+ */
+ unsigned int expected_http_status;
+
+};
+
+
+/**
+ * Callback to analyze the /aml/$OFFICER_PUB/$decision/$H_PAYTO response, just used to check
+ * if the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param adr response details
+ */
+static void
+check_aml_decision_cb (void *cls,
+ const struct TALER_EXCHANGE_AmlDecisionResponse *adr)
+{
+ struct AmlCheckState *ds = cls;
+
+ ds->dh = NULL;
+ if (ds->expected_http_status != adr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ adr->hr.http_status,
+ ds->expected_http_status);
+ return;
+ }
+ if (MHD_HTTP_OK == adr->hr.http_status)
+ {
+ const struct TALER_TESTING_Command *ref;
+ const char *justification;
+ enum TALER_AmlDecisionState *new_state;
+ const struct TALER_Amount *amount;
+ const struct TALER_EXCHANGE_AmlDecisionDetail *oldest = NULL;
+
+ ref = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->ref_operation);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_aml_justification (ref,
+ &justification));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_aml_decision (ref,
+ &new_state));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_amount (ref,
+ &amount));
+ for (unsigned int i = 0; i<adr->details.ok.aml_history_length; i++)
+ {
+ const struct TALER_EXCHANGE_AmlDecisionDetail *aml_history
+ = &adr->details.ok.aml_history[i];
+
+ if ( (NULL == oldest) ||
+ (0 !=
+ TALER_amount_cmp (amount,
+ &oldest->new_threshold)) ||
+ (GNUNET_TIME_timestamp_cmp (oldest->decision_time,
+ >,
+ aml_history->decision_time)) )
+ oldest = aml_history;
+ }
+ if (NULL == oldest)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ if ( (oldest->new_state != *new_state) ||
+ (0 != strcmp (oldest->justification,
+ justification) ) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+check_aml_decision_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AmlCheckState *ds = cls;
+ const struct TALER_PaytoHashP *h_payto;
+ const struct TALER_AmlOfficerPrivateKeyP *officer_priv;
+ const struct TALER_TESTING_Command *ref;
+ const char *exchange_url;
+
+ (void) cmd;
+ ds->is = is;
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ ds->ref_operation);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_h_payto (ref,
+ &h_payto));
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ ds->ref_officer);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_officer_priv (ref,
+ &officer_priv));
+ ds->dh = TALER_EXCHANGE_lookup_aml_decision (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ h_payto,
+ officer_priv,
+ true, /* history */
+ &check_aml_decision_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "check_aml_decision" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct AmlCheckState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+check_aml_decision_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AmlCheckState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_lookup_aml_decision_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ GNUNET_free (ds);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_aml_decision (
+ const char *label,
+ const char *ref_officer,
+ const char *ref_operation,
+ unsigned int expected_http_status)
+{
+ struct AmlCheckState *ds;
+
+ ds = GNUNET_new (struct AmlCheckState);
+ ds->ref_officer = ref_officer;
+ ds->ref_operation = ref_operation;
+ ds->expected_http_status = expected_http_status;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &check_aml_decision_run,
+ .cleanup = &check_aml_decision_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_check_aml_decision.c */
diff --git a/src/testing/testing_api_cmd_check_aml_decisions.c b/src/testing/testing_api_cmd_check_aml_decisions.c
new file mode 100644
index 000000000..c8c2ec3f5
--- /dev/null
+++ b/src/testing/testing_api_cmd_check_aml_decisions.c
@@ -0,0 +1,204 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_check_aml_decisions.c
+ * @brief command for testing /aml/$OFFICER/decisions/$FILTER
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "check_aml_decision" CMD.
+ */
+struct AmlCheckState
+{
+
+ /**
+ * Handle while operation is running.
+ */
+ struct TALER_EXCHANGE_LookupAmlDecisions *dh;
+
+ /**
+ * Our interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Reference to command to previous set officer.
+ */
+ const char *ref_officer;
+
+ /**
+ * Which states to filter by.
+ */
+ enum TALER_AmlDecisionState filter;
+
+ /**
+ * Expected HTTP status.
+ */
+ unsigned int expected_http_status;
+
+};
+
+
+/**
+ * Callback to analyze the /aml/$OFFICER_PUB/$decisions/$FILTER response, just used to check
+ * if the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param adr response details
+ */
+static void
+check_aml_decisions_cb (void *cls,
+ const struct TALER_EXCHANGE_AmlDecisionsResponse *adr)
+{
+ struct AmlCheckState *ds = cls;
+
+ ds->dh = NULL;
+ if (ds->expected_http_status != adr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ adr->hr.http_status,
+ ds->expected_http_status);
+ return;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+check_aml_decisions_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AmlCheckState *ds = cls;
+ const struct TALER_AmlOfficerPrivateKeyP *officer_priv;
+ const struct TALER_TESTING_Command *ref;
+ const char *exchange_url;
+
+ (void) cmd;
+ ds->is = is;
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ ds->ref_officer);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_officer_priv (ref,
+ &officer_priv));
+ ds->dh = TALER_EXCHANGE_lookup_aml_decisions (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ INT64_MAX,
+ -1, /* return last one for testing */
+ ds->filter,
+ officer_priv,
+ &check_aml_decisions_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "check_aml_decisions" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct AmlCheckState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+check_aml_decisions_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AmlCheckState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_lookup_aml_decisions_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ GNUNET_free (ds);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_aml_decisions (
+ const char *label,
+ const char *ref_officer,
+ enum TALER_AmlDecisionState filter,
+ unsigned int expected_http_status)
+{
+ struct AmlCheckState *ds;
+
+ ds = GNUNET_new (struct AmlCheckState);
+ ds->ref_officer = ref_officer;
+ ds->filter = filter;
+ ds->expected_http_status = expected_http_status;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &check_aml_decisions_run,
+ .cleanup = &check_aml_decisions_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_check_aml_decisions.c */
diff --git a/src/testing/testing_api_cmd_check_keys.c b/src/testing/testing_api_cmd_check_keys.c
deleted file mode 100644
index 5645bb9be..000000000
--- a/src/testing/testing_api_cmd_check_keys.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- This file is part of TALER
- (C) 2018, 2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_check_keys.c
- * @brief Implementation of "check keys" test command.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "check keys" CMD.
- */
-struct CheckKeysState
-{
- /**
- * This number will instruct the CMD interpreter to
- * make sure that /keys was downloaded `generation` times
- * _before_ running the very CMD logic.
- */
- unsigned int generation;
-
- /**
- * If this value is true, then the "cherry
- * picking" facility is turned off; whole /keys is
- * downloaded.
- */
- bool pull_all_keys;
-
- /**
- * Label of a command to use to derive the "last_denom_issue" date to use.
- */
- const char *last_denom_date_ref;
-
- /**
- * Last denomination date we received when doing this request.
- */
- struct GNUNET_TIME_Absolute my_denom_date;
-};
-
-
-/**
- * Run the "check keys" command.
- *
- * @param cls closure.
- * @param cmd the command currently being executed.
- * @param is the interpreter state.
- */
-static void
-check_keys_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct CheckKeysState *cks = cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "cmd `%s' (ip: %u), key generation: %d\n",
- cmd->label,
- is->ip,
- is->key_generation);
- if (is->key_generation < cks->generation)
- {
- struct GNUNET_TIME_Absolute rdate;
-
- is->working = GNUNET_NO;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Triggering GET /keys, cmd `%s'\n",
- cmd->label);
- if (NULL != cks->last_denom_date_ref)
- {
- if (0 == strcmp ("zero",
- cks->last_denom_date_ref))
- {
- TALER_LOG_DEBUG ("Forcing last_denom_date URL argument set to zero\n");
- TALER_EXCHANGE_set_last_denom (is->exchange,
- GNUNET_TIME_UNIT_ZERO_ABS);
- }
- else
- {
- const struct GNUNET_TIME_Absolute *last_denom_date;
- const struct TALER_TESTING_Command *ref;
-
- ref = TALER_TESTING_interpreter_lookup_command (is,
- cks->last_denom_date_ref);
- if (NULL == ref)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_absolute_time (ref,
- 0,
- &last_denom_date))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- TALER_LOG_DEBUG ("Forcing last_denom_date URL argument\n");
- TALER_EXCHANGE_set_last_denom (is->exchange,
- *last_denom_date);
- }
- }
-
- rdate = TALER_EXCHANGE_check_keys_current (
- is->exchange,
- cks->pull_all_keys
- ? TALER_EXCHANGE_CKF_FORCE_ALL_NOW
- : TALER_EXCHANGE_CKF_FORCE_DOWNLOAD);
- /* Redownload /keys. */
- GNUNET_break (0 ==
- rdate.abs_value_us);
- return;
- }
- {
- const struct TALER_EXCHANGE_Keys *keys;
-
- keys = TALER_EXCHANGE_get_keys (is->exchange);
- if (NULL == keys)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- cks->my_denom_date = keys->last_denom_issue_date;
- }
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-check_keys_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct CheckKeysState *cks = cls;
-
- (void) cmd;
- GNUNET_free (cks);
-}
-
-
-/**
- * Offer internal data to a "check_keys" CMD state to other
- * commands.
- *
- * @param cls closure
- * @param[out] ret result (could be anything)
- * @param trait name of the trait
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success
- */
-static int
-check_keys_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct CheckKeysState *cks = cls;
- struct TALER_TESTING_Trait traits[] = {
- /* history entry MUST be first due to response code logic below! */
- TALER_TESTING_make_trait_absolute_time (0,
- &cks->my_denom_date),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys (const char *label,
- unsigned int generation)
-{
- struct CheckKeysState *cks;
-
- cks = GNUNET_new (struct CheckKeysState);
- cks->generation = generation;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = cks,
- .label = label,
- .run = &check_keys_run,
- .cleanup = &check_keys_cleanup,
- .traits = &check_keys_traits
- };
-
- return cmd;
- }
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label,
- unsigned int generation)
-{
- struct TALER_TESTING_Command cmd
- = TALER_TESTING_cmd_check_keys (label,
- generation);
- struct CheckKeysState *cks = cmd.cls;
-
- cks->pull_all_keys = true;
- return cmd;
-}
-
-
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys_with_last_denom (
- const char *label,
- unsigned int generation,
- const char *last_denom_date_ref)
-{
- struct TALER_TESTING_Command cmd
- = TALER_TESTING_cmd_check_keys (label,
- generation);
- struct CheckKeysState *cks = cmd.cls;
- cks->last_denom_date_ref = last_denom_date_ref;
- return cmd;
-}
-
-
-/* end of testing_api_cmd_check_keys.c */
diff --git a/src/testing/testing_api_cmd_coin_history.c b/src/testing/testing_api_cmd_coin_history.c
new file mode 100644
index 000000000..a1345f67f
--- /dev/null
+++ b/src/testing/testing_api_cmd_coin_history.c
@@ -0,0 +1,609 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_coin_history.c
+ * @brief Implement the /coins/$COIN_PUB/history test command.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "history" CMD.
+ */
+struct HistoryState
+{
+
+ /**
+ * Public key of the coin being analyzed.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Label to the command which created the coin to check,
+ * needed to resort the coin key.
+ */
+ const char *coin_reference;
+
+ /**
+ * Handle to the "coin history" operation.
+ */
+ struct TALER_EXCHANGE_CoinsHistoryHandle *rsh;
+
+ /**
+ * Expected coin balance.
+ */
+ const char *expected_balance;
+
+ /**
+ * Private key of the coin being analyzed.
+ */
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+};
+
+
+/**
+ * Closure for analysis_cb().
+ */
+struct AnalysisContext
+{
+ /**
+ * Coin public key we are looking at.
+ */
+ const struct TALER_CoinSpendPublicKeyP *coin_pub;
+
+ /**
+ * Length of the @e history array.
+ */
+ unsigned int history_length;
+
+ /**
+ * Array of history items to match.
+ */
+ const struct TALER_EXCHANGE_CoinHistoryEntry *history;
+
+ /**
+ * Array of @e history_length of matched entries.
+ */
+ bool *found;
+
+ /**
+ * Set to true if an entry could not be found.
+ */
+ bool failure;
+};
+
+
+/**
+ * Compare @a h1 and @a h2.
+ *
+ * @param h1 a history entry
+ * @param h2 a history entry
+ * @return 0 if @a h1 and @a h2 are equal
+ */
+static int
+history_entry_cmp (
+ const struct TALER_EXCHANGE_CoinHistoryEntry *h1,
+ const struct TALER_EXCHANGE_CoinHistoryEntry *h2)
+{
+ if (h1->type != h2->type)
+ return 1;
+ if (0 != TALER_amount_cmp (&h1->amount,
+ &h2->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Amount mismatch (%s)\n",
+ TALER_amount2s (&h1->amount));
+ return 1;
+ }
+ switch (h1->type)
+ {
+ case TALER_EXCHANGE_CTT_NONE:
+ GNUNET_break (0);
+ break;
+ case TALER_EXCHANGE_CTT_DEPOSIT:
+ if (0 != GNUNET_memcmp (&h1->details.deposit.h_contract_terms,
+ &h2->details.deposit.h_contract_terms))
+ return 1;
+ if (0 != GNUNET_memcmp (&h1->details.deposit.merchant_pub,
+ &h2->details.deposit.merchant_pub))
+ return 1;
+ if (0 != GNUNET_memcmp (&h1->details.deposit.h_wire,
+ &h2->details.deposit.h_wire))
+ return 1;
+ if (0 != GNUNET_memcmp (&h1->details.deposit.sig,
+ &h2->details.deposit.sig))
+ return 1;
+ return 0;
+ case TALER_EXCHANGE_CTT_MELT:
+ if (0 != GNUNET_memcmp (&h1->details.melt.h_age_commitment,
+ &h2->details.melt.h_age_commitment))
+ return 1;
+ /* Note: most other fields are not initialized
+ in the trait as they are hard to extract from
+ the API */
+ return 0;
+ case TALER_EXCHANGE_CTT_REFUND:
+ if (0 != GNUNET_memcmp (&h1->details.refund.sig,
+ &h2->details.refund.sig))
+ return 1;
+ return 0;
+ case TALER_EXCHANGE_CTT_RECOUP:
+ if (0 != GNUNET_memcmp (&h1->details.recoup.coin_sig,
+ &h2->details.recoup.coin_sig))
+ return 1;
+ /* Note: exchange_sig, exchange_pub and timestamp are
+ fundamentally not available in the initiating command */
+ return 0;
+ case TALER_EXCHANGE_CTT_RECOUP_REFRESH:
+ if (0 != GNUNET_memcmp (&h1->details.recoup_refresh.coin_sig,
+ &h2->details.recoup_refresh.coin_sig))
+ return 1;
+ /* Note: exchange_sig, exchange_pub and timestamp are
+ fundamentally not available in the initiating command */
+ return 0;
+ case TALER_EXCHANGE_CTT_OLD_COIN_RECOUP:
+ if (0 != GNUNET_memcmp (&h1->details.old_coin_recoup.new_coin_pub,
+ &h2->details.old_coin_recoup.new_coin_pub))
+ return 1;
+ /* Note: exchange_sig, exchange_pub and timestamp are
+ fundamentally not available in the initiating command */
+ return 0;
+ case TALER_EXCHANGE_CTT_PURSE_DEPOSIT:
+ /* coin_sig is not initialized */
+ if (0 != GNUNET_memcmp (&h1->details.purse_deposit.purse_pub,
+ &h2->details.purse_deposit.purse_pub))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Purse public key mismatch\n");
+ return 1;
+ }
+ if (0 != strcmp (h1->details.purse_deposit.exchange_base_url,
+ h2->details.purse_deposit.exchange_base_url))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Exchange base URL mismatch (%s/%s)\n",
+ h1->details.purse_deposit.exchange_base_url,
+ h2->details.purse_deposit.exchange_base_url);
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+ case TALER_EXCHANGE_CTT_PURSE_REFUND:
+ /* NOTE: not supported yet (trait not returned) */
+ return 0;
+ case TALER_EXCHANGE_CTT_RESERVE_OPEN_DEPOSIT:
+ /* NOTE: not supported yet (trait not returned) */
+ if (0 != GNUNET_memcmp (&h1->details.reserve_open_deposit.coin_sig,
+ &h2->details.reserve_open_deposit.coin_sig))
+ return 1;
+ return 0;
+ }
+ GNUNET_assert (0);
+ return -1;
+}
+
+
+/**
+ * Check if @a cmd changed the coin, if so, find the
+ * entry in our history and set the respective index in found
+ * to true. If the entry is not found, set failure.
+ *
+ * @param cls our `struct AnalysisContext *`
+ * @param cmd command to analyze for impact on history
+ */
+static void
+analyze_command (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AnalysisContext *ac = cls;
+ const struct TALER_CoinSpendPublicKeyP *coin_pub = ac->coin_pub;
+ const struct TALER_EXCHANGE_CoinHistoryEntry *history = ac->history;
+ unsigned int history_length = ac->history_length;
+ bool *found = ac->found;
+
+ if (TALER_TESTING_cmd_is_batch (cmd))
+ {
+ struct TALER_TESTING_Command *cur;
+ struct TALER_TESTING_Command *bcmd;
+
+ cur = TALER_TESTING_cmd_batch_get_current (cmd);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_batch_cmds (cmd,
+ &bcmd))
+ {
+ GNUNET_break (0);
+ ac->failure = true;
+ return;
+ }
+ for (unsigned int i = 0; NULL != bcmd[i].label; i++)
+ {
+ struct TALER_TESTING_Command *step = &bcmd[i];
+
+ analyze_command (ac,
+ step);
+ if (ac->failure)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Entry for batch step `%s' missing in history\n",
+ step->label);
+ return;
+ }
+ if (step == cur)
+ break; /* if *we* are in a batch, make sure not to analyze commands past 'now' */
+ }
+ return;
+ }
+
+ for (unsigned int j = 0; true; j++)
+ {
+ const struct TALER_CoinSpendPublicKeyP *rp;
+ const struct TALER_EXCHANGE_CoinHistoryEntry *he;
+ bool matched = false;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_pub (cmd,
+ j,
+ &rp))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Command `%s#%u' has no public key for a coin\n",
+ cmd->label,
+ j);
+ break; /* command does nothing for coins */
+ }
+ if (0 !=
+ GNUNET_memcmp (rp,
+ coin_pub))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Command `%s#%u' is about another coin\n",
+ cmd->label,
+ j);
+ continue; /* command affects some _other_ coin */
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_history (cmd,
+ j,
+ &he))
+ {
+ /* NOTE: only for debugging... */
+ if (0 == j)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Command `%s' has the coin_pub, but lacks coin history trait\n",
+ cmd->label);
+ return; /* command does nothing for coins */
+ }
+ for (unsigned int i = 0; i<history_length; i++)
+ {
+ if (found[i])
+ continue; /* already found, skip */
+ if (0 ==
+ history_entry_cmp (he,
+ &history[i]))
+ {
+ found[i] = true;
+ matched = true;
+ break;
+ }
+ }
+ if (! matched)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Command `%s' coin history entry #%u not found\n",
+ cmd->label,
+ j);
+ ac->failure = true;
+ return;
+ }
+ }
+}
+
+
+/**
+ * Check that the coin balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+coin_history_cb (void *cls,
+ const struct TALER_EXCHANGE_CoinHistory *rs)
+{
+ struct HistoryState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+ struct TALER_Amount eb;
+ unsigned int hlen;
+
+ ss->rsh = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ss->is,
+ rs->hr.http_status,
+ ss->expected_response_code);
+ return;
+ }
+ if (MHD_HTTP_OK != rs->hr.http_status)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (ss->expected_balance,
+ &eb));
+
+ if (0 != TALER_amount_cmp (&eb,
+ &rs->details.ok.balance))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected balance for coin: %s\n",
+ TALER_amount_to_string (&rs->details.ok.balance));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected balance of: %s\n",
+ TALER_amount_to_string (&eb));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ hlen = json_array_size (rs->details.ok.history);
+ {
+ bool found[GNUNET_NZL (hlen)];
+ struct TALER_EXCHANGE_CoinHistoryEntry rhist[GNUNET_NZL (hlen)];
+ struct AnalysisContext ac = {
+ .coin_pub = &ss->coin_pub,
+ .history = rhist,
+ .history_length = hlen,
+ .found = found
+ };
+ const struct TALER_EXCHANGE_DenomPublicKey *dk;
+ struct TALER_Amount total_in;
+ struct TALER_Amount total_out;
+ struct TALER_Amount hbal;
+
+ dk = TALER_EXCHANGE_get_denomination_key_by_hash (
+ TALER_TESTING_get_keys (is),
+ &rs->details.ok.h_denom_pub);
+ memset (found,
+ 0,
+ sizeof (found));
+ memset (rhist,
+ 0,
+ sizeof (rhist));
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_parse_coin_history (
+ TALER_TESTING_get_keys (is),
+ dk,
+ rs->details.ok.history,
+ &ss->coin_pub,
+ &total_in,
+ &total_out,
+ hlen,
+ rhist))
+ {
+ GNUNET_break (0);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (0 >
+ TALER_amount_subtract (&hbal,
+ &total_in,
+ &total_out))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Coin credits: %s\n",
+ TALER_amount2s (&total_in));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Coin debits: %s\n",
+ TALER_amount2s (&total_out));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (0 != TALER_amount_cmp (&hbal,
+ &rs->details.ok.balance))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ (void) ac;
+ TALER_TESTING_iterate (is,
+ true,
+ &analyze_command,
+ &ac);
+ if (ac.failure)
+ {
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+#if 1
+ for (unsigned int i = 0; i<hlen; i++)
+ {
+ if (found[i])
+ continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "History entry at index %u of type %d not justified by command history\n",
+ i,
+ rs->details.ok.history[i].type);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+#endif
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+history_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct HistoryState *ss = cls;
+ const struct TALER_TESTING_Command *create_coin;
+ char *cref;
+ unsigned int idx;
+
+ ss->is = is;
+ GNUNET_assert (
+ GNUNET_OK ==
+ TALER_TESTING_parse_coin_reference (
+ ss->coin_reference,
+ &cref,
+ &idx));
+ create_coin
+ = TALER_TESTING_interpreter_lookup_command (is,
+ cref);
+ if (NULL == create_coin)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (create_coin,
+ idx,
+ &ss->coin_priv))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find coin_priv for history query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ss->coin_priv->eddsa_priv,
+ &ss->coin_pub.eddsa_pub);
+ ss->rsh = TALER_EXCHANGE_coins_history (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ ss->coin_priv,
+ 0,
+ &coin_history_cb,
+ ss);
+}
+
+
+/**
+ * Offer internal data from a "history" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+history_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct HistoryState *hs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_coin_pub (0,
+ &hs->coin_pub),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Cleanup the state from a "coin history" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+history_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct HistoryState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_coins_history_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_coin_history (const char *label,
+ const char *coin_reference,
+ const char *expected_balance,
+ unsigned int expected_response_code)
+{
+ struct HistoryState *ss;
+
+ GNUNET_assert (NULL != coin_reference);
+ ss = GNUNET_new (struct HistoryState);
+ ss->coin_reference = coin_reference;
+ ss->expected_balance = expected_balance;
+ ss->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &history_run,
+ .cleanup = &history_cleanup,
+ .traits = &history_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_common.c b/src/testing/testing_api_cmd_common.c
new file mode 100644
index 000000000..2d828a2b0
--- /dev/null
+++ b/src/testing/testing_api_cmd_common.c
@@ -0,0 +1,64 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_common.c
+ * @brief common functions for commands
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_testing_lib.h"
+
+
+enum GNUNET_GenericReturnValue
+TALER_TESTING_parse_coin_reference (
+ const char *coin_reference,
+ char **cref,
+ unsigned int *idx)
+{
+ const char *index;
+ char dummy;
+
+ /* We allow command references of the form "$LABEL#$INDEX" or
+ just "$LABEL", which implies the index is 0. Figure out
+ which one it is. */
+ index = strchr (coin_reference, '#');
+ if (NULL == index)
+ {
+ *idx = 0;
+ *cref = GNUNET_strdup (coin_reference);
+ return GNUNET_OK;
+ }
+ *cref = GNUNET_strndup (coin_reference,
+ index - coin_reference);
+ if (1 != sscanf (index + 1,
+ "%u%c",
+ idx,
+ &dummy))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Numeric index (not `%s') required after `#' in command reference of command in %s:%u\n",
+ index,
+ __FILE__,
+ __LINE__);
+ GNUNET_free (*cref);
+ *cref = NULL;
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
diff --git a/src/testing/testing_api_cmd_contract_get.c b/src/testing/testing_api_cmd_contract_get.c
new file mode 100644
index 000000000..fa83d83f7
--- /dev/null
+++ b/src/testing/testing_api_cmd_contract_get.c
@@ -0,0 +1,316 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_contract_get.c
+ * @brief command for testing GET /contracts/$CPUB
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "contract get" CMD.
+ */
+struct ContractGetState
+{
+
+ /**
+ * JSON string describing the resulting contract.
+ */
+ json_t *contract_terms;
+
+ /**
+ * Private key to decrypt the contract.
+ */
+ struct TALER_ContractDiffiePrivateP contract_priv;
+
+ /**
+ * Set to the returned merge key.
+ */
+ struct TALER_PurseMergePrivateKeyP merge_priv;
+
+ /**
+ * Public key of the purse.
+ */
+ struct TALER_PurseContractPublicKeyP purse_pub;
+
+ /**
+ * Reference to the command that uploaded the contract.
+ */
+ const char *contract_ref;
+
+ /**
+ * ContractGet handle while operation is running.
+ */
+ struct TALER_EXCHANGE_ContractsGetHandle *dh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * True if this is for a 'merge' operation,
+ * 'false' if this is for a 'deposit' operation.
+ */
+ bool merge;
+
+};
+
+
+/**
+ * Callback to analyze the /contracts/$CPUB response, just used to check if
+ * the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param dr get response details
+ */
+static void
+get_cb (void *cls,
+ const struct TALER_EXCHANGE_ContractGetResponse *dr)
+{
+ struct ContractGetState *ds = cls;
+ const struct TALER_TESTING_Command *ref;
+
+ ds->dh = NULL;
+ if (ds->expected_response_code != dr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ dr->hr.http_status,
+ ds->expected_response_code);
+ return;
+ }
+ ref = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->contract_ref);
+ GNUNET_assert (NULL != ref);
+ if (MHD_HTTP_OK == dr->hr.http_status)
+ {
+ const struct TALER_PurseMergePrivateKeyP *mp;
+ const json_t *ct;
+
+ ds->purse_pub = dr->details.ok.purse_pub;
+ if (ds->merge)
+ {
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_merge_priv (ref,
+ &mp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ ds->contract_terms =
+ TALER_CRYPTO_contract_decrypt_for_merge (
+ &ds->contract_priv,
+ &ds->purse_pub,
+ dr->details.ok.econtract,
+ dr->details.ok.econtract_size,
+ &ds->merge_priv);
+ if (0 !=
+ GNUNET_memcmp (mp,
+ &ds->merge_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ }
+ else
+ {
+ ds->contract_terms =
+ TALER_CRYPTO_contract_decrypt_for_deposit (
+ &ds->contract_priv,
+ dr->details.ok.econtract,
+ dr->details.ok.econtract_size);
+ }
+ if (NULL == ds->contract_terms)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_contract_terms (ref,
+ &ct))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ if (1 != /* 1: equal, 0: not equal */
+ json_equal (ct,
+ ds->contract_terms))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+get_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ContractGetState *ds = cls;
+ const struct TALER_ContractDiffiePrivateP *contract_priv;
+ const struct TALER_TESTING_Command *ref;
+ const char *exchange_url;
+
+ (void) cmd;
+ ds->is = is;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ ref = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->contract_ref);
+ GNUNET_assert (NULL != ref);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_contract_priv (ref,
+ &contract_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ ds->contract_priv = *contract_priv;
+ ds->dh = TALER_EXCHANGE_contract_get (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ contract_priv,
+ &get_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not GET contract\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "get" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct ContractGetState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+get_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ContractGetState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_contract_get_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ json_decref (ds->contract_terms);
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data from a "get" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+get_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct ContractGetState *ds = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
+ TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
+ TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
+ TALER_TESTING_trait_end ()
+ };
+
+ /* skip 'merge_priv' if we are in 'merge' mode */
+ return TALER_TESTING_get_trait (&traits[ds->merge ? 0 : 1],
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_contract_get (
+ const char *label,
+ unsigned int expected_http_status,
+ bool for_merge,
+ const char *contract_ref)
+{
+ struct ContractGetState *ds;
+
+ ds = GNUNET_new (struct ContractGetState);
+ ds->expected_response_code = expected_http_status;
+ ds->contract_ref = contract_ref;
+ ds->merge = for_merge;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &get_run,
+ .cleanup = &get_cleanup,
+ .traits = &get_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_contract_get.c */
diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c
index a392884a0..849c78c70 100644
--- a/src/testing/testing_api_cmd_deposit.c
+++ b/src/testing/testing_api_cmd_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2023 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
@@ -69,6 +69,11 @@ struct DepositState
unsigned int coin_index;
/**
+ * Our coin signature.
+ */
+ struct TALER_CoinSpendSignatureP coin_sig;
+
+ /**
* Wire details of who is depositing -- this would be merchant
* wire details in a normal scenario.
*/
@@ -82,7 +87,12 @@ struct DepositState
/**
* Refund deadline. Zero for no refunds.
*/
- struct GNUNET_TIME_Absolute refund_deadline;
+ struct GNUNET_TIME_Timestamp refund_deadline;
+
+ /**
+ * Wire deadline.
+ */
+ struct GNUNET_TIME_Timestamp wire_deadline;
/**
* Set (by the interpreter) to a fresh private key. This
@@ -93,12 +103,17 @@ struct DepositState
/**
* Deposit handle while operation is running.
*/
- struct TALER_EXCHANGE_DepositHandle *dh;
+ struct TALER_EXCHANGE_BatchDepositHandle *dh;
+
+ /**
+ * Denomination public key of the deposited coin.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
/**
* Timestamp of the /deposit operation in the wallet (contract signing time).
*/
- struct GNUNET_TIME_Absolute wallet_timestamp;
+ struct GNUNET_TIME_Timestamp wallet_timestamp;
/**
* Interpreter state.
@@ -126,15 +141,21 @@ struct DepositState
unsigned int do_retry;
/**
- * Set to #GNUNET_YES if the /deposit succeeded
+ * Set to true if the /deposit succeeded
* and we now can provide the resulting traits.
*/
- int deposit_succeeded;
+ bool deposit_succeeded;
+
+ /**
+ * Expected entry in the coin history created by this
+ * operation.
+ */
+ struct TALER_EXCHANGE_CoinHistoryEntry che;
/**
* When did the exchange receive the deposit?
*/
- struct GNUNET_TIME_Absolute exchange_timestamp;
+ struct GNUNET_TIME_Timestamp exchange_timestamp;
/**
* Signing key used by the exchange to sign the
@@ -160,7 +181,7 @@ struct DepositState
* When we're referencing another deposit operation,
* this will only be set after the command has been started.
*/
- int command_initialized;
+ bool command_initialized;
/**
* Reference to fetch the merchant private key from.
@@ -194,8 +215,7 @@ do_retry (void *cls)
struct DepositState *ds = cls;
ds->retry_task = NULL;
- ds->is->commands[ds->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (ds->is);
deposit_run (ds,
NULL,
ds->is);
@@ -207,43 +227,36 @@ do_retry (void *cls)
* check if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
- * @param exchange_timestamp when did the exchange receive the deposit permission
- * @param exchange_sig signature provided by the exchange
- * (NULL on errors)
- * @param exchange_pub public key of the exchange,
- * used for signing the response.
+ * @param dr deposit response details
*/
static void
deposit_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct GNUNET_TIME_Absolute exchange_timestamp,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
+ const struct TALER_EXCHANGE_BatchDepositResult *dr)
{
struct DepositState *ds = cls;
ds->dh = NULL;
- if (ds->expected_response_code != hr->http_status)
+ if (ds->expected_response_code != dr->hr.http_status)
{
if (0 != ds->do_retry)
{
ds->do_retry--;
- if ( (0 == hr->http_status) ||
- (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
+ if ( (0 == dr->hr.http_status) ||
+ (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Retrying deposit failed with %u/%d\n",
- hr->http_status,
- (int) hr->ec);
+ dr->hr.http_status,
+ (int) dr->hr.ec);
/* on DB conflicts, do not use backoff */
- if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
+ if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec)
ds->backoff = GNUNET_TIME_UNIT_ZERO;
else
ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff,
MAX_BACKOFF);
- ds->is->commands[ds->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (ds->is);
+ GNUNET_assert (NULL == ds->retry_task);
ds->retry_task
= GNUNET_SCHEDULER_add_delayed (ds->backoff,
&do_retry,
@@ -251,24 +264,20 @@ deposit_cb (void *cls,
return;
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ds->is);
+ TALER_TESTING_unexpected_status_with_body (
+ ds->is,
+ dr->hr.http_status,
+ ds->expected_response_code,
+ dr->hr.reply);
+
return;
}
- if (MHD_HTTP_OK == hr->http_status)
+ if (MHD_HTTP_OK == dr->hr.http_status)
{
- ds->deposit_succeeded = GNUNET_YES;
- ds->exchange_timestamp = exchange_timestamp;
- ds->exchange_pub = *exchange_pub;
- ds->exchange_sig = *exchange_sig;
+ ds->deposit_succeeded = true;
+ ds->exchange_timestamp = dr->details.ok.deposit_timestamp;
+ ds->exchange_pub = *dr->details.ok.exchange_pub;
+ ds->exchange_sig = *dr->details.ok.exchange_sig;
}
TALER_TESTING_interpreter_next (ds->is);
}
@@ -290,16 +299,46 @@ deposit_run (void *cls,
const struct TALER_TESTING_Command *coin_cmd;
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
struct TALER_CoinSpendPublicKeyP coin_pub;
- const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+ const struct TALER_AgeCommitmentHash *phac;
const struct TALER_DenominationSignature *denom_pub_sig;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct GNUNET_TIME_Absolute wire_deadline;
struct TALER_MerchantPublicKeyP merchant_pub;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_PrivateContractHashP h_contract_terms;
enum TALER_ErrorCode ec;
+ struct TALER_WireSaltP wire_salt;
+ const char *payto_uri;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("payto_uri",
+ &payto_uri),
+ GNUNET_JSON_spec_fixed_auto ("salt",
+ &wire_salt),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *exchange_url
+ = TALER_TESTING_get_exchange_url (is);
(void) cmd;
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
ds->is = is;
+ if (! GNUNET_TIME_absolute_is_zero (ds->refund_deadline.abs_time))
+ {
+ struct GNUNET_TIME_Relative refund_deadline;
+
+ refund_deadline
+ = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline.abs_time);
+ ds->wire_deadline
+ = GNUNET_TIME_relative_to_timestamp (
+ GNUNET_TIME_relative_multiply (refund_deadline,
+ 2));
+ }
+ else
+ {
+ ds->refund_deadline = ds->wallet_timestamp;
+ ds->wire_deadline = GNUNET_TIME_timestamp_get ();
+ }
if (NULL != ds->deposit_reference)
{
/* We're copying another deposit operation, initialize here. */
@@ -318,12 +357,14 @@ deposit_run (void *cls,
ds->coin_reference = ods->coin_reference;
ds->coin_index = ods->coin_index;
ds->wire_details = json_incref (ods->wire_details);
+ GNUNET_assert (NULL != ds->wire_details);
ds->contract_terms = json_incref (ods->contract_terms);
ds->wallet_timestamp = ods->wallet_timestamp;
ds->refund_deadline = ods->refund_deadline;
+ ds->wire_deadline = ods->wire_deadline;
ds->amount = ods->amount;
ds->merchant_priv = ods->merchant_priv;
- ds->command_initialized = GNUNET_YES;
+ ds->command_initialized = true;
}
else if (NULL != ds->merchant_priv_reference)
{
@@ -341,7 +382,6 @@ deposit_run (void *cls,
}
if ( (GNUNET_OK !=
TALER_TESTING_get_trait_merchant_priv (cmd,
- 0,
&merchant_priv)) )
{
GNUNET_break (0);
@@ -350,6 +390,19 @@ deposit_run (void *cls,
}
ds->merchant_priv = *merchant_priv;
}
+ GNUNET_assert (NULL != ds->wire_details);
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (ds->wire_details,
+ spec,
+ NULL, NULL))
+ {
+ json_dumpf (ds->wire_details,
+ stderr,
+ JSON_INDENT (2));
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
GNUNET_assert (ds->coin_reference);
coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
ds->coin_reference);
@@ -365,9 +418,13 @@ deposit_run (void *cls,
ds->coin_index,
&coin_priv)) ||
(GNUNET_OK !=
+ TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
+ ds->coin_index,
+ &phac)) ||
+ (GNUNET_OK !=
TALER_TESTING_get_trait_denom_pub (coin_cmd,
ds->coin_index,
- &denom_pub)) ||
+ &ds->denom_pub)) ||
(GNUNET_OK !=
TALER_TESTING_get_trait_denom_sig (coin_cmd,
ds->coin_index,
@@ -380,58 +437,79 @@ deposit_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
- ds->deposit_fee = denom_pub->fee_deposit;
+
+ ds->deposit_fee = ds->denom_pub->fees.deposit;
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
&coin_pub.eddsa_pub);
- if (0 != ds->refund_deadline.abs_value_us)
- {
- struct GNUNET_TIME_Relative refund_deadline;
-
- refund_deadline = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline);
- wire_deadline = GNUNET_TIME_relative_to_absolute
- (GNUNET_TIME_relative_multiply (refund_deadline, 2));
- }
- else
- {
- ds->refund_deadline = ds->wallet_timestamp;
- wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_ZERO);
- }
GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv,
&merchant_pub.eddsa_pub);
- (void) GNUNET_TIME_round_abs (&wire_deadline);
{
- struct GNUNET_HashCode h_wire;
+ struct TALER_MerchantWireHashP h_wire;
GNUNET_assert (GNUNET_OK ==
TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
&h_wire));
- TALER_EXCHANGE_deposit_permission_sign (&ds->amount,
- &denom_pub->fee_deposit,
- &h_wire,
- &h_contract_terms,
- &denom_pub->h_key,
- coin_priv,
- ds->wallet_timestamp,
- &merchant_pub,
- ds->refund_deadline,
- &coin_sig);
+ TALER_wallet_deposit_sign (&ds->amount,
+ &ds->denom_pub->fees.deposit,
+ &h_wire,
+ &h_contract_terms,
+ NULL, /* wallet data hash */
+ phac,
+ NULL, /* hash of extensions */
+ &ds->denom_pub->h_key,
+ ds->wallet_timestamp,
+ &merchant_pub,
+ ds->refund_deadline,
+ coin_priv,
+ &ds->coin_sig);
+ ds->che.type = TALER_EXCHANGE_CTT_DEPOSIT;
+ ds->che.amount = ds->amount;
+ ds->che.details.deposit.h_wire = h_wire;
+ ds->che.details.deposit.h_contract_terms = h_contract_terms;
+ ds->che.details.deposit.no_h_policy = true;
+ ds->che.details.deposit.no_wallet_data_hash = true;
+ ds->che.details.deposit.wallet_timestamp = ds->wallet_timestamp;
+ ds->che.details.deposit.merchant_pub = merchant_pub;
+ ds->che.details.deposit.refund_deadline = ds->refund_deadline;
+ ds->che.details.deposit.sig = ds->coin_sig;
+ ds->che.details.deposit.no_hac = true;
+ ds->che.details.deposit.deposit_fee = ds->denom_pub->fees.deposit;
+ }
+ GNUNET_assert (NULL == ds->dh);
+ {
+ struct TALER_EXCHANGE_CoinDepositDetail cdd = {
+ .amount = ds->amount,
+ .coin_pub = coin_pub,
+ .coin_sig = ds->coin_sig,
+ .denom_sig = *denom_pub_sig,
+ .h_denom_pub = ds->denom_pub->h_key,
+ .h_age_commitment = {{{0}}},
+ };
+ struct TALER_EXCHANGE_DepositContractDetail dcd = {
+ .wire_deadline = ds->wire_deadline,
+ .merchant_payto_uri = payto_uri,
+ .wire_salt = wire_salt,
+ .h_contract_terms = h_contract_terms,
+ .wallet_timestamp = ds->wallet_timestamp,
+ .merchant_pub = merchant_pub,
+ .refund_deadline = ds->refund_deadline
+ };
+
+ if (NULL != phac)
+ cdd.h_age_commitment = *phac;
+
+ ds->dh = TALER_EXCHANGE_batch_deposit (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ TALER_TESTING_get_keys (is),
+ &dcd,
+ 1,
+ &cdd,
+ &deposit_cb,
+ ds,
+ &ec);
}
- ds->dh = TALER_EXCHANGE_deposit (is->exchange,
- &ds->amount,
- wire_deadline,
- ds->wire_details,
- &h_contract_terms,
- &coin_pub,
- denom_pub_sig,
- &denom_pub->key,
- ds->wallet_timestamp,
- &merchant_pub,
- ds->refund_deadline,
- &coin_sig,
- &deposit_cb,
- ds,
- &ec);
if (NULL == ds->dh)
{
GNUNET_break (0);
@@ -459,11 +537,9 @@ deposit_cleanup (void *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);
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_batch_deposit_cancel (ds->dh);
ds->dh = NULL;
}
if (NULL != ds->retry_task)
@@ -484,10 +560,9 @@ deposit_cleanup (void *cls,
* @param[out] ret result.
* @param trait name of the trait.
* @param index index number of the object to offer.
- *
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
deposit_traits (void *cls,
const void **ret,
const char *trait,
@@ -497,8 +572,11 @@ deposit_traits (void *cls,
const struct TALER_TESTING_Command *coin_cmd;
/* Will point to coin cmd internals. */
const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
+ struct TALER_CoinSpendPublicKeyP coin_spent_pub;
+ const struct TALER_AgeCommitmentProof *age_commitment_proof;
+ const struct TALER_AgeCommitmentHash *h_age_commitment;
- if (GNUNET_YES != ds->command_initialized)
+ if (! ds->command_initialized)
{
/* No access to traits yet. */
GNUNET_break (0);
@@ -514,40 +592,63 @@ deposit_traits (void *cls,
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))
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ ds->coin_index,
+ &coin_spent_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
+ ds->coin_index,
+ &age_commitment_proof)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
+ ds->coin_index,
+ &h_age_commitment)) )
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (ds->is);
return GNUNET_NO;
}
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_spent_priv->eddsa_priv,
+ &coin_spent_pub.eddsa_pub);
+
{
struct TALER_TESTING_Trait traits[] = {
/* First two traits are only available if
- ds->traits is #GNUNET_YES */
+ ds->traits is true */
TALER_TESTING_make_trait_exchange_pub (0,
&ds->exchange_pub),
TALER_TESTING_make_trait_exchange_sig (0,
&ds->exchange_sig),
/* These traits are always available */
+ TALER_TESTING_make_trait_coin_history (0,
+ &ds->che),
TALER_TESTING_make_trait_coin_priv (0,
coin_spent_priv),
- TALER_TESTING_make_trait_wire_details (0,
- ds->wire_details),
- TALER_TESTING_make_trait_contract_terms (0,
- ds->contract_terms),
- TALER_TESTING_make_trait_merchant_priv (0,
- &ds->merchant_priv),
- TALER_TESTING_make_trait_amount_obj (
- TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_VALUE,
- &ds->amount),
- TALER_TESTING_make_trait_amount_obj (
- TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_FEE,
- &ds->deposit_fee),
- TALER_TESTING_make_trait_absolute_time (0,
- &ds->exchange_timestamp),
+ TALER_TESTING_make_trait_coin_pub (0,
+ &coin_spent_pub),
+ TALER_TESTING_make_trait_denom_pub (0,
+ ds->denom_pub),
+ TALER_TESTING_make_trait_coin_sig (0,
+ &ds->coin_sig),
+ TALER_TESTING_make_trait_age_commitment_proof (0,
+ age_commitment_proof),
+ TALER_TESTING_make_trait_h_age_commitment (0,
+ h_age_commitment),
+ TALER_TESTING_make_trait_wire_details (ds->wire_details),
+ TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
+ TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv),
+ TALER_TESTING_make_trait_deposit_amount (0,
+ &ds->amount),
+ TALER_TESTING_make_trait_deposit_fee_amount (0,
+ &ds->deposit_fee),
+ TALER_TESTING_make_trait_timestamp (0,
+ &ds->exchange_timestamp),
+ TALER_TESTING_make_trait_wire_deadline (0,
+ &ds->wire_deadline),
+ TALER_TESTING_make_trait_refund_deadline (0,
+ &ds->refund_deadline),
TALER_TESTING_trait_end ()
};
@@ -561,46 +662,24 @@ deposit_traits (void *cls,
}
-/**
- * Create a "deposit" command.
- *
- * @param label command label.
- * @param coin_reference reference to any operation that can
- * provide a coin.
- * @param coin_index if @a withdraw_reference offers an array of
- * coins, this parameter selects which one in that array.
- * This value is currently ignored, as only one-coin
- * withdrawals are implemented.
- * @param target_account_payto target account for the "deposit"
- * request.
- * @param contract_terms contract terms to be signed over by the
- * coin.
- * @param refund_deadline refund deadline, zero means 'no refunds'.
- * Note, if time were absolute, then it would have come
- * one day and disrupt tests meaning.
- * @param amount how much is going to be deposited.
- * @param expected_response_code expected HTTP response code.
- *
- * @return the command.
- */
struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit (const char *label,
- const char *coin_reference,
- unsigned int coin_index,
- const char *target_account_payto,
- const char *contract_terms,
- struct GNUNET_TIME_Relative refund_deadline,
- const char *amount,
- unsigned int expected_response_code)
+TALER_TESTING_cmd_deposit (
+ const char *label,
+ const char *coin_reference,
+ unsigned int coin_index,
+ const char *target_account_payto,
+ const char *contract_terms,
+ struct GNUNET_TIME_Relative refund_deadline,
+ const char *amount,
+ unsigned int expected_response_code)
{
struct DepositState *ds;
- json_t *wire_details;
- wire_details = TALER_TESTING_make_wire_details (target_account_payto);
ds = GNUNET_new (struct DepositState);
ds->coin_reference = coin_reference;
ds->coin_index = coin_index;
- ds->wire_details = wire_details;
+ ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
+ GNUNET_assert (NULL != ds->wire_details);
ds->contract_terms = json_loads (contract_terms,
JSON_REJECT_DUPLICATES,
NULL);
@@ -613,25 +692,26 @@ TALER_TESTING_cmd_deposit (const char *label,
label);
GNUNET_assert (0);
}
- ds->wallet_timestamp = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&ds->wallet_timestamp);
-
- json_object_set_new (ds->contract_terms,
- "timestamp",
- GNUNET_JSON_from_time_abs (ds->wallet_timestamp));
- if (0 != refund_deadline.rel_value_us)
+ ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
+ GNUNET_assert (0 ==
+ json_object_set_new (ds->contract_terms,
+ "timestamp",
+ GNUNET_JSON_from_timestamp (
+ ds->wallet_timestamp)));
+ if (! GNUNET_TIME_relative_is_zero (refund_deadline))
{
- ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
- (void) GNUNET_TIME_round_abs (&ds->refund_deadline);
- json_object_set_new (ds->contract_terms,
- "refund_deadline",
- GNUNET_JSON_from_time_abs (ds->refund_deadline));
+ ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
+ GNUNET_assert (0 ==
+ json_object_set_new (ds->contract_terms,
+ "refund_deadline",
+ GNUNET_JSON_from_timestamp (
+ ds->refund_deadline)));
}
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (amount,
&ds->amount));
ds->expected_response_code = expected_response_code;
- ds->command_initialized = GNUNET_YES;
+ ds->command_initialized = true;
{
struct TALER_TESTING_Command cmd = {
.cls = ds,
@@ -646,50 +726,26 @@ TALER_TESTING_cmd_deposit (const char *label,
}
-/**
- * Create a "deposit" command that references an existing merchant key.
- *
- * @param label command label.
- * @param coin_reference reference to any operation that can
- * provide a coin.
- * @param coin_index if @a withdraw_reference offers an array of
- * coins, this parameter selects which one in that array.
- * This value is currently ignored, as only one-coin
- * withdrawals are implemented.
- * @param target_account_payto target account for the "deposit"
- * request.
- * @param contract_terms contract terms to be signed over by the
- * coin.
- * @param refund_deadline refund deadline, zero means 'no refunds'.
- * Note, if time were absolute, then it would have come
- * one day and disrupt tests meaning.
- * @param amount how much is going to be deposited.
- * @param expected_response_code expected HTTP response code.
- * @param merchant_priv_reference reference to another operation
- * that has a merchant private key trait
- *
- * @return the command.
- */
struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit_with_ref (const char *label,
- const char *coin_reference,
- unsigned int coin_index,
- const char *target_account_payto,
- const char *contract_terms,
- struct GNUNET_TIME_Relative refund_deadline,
- const char *amount,
- unsigned int expected_response_code,
- const char *merchant_priv_reference)
+TALER_TESTING_cmd_deposit_with_ref (
+ const char *label,
+ const char *coin_reference,
+ unsigned int coin_index,
+ const char *target_account_payto,
+ const char *contract_terms,
+ struct GNUNET_TIME_Relative refund_deadline,
+ const char *amount,
+ unsigned int expected_response_code,
+ const char *merchant_priv_reference)
{
struct DepositState *ds;
- json_t *wire_details;
- wire_details = TALER_TESTING_make_wire_details (target_account_payto);
ds = GNUNET_new (struct DepositState);
ds->merchant_priv_reference = merchant_priv_reference;
ds->coin_reference = coin_reference;
ds->coin_index = coin_index;
- ds->wire_details = wire_details;
+ ds->wire_details = TALER_TESTING_make_wire_details (target_account_payto);
+ GNUNET_assert (NULL != ds->wire_details);
ds->contract_terms = json_loads (contract_terms,
JSON_REJECT_DUPLICATES,
NULL);
@@ -701,25 +757,26 @@ TALER_TESTING_cmd_deposit_with_ref (const char *label,
label);
GNUNET_assert (0);
}
- ds->wallet_timestamp = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&ds->wallet_timestamp);
-
- json_object_set_new (ds->contract_terms,
- "timestamp",
- GNUNET_JSON_from_time_abs (ds->wallet_timestamp));
+ ds->wallet_timestamp = GNUNET_TIME_timestamp_get ();
+ GNUNET_assert (0 ==
+ json_object_set_new (ds->contract_terms,
+ "timestamp",
+ GNUNET_JSON_from_timestamp (
+ ds->wallet_timestamp)));
if (0 != refund_deadline.rel_value_us)
{
- ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
- (void) GNUNET_TIME_round_abs (&ds->refund_deadline);
- json_object_set_new (ds->contract_terms,
- "refund_deadline",
- GNUNET_JSON_from_time_abs (ds->refund_deadline));
+ ds->refund_deadline = GNUNET_TIME_relative_to_timestamp (refund_deadline);
+ GNUNET_assert (0 ==
+ json_object_set_new (ds->contract_terms,
+ "refund_deadline",
+ GNUNET_JSON_from_timestamp (
+ ds->refund_deadline)));
}
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (amount,
&ds->amount));
ds->expected_response_code = expected_response_code;
- ds->command_initialized = GNUNET_YES;
+ ds->command_initialized = true;
{
struct TALER_TESTING_Command cmd = {
.cls = ds,
@@ -734,19 +791,11 @@ TALER_TESTING_cmd_deposit_with_ref (const char *label,
}
-/**
- * Create a "deposit" command that repeats an existing
- * deposit command.
- *
- * @param label command label.
- * @param deposit_reference which deposit command should we repeat
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit_replay (const char *label,
- const char *deposit_reference,
- unsigned int expected_response_code)
+TALER_TESTING_cmd_deposit_replay (
+ const char *label,
+ const char *deposit_reference,
+ unsigned int expected_response_code)
{
struct DepositState *ds;
@@ -767,13 +816,6 @@ TALER_TESTING_cmd_deposit_replay (const char *label,
}
-/**
- * Modify a deposit command to enable retries when we get transient
- * errors from the exchange.
- *
- * @param cmd a deposit command
- * @return the command with retries enabled
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
{
diff --git a/src/testing/testing_api_cmd_deposits_get.c b/src/testing/testing_api_cmd_deposits_get.c
index f2f3f0e39..5d4436e2a 100644
--- a/src/testing/testing_api_cmd_deposits_get.c
+++ b/src/testing/testing_api_cmd_deposits_get.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -40,6 +40,11 @@ struct TrackTransactionState
const char *bank_transfer_reference;
/**
+ * Our command.
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
* The WTID associated by the transaction being tracked.
*/
struct TALER_WireTransferIdentifierRawP wtid;
@@ -50,12 +55,31 @@ struct TrackTransactionState
unsigned int expected_response_code;
/**
+ * Set to the KYC requirement payto hash *if* the exchange replied with a
+ * request for KYC (#MHD_HTTP_ACCEPTED).
+ * Note: set based on our @e merchant_payto_uri, as
+ * the exchange does not respond with the payto hash.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC (#MHD_HTTP_ACCEPTED).
+ */
+ uint64_t requirement_row;
+
+ /**
* Reference to any operation that can provide a transaction.
* Will be the transaction to track.
*/
const char *transaction_reference;
/**
+ * Payto URI of the merchant receiving the deposit.
+ */
+ char *merchant_payto_uri;
+
+ /**
* Index of the coin involved in the transaction. Recall:
* at the exchange, the tracking is done _per coin_.
*/
@@ -80,38 +104,27 @@ struct TrackTransactionState
* line matches our expectations.
*
* @param cls closure.
- * @param hr HTTP response details
- * @param dd data about the wire transfer associated with the deposit
+ * @param dr GET deposit response details
*/
static void
deposit_wtid_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_EXCHANGE_DepositData *dd)
+ const struct TALER_EXCHANGE_GetDepositResponse *dr)
{
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 != hr->http_status)
+ if (tts->expected_response_code != dr->hr.http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (is);
+ TALER_TESTING_unexpected_status (is,
+ dr->hr.http_status,
+ tts->expected_response_code);
return;
}
- switch (hr->http_status)
+ switch (dr->hr.http_status)
{
case MHD_HTTP_OK:
- tts->wtid = dd->wtid;
+ tts->wtid = dr->details.ok.wtid;
if (NULL != tts->bank_transfer_reference)
{
const struct TALER_TESTING_Command *bank_transfer_cmd;
@@ -130,7 +143,6 @@ deposit_wtid_cb (void *cls,
if (GNUNET_OK !=
TALER_TESTING_get_trait_wtid (bank_transfer_cmd,
- 0,
&wtid_want))
{
GNUNET_break (0);
@@ -139,7 +151,7 @@ deposit_wtid_cb (void *cls,
}
/* Compare that expected and gotten subjects match. */
- if (0 != GNUNET_memcmp (&dd->wtid,
+ if (0 != GNUNET_memcmp (&dr->details.ok.wtid,
wtid_want))
{
GNUNET_break (0);
@@ -147,11 +159,13 @@ deposit_wtid_cb (void *cls,
return;
}
}
-
-
break;
case MHD_HTTP_ACCEPTED:
/* allowed, nothing to check here */
+ TALER_payto_hash (tts->merchant_payto_uri,
+ &tts->h_payto);
+ tts->requirement_row
+ = dr->details.accepted.requirement_row;
break;
case MHD_HTTP_NOT_FOUND:
/* allowed, nothing to check here */
@@ -182,11 +196,11 @@ track_transaction_run (void *cls,
struct TALER_CoinSpendPublicKeyP coin_pub;
const json_t *contract_terms;
const json_t *wire_details;
- struct GNUNET_HashCode h_wire_details;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_MerchantWireHashP h_wire_details;
+ struct TALER_PrivateContractHashP h_contract_terms;
const struct TALER_MerchantPrivateKeyP *merchant_priv;
- (void) cmd;
+ tts->cmd = cmd;
tts->is = is;
transaction_cmd
= TALER_TESTING_interpreter_lookup_command (tts->is,
@@ -214,17 +228,17 @@ track_transaction_run (void *cls,
/* 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;
}
-
+ tts->merchant_payto_uri
+ = GNUNET_strdup (json_string_value (json_object_get (wire_details,
+ "payto_uri")));
if (GNUNET_OK !=
TALER_TESTING_get_trait_contract_terms (transaction_cmd,
- 0,
&contract_terms))
{
GNUNET_break (0);
@@ -251,7 +265,6 @@ track_transaction_run (void *cls,
if (GNUNET_OK !=
TALER_TESTING_get_trait_merchant_priv (transaction_cmd,
- 0,
&merchant_priv))
{
GNUNET_break (0);
@@ -259,13 +272,17 @@ track_transaction_run (void *cls,
return;
}
- tts->tth = TALER_EXCHANGE_deposits_get (is->exchange,
- merchant_priv,
- &h_wire_details,
- &h_contract_terms,
- &coin_pub,
- &deposit_wtid_cb,
- tts);
+ tts->tth = TALER_EXCHANGE_deposits_get (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ merchant_priv,
+ &h_wire_details,
+ &h_contract_terms,
+ &coin_pub,
+ GNUNET_TIME_UNIT_ZERO,
+ &deposit_wtid_cb,
+ tts);
GNUNET_assert (NULL != tts->tth);
}
@@ -285,13 +302,12 @@ track_transaction_cleanup (void *cls,
if (NULL != tts->tth)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- tts->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (tts->is,
+ cmd->label);
TALER_EXCHANGE_deposits_get_cancel (tts->tth);
tts->tth = NULL;
}
+ GNUNET_free (tts->merchant_payto_uri);
GNUNET_free (tts);
}
@@ -305,7 +321,7 @@ track_transaction_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
track_transaction_traits (void *cls,
const void **ret,
const char *trait,
@@ -313,7 +329,11 @@ track_transaction_traits (void *cls,
{
struct TrackTransactionState *tts = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_wtid (0, &tts->wtid),
+ TALER_TESTING_make_trait_wtid (&tts->wtid),
+ TALER_TESTING_make_trait_legi_requirement_row (
+ &tts->requirement_row),
+ TALER_TESTING_make_trait_h_payto (&tts->h_payto),
+ TALER_TESTING_make_trait_payto_uri (tts->merchant_payto_uri),
TALER_TESTING_trait_end ()
};
@@ -324,19 +344,6 @@ track_transaction_traits (void *cls,
}
-/**
- * Create a "track transaction" command.
- *
- * @param label the command label.
- * @param transaction_reference reference to a deposit operation,
- * will be used to get the input data for the track.
- * @param coin_index index of the coin involved in the transaction.
- * @param expected_response_code expected HTTP response code.
- * @param bank_transfer_reference reference to a command that
- * can offer a WTID so as to check that against what WTID
- * the tracked operation has. Set as NULL if not needed.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_track_transaction (const char *label,
const char *transaction_reference,
diff --git a/src/testing/testing_api_cmd_exec_aggregator.c b/src/testing/testing_api_cmd_exec_aggregator.c
index 6ec56c175..1f05576ff 100644
--- a/src/testing/testing_api_cmd_exec_aggregator.c
+++ b/src/testing/testing_api_cmd_exec_aggregator.c
@@ -43,6 +43,11 @@ struct AggregatorState
* Configuration file used by the aggregator.
*/
const char *config_filename;
+
+ /**
+ * Run with KYC restrictions on.
+ */
+ bool kyc_on;
};
@@ -68,6 +73,9 @@ aggregator_run (void *cls,
"taler-exchange-aggregator",
"-c", as->config_filename,
"-t", /* exit when done */
+ (as->kyc_on)
+ ? NULL
+ : "-y", /* skip KYC */
NULL);
if (NULL == as->aggregator_proc)
{
@@ -115,7 +123,7 @@ aggregator_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
aggregator_traits (void *cls,
const void **ret,
const char *trait,
@@ -123,7 +131,7 @@ aggregator_traits (void *cls,
{
struct AggregatorState *as = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &as->aggregator_proc),
+ TALER_TESTING_make_trait_process (&as->aggregator_proc),
TALER_TESTING_trait_end ()
};
@@ -134,14 +142,6 @@ aggregator_traits (void *cls,
}
-/**
- * Make a "aggregator" CMD.
- *
- * @param label command label.
- * @param config_filename configuration file for the
- * aggregator to use.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_exec_aggregator (const char *label,
const char *config_filename)
@@ -164,4 +164,27 @@ TALER_TESTING_cmd_exec_aggregator (const char *label,
}
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_aggregator_with_kyc (const char *label,
+ const char *config_filename)
+{
+ struct AggregatorState *as;
+
+ as = GNUNET_new (struct AggregatorState);
+ as->config_filename = config_filename;
+ as->kyc_on = true;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = as,
+ .label = label,
+ .run = &aggregator_run,
+ .cleanup = &aggregator_cleanup,
+ .traits = &aggregator_traits
+ };
+
+ return cmd;
+ }
+}
+
+
/* end of testing_api_cmd_exec_aggregator.c */
diff --git a/src/testing/testing_api_cmd_exec_auditor-offline.c b/src/testing/testing_api_cmd_exec_auditor-offline.c
new file mode 100644
index 000000000..1899d5c06
--- /dev/null
+++ b/src/testing/testing_api_cmd_exec_auditor-offline.c
@@ -0,0 +1,163 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not,
+ see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_exec_auditor-offline.c
+ * @brief run the taler-exchange-auditor-offline command
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "auditor-offline" CMD.
+ */
+struct AuditorOfflineState
+{
+
+ /**
+ * AuditorOffline process.
+ */
+ struct GNUNET_OS_Process *auditor_offline_proc;
+
+ /**
+ * Configuration file used by the auditor-offline.
+ */
+ const char *config_filename;
+
+};
+
+
+/**
+ * Run the command. Use the `taler-exchange-auditor-offline' program.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ * @param is interpreter state.
+ */
+static void
+auditor_offline_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AuditorOfflineState *as = cls;
+
+ (void) cmd;
+ as->auditor_offline_proc
+ = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-offline",
+ "taler-auditor-offline",
+ "-c", as->config_filename,
+ "-L", "INFO",
+ "download",
+ "sign",
+ "upload",
+ NULL);
+ if (NULL == as->auditor_offline_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "auditor-offline" CMD, and possibly kill its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+auditor_offline_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AuditorOfflineState *as = cls;
+
+ (void) cmd;
+ if (NULL != as->auditor_offline_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (as->auditor_offline_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (as->auditor_offline_proc);
+ GNUNET_OS_process_destroy (as->auditor_offline_proc);
+ as->auditor_offline_proc = NULL;
+ }
+ GNUNET_free (as);
+}
+
+
+/**
+ * Offer "auditor-offline" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+auditor_offline_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AuditorOfflineState *as = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (&as->auditor_offline_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_auditor_offline (const char *label,
+ const char *config_filename)
+{
+ struct AuditorOfflineState *as;
+
+ as = GNUNET_new (struct AuditorOfflineState);
+ as->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = as,
+ .label = label,
+ .run = &auditor_offline_run,
+ .cleanup = &auditor_offline_cleanup,
+ .traits = &auditor_offline_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_auditor-offline.c */
diff --git a/src/testing/testing_api_cmd_exec_closer.c b/src/testing/testing_api_cmd_exec_closer.c
index c1153babb..2501b39a6 100644
--- a/src/testing/testing_api_cmd_exec_closer.c
+++ b/src/testing/testing_api_cmd_exec_closer.c
@@ -49,7 +49,7 @@ struct CloserState
* expect_close is true. Will be of type
* #TALER_EXCHANGE_RTT_RESERVE_CLOSED.
*/
- struct TALER_EXCHANGE_ReserveHistory reserve_history;
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
/**
* If the closer filled a reserve (@e expect_close is set), this is set to
@@ -65,7 +65,7 @@ struct CloserState
/**
* Do we expect the command to actually close a reserve?
*/
- int expect_close;
+ bool expect_close;
};
@@ -91,9 +91,9 @@ closer_run (void *cls,
rcmd = TALER_TESTING_interpreter_lookup_command (is,
as->reserve_ref);
+ GNUNET_assert (NULL != rcmd);
if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_pub (rcmd,
- 0,
&reserve_pubp))
{
GNUNET_break (0);
@@ -156,7 +156,7 @@ closer_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
closer_traits (void *cls,
const void **ret,
const char *trait,
@@ -164,13 +164,12 @@ closer_traits (void *cls,
{
struct CloserState *as = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &as->closer_proc),
+ TALER_TESTING_make_trait_process (&as->closer_proc),
TALER_TESTING_trait_end ()
};
struct TALER_TESTING_Trait xtraits[] = {
- TALER_TESTING_make_trait_process (0, &as->closer_proc),
- TALER_TESTING_make_trait_reserve_pub (0,
- &as->reserve_pub),
+ TALER_TESTING_make_trait_process (&as->closer_proc),
+ TALER_TESTING_make_trait_reserve_pub (&as->reserve_pub),
TALER_TESTING_make_trait_reserve_history (0,
&as->reserve_history),
TALER_TESTING_trait_end ()
@@ -185,22 +184,6 @@ closer_traits (void *cls,
}
-/**
- * Make a "closer" CMD. Note that it is right now not supported to run the
- * closer to close multiple reserves in combination with a subsequent reserve
- * status call, as we cannot generate the traits necessary for multiple closed
- * reserves. You can work around this by using multiple closer commands, one
- * per reserve that is being closed.
- *
- * @param label command label.
- * @param config_filename configuration file for the
- * closer to use.
- * @param expected_amount amount we expect to see wired from a @a expected_reserve_ref
- * @param expected_fee closing fee we expect to see
- * @param expected_reserve_ref reference to a reserve we expect the closer to drain;
- * NULL if we do not expect the closer to do anything
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_exec_closer (const char *label,
const char *config_filename,
@@ -214,7 +197,7 @@ TALER_TESTING_cmd_exec_closer (const char *label,
as->config_filename = config_filename;
if (NULL != expected_reserve_ref)
{
- as->expect_close = GNUNET_YES;
+ as->expect_close = true;
as->reserve_ref = expected_reserve_ref;
if (GNUNET_OK !=
TALER_string_to_amount (expected_amount,
@@ -239,11 +222,11 @@ TALER_TESTING_cmd_exec_closer (const char *label,
/* expected amount includes fee, while our argument
gives the amount _without_ the fee. So add the fee. */
GNUNET_assert (0 <=
- TALER_amount_add (&as->reserve_history.amount,
- &as->reserve_history.amount,
- &as->reserve_history.details.close_details.
- fee));
- as->reserve_history.type = TALER_EXCHANGE_RTT_CLOSE;
+ TALER_amount_add (
+ &as->reserve_history.amount,
+ &as->reserve_history.amount,
+ &as->reserve_history.details.close_details.fee));
+ as->reserve_history.type = TALER_EXCHANGE_RTT_CLOSING;
}
{
struct TALER_TESTING_Command cmd = {
diff --git a/src/testing/testing_api_cmd_exec_expire.c b/src/testing/testing_api_cmd_exec_expire.c
new file mode 100644
index 000000000..aabf37361
--- /dev/null
+++ b/src/testing/testing_api_cmd_exec_expire.c
@@ -0,0 +1,162 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3,
+ or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_exec_expire.c
+ * @brief run the taler-exchange-expire command
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "expire" CMD.
+ */
+struct ExpireState
+{
+
+ /**
+ * Process for the expireer.
+ */
+ struct GNUNET_OS_Process *expire_proc;
+
+ /**
+ * Configuration file used by the expireer.
+ */
+ const char *config_filename;
+};
+
+
+/**
+ * Run the command; use the `taler-exchange-expire' program.
+ *
+ * @param cls closure.
+ * @param cmd command currently being executed.
+ * @param is interpreter state.
+ */
+static void
+expire_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ExpireState *ws = cls;
+
+ (void) cmd;
+ ws->expire_proc
+ = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-expire",
+ "taler-exchange-expire",
+ "-L", "INFO",
+ "-c", ws->config_filename,
+ "-t", /* exit when done */
+ NULL);
+ if (NULL == ws->expire_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "expire" CMD, and possibly
+ * kills its process if it did not terminate regularly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+expire_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ExpireState *ws = cls;
+
+ (void) cmd;
+ if (NULL != ws->expire_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ws->expire_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ws->expire_proc);
+ GNUNET_OS_process_destroy (ws->expire_proc);
+ ws->expire_proc = NULL;
+ }
+ GNUNET_free (ws);
+}
+
+
+/**
+ * Offer "expire" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+expire_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct ExpireState *ws = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (&ws->expire_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_expire (const char *label,
+ const char *config_filename)
+{
+ struct ExpireState *ws;
+
+ ws = GNUNET_new (struct ExpireState);
+ ws->config_filename = config_filename;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &expire_run,
+ .cleanup = &expire_cleanup,
+ .traits = &expire_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_expire.c */
diff --git a/src/testing/testing_api_cmd_exec_router.c b/src/testing/testing_api_cmd_exec_router.c
new file mode 100644
index 000000000..d7f3fe265
--- /dev/null
+++ b/src/testing/testing_api_cmd_exec_router.c
@@ -0,0 +1,161 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3,
+ or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_exec_router.c
+ * @brief run the taler-exchange-router command
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "router" CMD.
+ */
+struct RouterState
+{
+
+ /**
+ * Process for the routerer.
+ */
+ struct GNUNET_OS_Process *router_proc;
+
+ /**
+ * Configuration file used by the routerer.
+ */
+ const char *config_filename;
+};
+
+
+/**
+ * Run the command; use the `taler-exchange-router' program.
+ *
+ * @param cls closure.
+ * @param cmd command currently being executed.
+ * @param is interpreter state.
+ */
+static void
+router_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RouterState *ws = cls;
+
+ (void) cmd;
+ ws->router_proc
+ = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-router",
+ "taler-exchange-router",
+ "-c", ws->config_filename,
+ "-t", /* exit when done */
+ NULL);
+ if (NULL == ws->router_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "router" CMD, and possibly
+ * kills its process if it did not terminate regularly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+router_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RouterState *ws = cls;
+
+ (void) cmd;
+ if (NULL != ws->router_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ws->router_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ws->router_proc);
+ GNUNET_OS_process_destroy (ws->router_proc);
+ ws->router_proc = NULL;
+ }
+ GNUNET_free (ws);
+}
+
+
+/**
+ * Offer "router" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+router_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RouterState *ws = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (&ws->router_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_router (const char *label,
+ const char *config_filename)
+{
+ struct RouterState *ws;
+
+ ws = GNUNET_new (struct RouterState);
+ ws->config_filename = config_filename;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &router_run,
+ .cleanup = &router_cleanup,
+ .traits = &router_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_router.c */
diff --git a/src/testing/testing_api_cmd_exec_transfer.c b/src/testing/testing_api_cmd_exec_transfer.c
index 796f32d07..300413b4b 100644
--- a/src/testing/testing_api_cmd_exec_transfer.c
+++ b/src/testing/testing_api_cmd_exec_transfer.c
@@ -60,13 +60,13 @@ transfer_run (void *cls,
{
struct TransferState *as = cls;
+ (void) cmd;
as->transfer_proc
= GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL,
"taler-exchange-transfer",
"taler-exchange-transfer",
"-c", as->config_filename,
- "-L", "INFO",
"-S", "1",
"-w", "0",
"-t", /* exit when done */
@@ -94,6 +94,7 @@ transfer_cleanup (void *cls,
{
struct TransferState *as = cls;
+ (void) cmd;
if (NULL != as->transfer_proc)
{
GNUNET_break (0 ==
@@ -116,7 +117,7 @@ transfer_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
transfer_traits (void *cls,
const void **ret,
const char *trait,
@@ -124,7 +125,7 @@ transfer_traits (void *cls,
{
struct TransferState *as = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &as->transfer_proc),
+ TALER_TESTING_make_trait_process (&as->transfer_proc),
TALER_TESTING_trait_end ()
};
@@ -135,14 +136,6 @@ transfer_traits (void *cls,
}
-/**
- * Make a "transfer" CMD.
- *
- * @param label command label.
- * @param config_filename configuration file for the
- * transfer to use.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_exec_transfer (const char *label,
const char *config_filename)
diff --git a/src/testing/testing_api_cmd_exec_wget.c b/src/testing/testing_api_cmd_exec_wget.c
new file mode 100644
index 000000000..67aceca0a
--- /dev/null
+++ b/src/testing/testing_api_cmd_exec_wget.c
@@ -0,0 +1,158 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3,
+ or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_exec_wget.c
+ * @brief run a wget command
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "wget" CMD.
+ */
+struct WgetState
+{
+ /**
+ * Process for the wgeter.
+ */
+ struct GNUNET_OS_Process *wget_proc;
+
+ /**
+ * URL to used by the wget.
+ */
+ const char *url;
+};
+
+
+/**
+ * Run the command; use the `wget' program.
+ *
+ * @param cls closure.
+ * @param cmd command currently being executed.
+ * @param is interpreter state.
+ */
+static void
+wget_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct WgetState *ws = cls;
+
+ (void) cmd;
+ ws->wget_proc
+ = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "wget",
+ "wget",
+ ws->url,
+ NULL);
+ if (NULL == ws->wget_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "wget" CMD, and possibly
+ * kills its process if it did not terminate regularly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+wget_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct WgetState *ws = cls;
+
+ (void) cmd;
+ if (NULL != ws->wget_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ws->wget_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ws->wget_proc);
+ GNUNET_OS_process_destroy (ws->wget_proc);
+ ws->wget_proc = NULL;
+ }
+ GNUNET_free (ws);
+}
+
+
+/**
+ * Offer "wget" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+wget_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct WgetState *ws = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (&ws->wget_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_wget (const char *label,
+ const char *url)
+{
+ struct WgetState *ws;
+
+ ws = GNUNET_new (struct WgetState);
+ ws->url = url;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &wget_run,
+ .cleanup = &wget_cleanup,
+ .traits = &wget_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_wget.c */
diff --git a/src/testing/testing_api_cmd_exec_wirewatch.c b/src/testing/testing_api_cmd_exec_wirewatch.c
index 2c50b4f4a..b6ed4f0f1 100644
--- a/src/testing/testing_api_cmd_exec_wirewatch.c
+++ b/src/testing/testing_api_cmd_exec_wirewatch.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
+ Copyright (C) 2018, 2023 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
@@ -34,7 +34,6 @@
*/
struct WirewatchState
{
-
/**
* Process for the wirewatcher.
*/
@@ -44,8 +43,14 @@ struct WirewatchState
* Configuration file used by the wirewatcher.
*/
const char *config_filename;
+
+ /**
+ * Account section to be used by the wirewatcher.
+ */
+ const char *account_section;
};
+
/**
* Run the command; use the `taler-exchange-wirewatch' program.
*
@@ -60,6 +65,7 @@ wirewatch_run (void *cls,
{
struct WirewatchState *ws = cls;
+ (void) cmd;
ws->wirewatch_proc
= GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL,
@@ -69,6 +75,10 @@ wirewatch_run (void *cls,
"-S", "1",
"-w", "0",
"-t", /* exit when done */
+ (NULL == ws->account_section)
+ ? NULL
+ : "-a",
+ ws->account_section,
NULL);
if (NULL == ws->wirewatch_proc)
{
@@ -93,6 +103,7 @@ wirewatch_cleanup (void *cls,
{
struct WirewatchState *ws = cls;
+ (void) cmd;
if (NULL != ws->wirewatch_proc)
{
GNUNET_break (0 ==
@@ -115,7 +126,7 @@ wirewatch_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
wirewatch_traits (void *cls,
const void **ret,
const char *trait,
@@ -123,8 +134,7 @@ wirewatch_traits (void *cls,
{
struct WirewatchState *ws = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0,
- &ws->wirewatch_proc),
+ TALER_TESTING_make_trait_process (&ws->wirewatch_proc),
TALER_TESTING_trait_end ()
};
@@ -135,22 +145,16 @@ wirewatch_traits (void *cls,
}
-/**
- * Make a "wirewatch" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @return the command.
- */
struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_wirewatch (const char *label,
- const char *config_filename)
+TALER_TESTING_cmd_exec_wirewatch2 (const char *label,
+ const char *config_filename,
+ const char *account_section)
{
struct WirewatchState *ws;
ws = GNUNET_new (struct WirewatchState);
ws->config_filename = config_filename;
-
+ ws->account_section = account_section;
{
struct TALER_TESTING_Command cmd = {
.cls = ws,
@@ -165,4 +169,14 @@ TALER_TESTING_cmd_exec_wirewatch (const char *label,
}
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_wirewatch (const char *label,
+ const char *config_filename)
+{
+ return TALER_TESTING_cmd_exec_wirewatch2 (label,
+ config_filename,
+ NULL);
+}
+
+
/* end of testing_api_cmd_exec_wirewatch.c */
diff --git a/src/testing/testing_api_cmd_get_auditor.c b/src/testing/testing_api_cmd_get_auditor.c
new file mode 100644
index 000000000..ab4e32665
--- /dev/null
+++ b/src/testing/testing_api_cmd_get_auditor.c
@@ -0,0 +1,286 @@
+/*
+ This file is part of TALER
+ (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_get_auditor.c
+ * @brief Command to get an auditor handle
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "get auditor" CMD.
+ */
+struct GetAuditorState
+{
+
+ /**
+ * Private key of the auditor.
+ */
+ struct TALER_AuditorPrivateKeyP auditor_priv;
+
+ /**
+ * Public key of the auditor.
+ */
+ struct TALER_AuditorPublicKeyP auditor_pub;
+
+ /**
+ * Our interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Auditor handle used to get the configuration.
+ */
+ struct TALER_AUDITOR_GetConfigHandle *auditor;
+
+ /**
+ * URL of the auditor.
+ */
+ char *auditor_url;
+
+ /**
+ * Filename of the master private key of the auditor.
+ */
+ char *priv_file;
+
+};
+
+
+/**
+ * Function called with information about the auditor.
+ *
+ * @param cls closure
+ * @param vr response data
+ */
+static void
+version_cb (
+ void *cls,
+ const struct TALER_AUDITOR_ConfigResponse *vr)
+{
+ struct GetAuditorState *gas = cls;
+
+ gas->auditor = NULL;
+ if (MHD_HTTP_OK != vr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (gas->is,
+ vr->hr.http_status,
+ MHD_HTTP_OK);
+ return;
+ }
+ if ( (NULL != gas->priv_file) &&
+ (0 != GNUNET_memcmp (&gas->auditor_pub,
+ &vr->details.ok.vi.auditor_pub)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (gas->is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (gas->is);
+}
+
+
+/**
+ * Run the "get_auditor" command.
+ *
+ * @param cls closure.
+ * @param cmd the command currently being executed.
+ * @param is the interpreter state.
+ */
+static void
+get_auditor_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct GetAuditorState *gas = cls;
+
+ (void) cmd;
+ if (NULL == gas->auditor_url)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL != gas->priv_file)
+ {
+ if (GNUNET_SYSERR ==
+ GNUNET_CRYPTO_eddsa_key_from_file (gas->priv_file,
+ GNUNET_YES,
+ &gas->auditor_priv.eddsa_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&gas->auditor_priv.eddsa_priv,
+ &gas->auditor_pub.eddsa_pub);
+ }
+ gas->is = is;
+ gas->auditor
+ = TALER_AUDITOR_get_config (TALER_TESTING_interpreter_get_context (is),
+ gas->auditor_url,
+ &version_cb,
+ gas);
+ if (NULL == gas->auditor)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Cleanup the state.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+get_auditor_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct GetAuditorState *gas = cls;
+
+ if (NULL != gas->auditor)
+ {
+ GNUNET_break (0);
+ TALER_AUDITOR_get_config_cancel (gas->auditor);
+ gas->auditor = NULL;
+ }
+ GNUNET_free (gas->priv_file);
+ GNUNET_free (gas->auditor_url);
+ GNUNET_free (gas);
+}
+
+
+/**
+ * Offer internal data to a "get_auditor" CMD state to other commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+get_auditor_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct GetAuditorState *gas = cls;
+ unsigned int off = (NULL == gas->priv_file) ? 2 : 0;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_auditor_priv (&gas->auditor_priv),
+ TALER_TESTING_make_trait_auditor_pub (&gas->auditor_pub),
+ TALER_TESTING_make_trait_auditor_url (gas->auditor_url),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (&traits[off],
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Get the base URL of the auditor from @a cfg.
+ *
+ * @param cfg configuration to evaluate
+ * @return base URL of the auditor according to @a cfg
+ */
+static char *
+get_auditor_base_url (
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *auditor_url;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "auditor",
+ "BASE_URL",
+ &auditor_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "auditor",
+ "BASE_URL");
+ return NULL;
+ }
+ return auditor_url;
+}
+
+
+/**
+ * Get the file name of the master private key file of the auditor from @a
+ * cfg.
+ *
+ * @param cfg configuration to evaluate
+ * @return base URL of the auditor according to @a cfg
+ */
+static char *
+get_auditor_priv_file (
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *fn;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "auditor",
+ "AUDITOR_PRIV_FILE",
+ &fn))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "auditor",
+ "AUDITOR_PRIV_FILE");
+ return NULL;
+ }
+ return fn;
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_get_auditor (
+ const char *label,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ bool load_auditor_keys)
+{
+ struct GetAuditorState *gas;
+
+ gas = GNUNET_new (struct GetAuditorState);
+ gas->auditor_url = get_auditor_base_url (cfg);
+ if (load_auditor_keys)
+ gas->priv_file = get_auditor_priv_file (cfg);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = gas,
+ .label = label,
+ .run = &get_auditor_run,
+ .cleanup = &get_auditor_cleanup,
+ .traits = &get_auditor_traits,
+ .name = "auditor"
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_get_exchange.c b/src/testing/testing_api_cmd_get_exchange.c
new file mode 100644
index 000000000..69a6e82b0
--- /dev/null
+++ b/src/testing/testing_api_cmd_get_exchange.c
@@ -0,0 +1,411 @@
+/*
+ This file is part of TALER
+ (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_get_exchange.c
+ * @brief Command to get an exchange handle
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "get exchange" CMD.
+ */
+struct GetExchangeState
+{
+
+ /**
+ * Master private key of the exchange.
+ */
+ struct TALER_MasterPrivateKeyP master_priv;
+
+ /**
+ * Our interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Exchange handle we produced.
+ */
+ struct TALER_EXCHANGE_GetKeysHandle *exchange;
+
+ /**
+ * Keys of the exchange.
+ */
+ struct TALER_EXCHANGE_Keys *keys;
+
+ /**
+ * URL of the exchange.
+ */
+ char *exchange_url;
+
+ /**
+ * Filename of the master private key of the exchange.
+ */
+ char *master_priv_file;
+
+ /**
+ * Label of a command to use to obtain existing
+ * keys.
+ */
+ const char *last_keys_ref;
+
+ /**
+ * Last denomination date we received when doing this request.
+ */
+ struct GNUNET_TIME_Timestamp my_denom_date;
+
+ /**
+ * Are we waiting for /keys before continuing?
+ */
+ bool wait_for_keys;
+};
+
+
+/**
+ * Function called with information about who is auditing
+ * a particular exchange and what keys the exchange is using.
+ *
+ * @param cls closure
+ * @param kr response from /keys
+ * @param[in] keys the keys of the exchange
+ */
+static void
+cert_cb (void *cls,
+ const struct TALER_EXCHANGE_KeysResponse *kr,
+ struct TALER_EXCHANGE_Keys *keys)
+{
+ struct GetExchangeState *ges = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
+ struct TALER_TESTING_Interpreter *is = ges->is;
+
+ ges->exchange = NULL;
+ ges->keys = keys;
+ switch (hr->http_status)
+ {
+ case MHD_HTTP_OK:
+ if (ges->wait_for_keys)
+ {
+ ges->wait_for_keys = false;
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date;
+ return;
+ default:
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "/keys responded with HTTP status %u\n",
+ hr->http_status);
+ if (ges->wait_for_keys)
+ {
+ ges->wait_for_keys = false;
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ return;
+ }
+}
+
+
+/**
+ * Run the "get_exchange" command.
+ *
+ * @param cls closure.
+ * @param cmd the command currently being executed.
+ * @param is the interpreter state.
+ */
+static void
+get_exchange_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct GetExchangeState *ges = cls;
+ struct TALER_EXCHANGE_Keys *xkeys = NULL;
+
+ (void) cmd;
+ if (NULL == ges->exchange_url)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL != ges->last_keys_ref)
+ {
+ const struct TALER_TESTING_Command *state_cmd;
+ struct TALER_EXCHANGE_Keys *old_keys;
+ const char *exchange_url;
+ json_t *s_keys;
+
+ state_cmd
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ges->last_keys_ref);
+ if (NULL == state_cmd)
+ {
+ /* Command providing serialized keys not found. */
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_keys (state_cmd,
+ &old_keys))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL == old_keys)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_exchange_url (state_cmd,
+ &exchange_url))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (0 != strcmp (exchange_url,
+ ges->exchange_url))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ s_keys = TALER_EXCHANGE_keys_to_json (old_keys);
+ if (NULL == s_keys)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ xkeys = TALER_EXCHANGE_keys_from_json (s_keys);
+ if (NULL == xkeys)
+ {
+ GNUNET_break (0);
+ json_dumpf (s_keys,
+ stderr,
+ JSON_INDENT (2));
+ json_decref (s_keys);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ json_decref (s_keys);
+ }
+ if (NULL != ges->master_priv_file)
+ {
+ if (GNUNET_SYSERR ==
+ GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file,
+ GNUNET_YES,
+ &ges->master_priv.eddsa_priv))
+ {
+ GNUNET_break (0);
+ TALER_EXCHANGE_keys_decref (xkeys);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ ges->is = is;
+ ges->exchange
+ = TALER_EXCHANGE_get_keys (TALER_TESTING_interpreter_get_context (is),
+ ges->exchange_url,
+ xkeys,
+ &cert_cb,
+ ges);
+ TALER_EXCHANGE_keys_decref (xkeys);
+ if (NULL == ges->exchange)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (! ges->wait_for_keys)
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Cleanup the state.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+get_exchange_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct GetExchangeState *ges = cls;
+
+ if (NULL != ges->exchange)
+ {
+ TALER_EXCHANGE_get_keys_cancel (ges->exchange);
+ ges->exchange = NULL;
+ }
+ TALER_EXCHANGE_keys_decref (ges->keys);
+ ges->keys = NULL;
+ GNUNET_free (ges->master_priv_file);
+ GNUNET_free (ges->exchange_url);
+ GNUNET_free (ges);
+}
+
+
+/**
+ * Offer internal data to a "get_exchange" CMD state to other commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+get_exchange_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct GetExchangeState *ges = cls;
+ unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0;
+
+ if (NULL != ges->keys)
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_master_priv (&ges->master_priv),
+ TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub),
+ TALER_TESTING_make_trait_keys (ges->keys),
+ TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
+ TALER_TESTING_make_trait_timestamp (0,
+ &ges->my_denom_date),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (&traits[off],
+ ret,
+ trait,
+ index);
+ }
+ else
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_master_priv (&ges->master_priv),
+ TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
+ TALER_TESTING_make_trait_timestamp (0,
+ &ges->my_denom_date),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (&traits[off],
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+/**
+ * Get the base URL of the exchange from @a cfg.
+ *
+ * @param cfg configuration to evaluate
+ * @return base URL of the exchange according to @a cfg
+ */
+static char *
+get_exchange_base_url (
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *exchange_url;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "BASE_URL",
+ &exchange_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "BASE_URL");
+ return NULL;
+ }
+ return exchange_url;
+}
+
+
+/**
+ * Get the file name of the master private key file of the exchange from @a
+ * cfg.
+ *
+ * @param cfg configuration to evaluate
+ * @return base URL of the exchange according to @a cfg
+ */
+static char *
+get_exchange_master_priv_file (
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *fn;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange-offline",
+ "MASTER_PRIV_FILE",
+ &fn))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange-offline",
+ "MASTER_PRIV_FILE");
+ return NULL;
+ }
+ return fn;
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_get_exchange (
+ const char *label,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *last_keys_ref,
+ bool wait_for_keys,
+ bool load_private_key)
+{
+ struct GetExchangeState *ges;
+
+ ges = GNUNET_new (struct GetExchangeState);
+ ges->exchange_url = get_exchange_base_url (cfg);
+ ges->last_keys_ref = last_keys_ref;
+ if (load_private_key)
+ ges->master_priv_file = get_exchange_master_priv_file (cfg);
+ ges->wait_for_keys = wait_for_keys;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ges,
+ .label = label,
+ .run = &get_exchange_run,
+ .cleanup = &get_exchange_cleanup,
+ .traits = &get_exchange_traits,
+ .name = "exchange"
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c
index 0d57ab6c4..03e704c72 100644
--- a/src/testing/testing_api_cmd_insert_deposit.c
+++ b/src/testing/testing_api_cmd_insert_deposit.c
@@ -29,6 +29,7 @@
#include "taler_signatures.h"
#include "taler_testing_lib.h"
#include "taler_exchangedb_plugin.h"
+#include "taler_exchangedb_lib.h"
/**
@@ -37,9 +38,9 @@
struct InsertDepositState
{
/**
- * Configuration file used by the command.
+ * Database connection we use.
*/
- const struct TALER_TESTING_DatabaseConnection *dbc;
+ struct TALER_EXCHANGEDB_Plugin *plugin;
/**
* Human-readable name of the shop.
@@ -60,7 +61,7 @@ struct InsertDepositState
/**
* When did the exchange receive the deposit?
*/
- struct GNUNET_TIME_Absolute exchange_timestamp;
+ struct GNUNET_TIME_Timestamp exchange_timestamp;
/**
* Amount to deposit, inclusive of deposit fee.
@@ -71,6 +72,11 @@ struct InsertDepositState
* Deposit fee.
*/
const char *deposit_fee;
+
+ /**
+ * Do we used a cached @e plugin?
+ */
+ bool cached;
};
/**
@@ -79,44 +85,37 @@ struct InsertDepositState
* @param[out] issue information to initialize with "valid" data
*/
static void
-fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
+fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformation *issue)
{
- struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp now;
memset (issue,
0,
- sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP));
- now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
- issue->properties.start
- = GNUNET_TIME_absolute_hton (now);
- issue->properties.expire_withdraw
- = GNUNET_TIME_absolute_hton (
- GNUNET_TIME_absolute_add (now,
- GNUNET_TIME_UNIT_MINUTES));
- issue->properties.expire_deposit
- = GNUNET_TIME_absolute_hton (
- GNUNET_TIME_absolute_add (now,
- GNUNET_TIME_UNIT_HOURS));
- issue->properties.expire_legal
- = GNUNET_TIME_absolute_hton (
- GNUNET_TIME_absolute_add (now,
- GNUNET_TIME_UNIT_DAYS));
+ sizeof (*issue));
+ now = GNUNET_TIME_timestamp_get ();
+ issue->start
+ = now;
+ issue->expire_withdraw
+ = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES);
+ issue->expire_deposit
+ = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS);
+ issue->expire_legal
+ = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_DAYS);
GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:1",
- &issue->properties.value));
+ TALER_string_to_amount ("EUR:1",
+ &issue->value));
GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_withdraw));
+ TALER_string_to_amount ("EUR:0.1",
+ &issue->fees.withdraw));
GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_deposit));
+ TALER_string_to_amount ("EUR:0.1",
+ &issue->fees.deposit));
GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_refresh));
+ TALER_string_to_amount ("EUR:0.1",
+ &issue->fees.refresh));
GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_refund));
+ TALER_string_to_amount ("EUR:0.1",
+ &issue->fees.refund));
}
@@ -133,31 +132,50 @@ insert_deposit_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct InsertDepositState *ids = cls;
- struct TALER_EXCHANGEDB_Deposit deposit;
+ struct TALER_EXCHANGEDB_CoinDepositInformation deposit;
+ struct TALER_EXCHANGEDB_BatchDeposit bd;
struct TALER_MerchantPrivateKeyP merchant_priv;
- struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
+ struct TALER_EXCHANGEDB_DenominationKeyInformation issue;
struct TALER_DenominationPublicKey dpk;
- struct GNUNET_CRYPTO_RsaPrivateKey *denom_priv;
- struct GNUNET_HashCode hc;
+ struct TALER_DenominationPrivateKey denom_priv;
+ char *receiver_wire_account;
- // prepare and store issue first.
+ (void) cmd;
+ if (NULL == ids->plugin)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ids->plugin->preflight (ids->plugin->cls))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
fake_issue (&issue);
- denom_priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
- dpk.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv);
- GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key,
- &issue.properties.denom_hash);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_denom_priv_create (&denom_priv,
+ &dpk,
+ GNUNET_CRYPTO_BSA_RSA,
+ 1024));
+ TALER_denom_pub_hash (&dpk,
+ &issue.denom_hash);
if ( (GNUNET_OK !=
- ids->dbc->plugin->start (ids->dbc->plugin->cls,
- "talertestinglib: denomination insertion")) ||
+ ids->plugin->start (ids->plugin->cls,
+ "talertestinglib: denomination insertion")) ||
(GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- ids->dbc->plugin->insert_denomination_info (ids->dbc->plugin->cls,
- &dpk,
- &issue)) ||
+ ids->plugin->insert_denomination_info (ids->plugin->cls,
+ &dpk,
+ &issue)) ||
(GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- ids->dbc->plugin->commit (ids->dbc->plugin->cls)) )
+ ids->plugin->commit (ids->plugin->cls)) )
{
TALER_TESTING_interpreter_fail (is);
+ TALER_denom_pub_free (&dpk);
+ TALER_denom_priv_free (&denom_priv);
return;
}
@@ -165,87 +183,132 @@ insert_deposit_run (void *cls,
memset (&deposit,
0,
sizeof (deposit));
-
- GNUNET_CRYPTO_kdf (&merchant_priv,
- sizeof (struct TALER_MerchantPrivateKeyP),
- "merchant-priv",
- strlen ("merchant-priv"),
- ids->merchant_name,
- strlen (ids->merchant_name),
- NULL,
- 0);
+ memset (&bd,
+ 0,
+ sizeof (bd));
+ bd.cdis = &deposit;
+ bd.num_cdis = 1;
+
+ GNUNET_assert (
+ GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (&merchant_priv,
+ sizeof (struct TALER_MerchantPrivateKeyP),
+ "merchant-priv",
+ strlen ("merchant-priv"),
+ ids->merchant_name,
+ strlen (ids->merchant_name),
+ NULL,
+ 0));
GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv,
- &deposit.merchant_pub.eddsa_pub);
+ &bd.merchant_pub.eddsa_pub);
GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- &deposit.h_contract_terms);
- if ( (GNUNET_OK !=
- TALER_string_to_amount (ids->amount_with_fee,
- &deposit.amount_with_fee)) ||
- (GNUNET_OK !=
- TALER_string_to_amount (ids->deposit_fee,
- &deposit.deposit_fee)) )
+ &bd.h_contract_terms.hash);
+ if (GNUNET_OK !=
+ TALER_string_to_amount (ids->amount_with_fee,
+ &deposit.amount_with_fee))
{
TALER_TESTING_interpreter_fail (is);
+ TALER_denom_pub_free (&dpk);
+ TALER_denom_priv_free (&denom_priv);
return;
}
- GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key,
- &deposit.coin.denom_pub_hash);
+ TALER_denom_pub_hash (&dpk,
+ &deposit.coin.denom_pub_hash);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&deposit.coin.coin_pub,
sizeof (deposit.coin.coin_pub));
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- &hc);
- deposit.coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (denom_priv,
- &hc);
{
- char *str;
-
- GNUNET_asprintf (&str,
- "payto://x-taler-bank/localhost/%s",
- ids->merchant_account);
- deposit.receiver_wire_account
- = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("salt",
- "this-is-a-salt-value"),
- GNUNET_JSON_pack_string ("payto_uri",
- str));
- GNUNET_free (str);
+ struct TALER_CoinPubHashP c_hash;
+ struct TALER_PlanchetDetail pd;
+ struct TALER_BlindedDenominationSignature bds;
+ struct TALER_PlanchetMasterSecretP ps;
+ union GNUNET_CRYPTO_BlindingSecretP bks;
+ const struct TALER_ExchangeWithdrawValues *alg_values;
+
+ alg_values = TALER_denom_ewv_rsa_singleton ();
+ TALER_planchet_blinding_secret_create (&ps,
+ alg_values,
+ &bks);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_denom_blind (&dpk,
+ &bks,
+ NULL, /* no age restriction active */
+ NULL, /* no nonce needed */
+ &deposit.coin.coin_pub,
+ alg_values,
+ &c_hash,
+ &pd.blinded_planchet));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_denom_sign_blinded (&bds,
+ &denom_priv,
+ false,
+ &pd.blinded_planchet));
+ TALER_blinded_planchet_free (&pd.blinded_planchet);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_denom_sig_unblind (&deposit.coin.denom_sig,
+ &bds,
+ &bks,
+ &c_hash,
+ alg_values,
+ &dpk));
+ TALER_blinded_denom_sig_free (&bds);
}
-
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_merchant_wire_signature_hash (
- deposit.receiver_wire_account,
- &deposit.h_wire));
- deposit.timestamp = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&deposit.timestamp);
- deposit.wire_deadline = GNUNET_TIME_relative_to_absolute (ids->wire_deadline);
- (void) GNUNET_TIME_round_abs (&deposit.wire_deadline);
-
+ GNUNET_asprintf (&receiver_wire_account,
+ "payto://x-taler-bank/localhost/%s?receiver-name=%s",
+ ids->merchant_account,
+ ids->merchant_account);
+ bd.receiver_wire_account = receiver_wire_account;
+ TALER_payto_hash (bd.receiver_wire_account,
+ &bd.wire_target_h_payto);
+ memset (&bd.wire_salt,
+ 46,
+ sizeof (bd.wire_salt));
+ bd.wallet_timestamp = GNUNET_TIME_timestamp_get ();
+ bd.wire_deadline = GNUNET_TIME_relative_to_timestamp (
+ ids->wire_deadline);
/* finally, actually perform the DB operation */
- if ( (GNUNET_OK !=
- ids->dbc->plugin->start (ids->dbc->plugin->cls,
- "libtalertesting: insert deposit")) ||
- (0 >
- ids->dbc->plugin->ensure_coin_known (ids->dbc->plugin->cls,
- &deposit.coin)) ||
- (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls,
- ids->exchange_timestamp,
- &deposit)) ||
- (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- ids->dbc->plugin->commit (ids->dbc->plugin->cls)) )
{
- GNUNET_break (0);
- ids->dbc->plugin->rollback (ids->dbc->plugin->cls);
- TALER_TESTING_interpreter_fail (is);
+ uint64_t known_coin_id;
+ struct TALER_DenominationHashP dph;
+ struct TALER_AgeCommitmentHash agh;
+ bool balance_ok;
+ uint32_t bad_index;
+ bool ctr_conflict;
+
+ if ( (GNUNET_OK !=
+ ids->plugin->start (ids->plugin->cls,
+ "libtalertesting: insert deposit")) ||
+ (0 >
+ ids->plugin->ensure_coin_known (ids->plugin->cls,
+ &deposit.coin,
+ &known_coin_id,
+ &dph,
+ &agh)) ||
+ (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ ids->plugin->do_deposit (ids->plugin->cls,
+ &bd,
+ &ids->exchange_timestamp,
+ &balance_ok,
+ &bad_index,
+ &ctr_conflict)) ||
+ (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+ ids->plugin->commit (ids->plugin->cls)) )
+ {
+ GNUNET_break (0);
+ ids->plugin->rollback (ids->plugin->cls);
+ GNUNET_free (receiver_wire_account);
+ TALER_denom_pub_free (&dpk);
+ TALER_denom_priv_free (&denom_priv);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
}
- GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (dpk.rsa_public_key);
- GNUNET_CRYPTO_rsa_private_key_free (denom_priv);
- json_decref (deposit.receiver_wire_account);
-
+ TALER_denom_sig_free (&deposit.coin.denom_sig);
+ TALER_denom_pub_free (&dpk);
+ TALER_denom_priv_free (&denom_priv);
+ GNUNET_free (receiver_wire_account);
TALER_TESTING_interpreter_next (is);
}
@@ -263,63 +326,46 @@ insert_deposit_cleanup (void *cls,
{
struct InsertDepositState *ids = cls;
+ (void) cmd;
+ if ( (NULL != ids->plugin) &&
+ (! ids->cached) )
+ {
+ // FIXME: historically, we also did:
+ // ids->plugin->drop_tables (ids->plugin->cls);
+ TALER_EXCHANGEDB_plugin_unload (ids->plugin);
+ ids->plugin = NULL;
+ }
GNUNET_free (ids);
}
-/**
- * Offer "insert-deposit" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-insert_deposit_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- return GNUNET_NO;
-}
-
-
-/**
- * Make the "insert-deposit" CMD.
- *
- * @param label command label.
- * @param dbc collects database plugin
- * @param merchant_name Human-readable name of the merchant.
- * @param merchant_account merchant's account name (NOT a payto:// URI)
- * @param exchange_timestamp when did the exchange receive the deposit
- * @param wire_deadline point in time where the aggregator should have
- * wired money to the merchant.
- * @param amount_with_fee amount to deposit (inclusive of deposit fee)
- * @param deposit_fee deposit fee
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_insert_deposit (
const char *label,
- const struct TALER_TESTING_DatabaseConnection *dbc,
+ const struct GNUNET_CONFIGURATION_Handle *db_cfg,
const char *merchant_name,
const char *merchant_account,
- struct GNUNET_TIME_Absolute exchange_timestamp,
+ struct GNUNET_TIME_Timestamp exchange_timestamp,
struct GNUNET_TIME_Relative wire_deadline,
const char *amount_with_fee,
const char *deposit_fee)
{
+ static struct TALER_EXCHANGEDB_Plugin *pluginc;
+ static const struct GNUNET_CONFIGURATION_Handle *db_cfgc;
struct InsertDepositState *ids;
- GNUNET_TIME_round_abs (&exchange_timestamp);
ids = GNUNET_new (struct InsertDepositState);
- ids->dbc = dbc;
+ if (db_cfgc == db_cfg)
+ {
+ ids->plugin = pluginc;
+ ids->cached = true;
+ }
+ else
+ {
+ ids->plugin = TALER_EXCHANGEDB_plugin_load (db_cfg);
+ pluginc = ids->plugin;
+ db_cfgc = db_cfg;
+ }
ids->merchant_name = merchant_name;
ids->merchant_account = merchant_account;
ids->exchange_timestamp = exchange_timestamp;
@@ -332,8 +378,7 @@ TALER_TESTING_cmd_insert_deposit (
.cls = ids,
.label = label,
.run = &insert_deposit_run,
- .cleanup = &insert_deposit_cleanup,
- .traits = &insert_deposit_traits
+ .cleanup = &insert_deposit_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_kyc_check_get.c b/src/testing/testing_api_cmd_kyc_check_get.c
new file mode 100644
index 000000000..25c7e98b8
--- /dev/null
+++ b/src/testing/testing_api_cmd_kyc_check_get.c
@@ -0,0 +1,243 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_cmd_kyc_check_get.c
+ * @brief Implement the testing CMDs for the /kyc_check/ GET operations.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+/**
+ * State for a "track transaction" CMD.
+ */
+struct KycCheckGetState
+{
+
+ /**
+ * Command to get a reserve private key from.
+ */
+ const char *payment_target_reference;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Set to the KYC URL *if* the exchange replied with
+ * a request for KYC (#MHD_HTTP_ACCEPTED).
+ */
+ char *kyc_url;
+
+ /**
+ * Handle to the "track transaction" pending operation.
+ */
+ struct TALER_EXCHANGE_KycCheckHandle *kwh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Handle response to the command.
+ *
+ * @param cls closure.
+ * @param ks GET KYC status response details
+ */
+static void
+check_kyc_cb (void *cls,
+ const struct TALER_EXCHANGE_KycStatus *ks)
+{
+ struct KycCheckGetState *kcg = cls;
+ struct TALER_TESTING_Interpreter *is = kcg->is;
+
+ kcg->kwh = NULL;
+ if (kcg->expected_response_code != ks->http_status)
+ {
+ TALER_TESTING_unexpected_status (is,
+ ks->http_status,
+ kcg->expected_response_code);
+ return;
+ }
+ switch (ks->http_status)
+ {
+ case MHD_HTTP_OK:
+ break;
+ case MHD_HTTP_ACCEPTED:
+ kcg->kyc_url = GNUNET_strdup (ks->details.accepted.kyc_url);
+ break;
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ TALER_TESTING_interpreter_next (kcg->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+check_kyc_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct KycCheckGetState *kcg = cls;
+ const struct TALER_TESTING_Command *res_cmd;
+ const uint64_t *requirement_row;
+ const struct TALER_PaytoHashP *h_payto;
+
+ (void) cmd;
+ kcg->is = is;
+ res_cmd = TALER_TESTING_interpreter_lookup_command (
+ kcg->is,
+ kcg->payment_target_reference);
+ if (NULL == res_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kcg->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_legi_requirement_row (res_cmd,
+ &requirement_row))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kcg->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_h_payto (res_cmd,
+ &h_payto))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kcg->is);
+ return;
+ }
+ if (0 == *requirement_row)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kcg->is);
+ return;
+ }
+ kcg->kwh = TALER_EXCHANGE_kyc_check (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ *requirement_row,
+ h_payto,
+ TALER_KYCLOGIC_KYC_UT_INDIVIDUAL,
+ GNUNET_TIME_UNIT_SECONDS,
+ &check_kyc_cb,
+ kcg);
+ GNUNET_assert (NULL != kcg->kwh);
+}
+
+
+/**
+ * Cleanup the state from a "track transaction" CMD, and possibly
+ * cancel a operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+check_kyc_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct KycCheckGetState *kcg = cls;
+
+ if (NULL != kcg->kwh)
+ {
+ TALER_TESTING_command_incomplete (kcg->is,
+ cmd->label);
+ TALER_EXCHANGE_kyc_check_cancel (kcg->kwh);
+ kcg->kwh = NULL;
+ }
+ GNUNET_free (kcg->kyc_url);
+ GNUNET_free (kcg);
+}
+
+
+/**
+ * Offer internal data from a "check KYC" CMD.
+ *
+ * @param cls closure.
+ * @param[out] ret result (could be anything).
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+check_kyc_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct KycCheckGetState *kcg = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_kyc_url (kcg->kyc_url),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_kyc_get (const char *label,
+ const char *payment_target_reference,
+ unsigned int expected_response_code)
+{
+ struct KycCheckGetState *kcg;
+
+ kcg = GNUNET_new (struct KycCheckGetState);
+ kcg->payment_target_reference = payment_target_reference;
+ kcg->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = kcg,
+ .label = label,
+ .run = &check_kyc_run,
+ .cleanup = &check_kyc_cleanup,
+ .traits = &check_kyc_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_kyc_check_get.c */
diff --git a/src/testing/testing_api_cmd_kyc_proof.c b/src/testing/testing_api_cmd_kyc_proof.c
new file mode 100644
index 000000000..b079fffce
--- /dev/null
+++ b/src/testing/testing_api_cmd_kyc_proof.c
@@ -0,0 +1,259 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_cmd_kyc_proof.c
+ * @brief Implement the testing CMDs for the /kyc-proof/ operation.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+/**
+ * State for a "track transaction" CMD.
+ */
+struct KycProofGetState
+{
+
+ /**
+ * Command to get a reserve private key from.
+ */
+ const char *payment_target_reference;
+
+ /**
+ * Code to pass.
+ */
+ const char *code;
+
+ /**
+ * Logic section name to pass to `/kyc-proof/` handler.
+ */
+ const char *logic;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Set to the KYC REDIRECT *if* the exchange replied with
+ * success (#MHD_HTTP_OK).
+ */
+ char *redirect_url;
+
+ /**
+ * Handle to the "track transaction" pending operation.
+ */
+ struct TALER_EXCHANGE_KycProofHandle *kph;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Handle response to the command.
+ *
+ * @param cls closure.
+ * @param kpr KYC proof response details
+ */
+static void
+proof_kyc_cb (void *cls,
+ const struct TALER_EXCHANGE_KycProofResponse *kpr)
+{
+ struct KycProofGetState *kcg = cls;
+ struct TALER_TESTING_Interpreter *is = kcg->is;
+
+ kcg->kph = NULL;
+ if (kcg->expected_response_code != kpr->http_status)
+ {
+ TALER_TESTING_unexpected_status (is,
+ kpr->http_status,
+ kcg->expected_response_code);
+ return;
+ }
+ switch (kpr->http_status)
+ {
+ case MHD_HTTP_SEE_OTHER:
+ kcg->redirect_url = GNUNET_strdup (kpr->details.found.redirect_url);
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ break;
+ case MHD_HTTP_BAD_GATEWAY:
+ break;
+ default:
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to /kyc-proof\n",
+ kpr->http_status);
+ break;
+ }
+ TALER_TESTING_interpreter_next (kcg->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+proof_kyc_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct KycProofGetState *kps = cls;
+ const struct TALER_TESTING_Command *res_cmd;
+ const struct TALER_PaytoHashP *h_payto;
+ char *uargs;
+ const char *exchange_url;
+
+ (void) cmd;
+ kps->is = is;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ res_cmd = TALER_TESTING_interpreter_lookup_command (
+ kps->is,
+ kps->payment_target_reference);
+ if (NULL == res_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kps->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_h_payto (res_cmd,
+ &h_payto))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kps->is);
+ return;
+ }
+ if (NULL == kps->code)
+ uargs = NULL;
+ else
+ GNUNET_asprintf (&uargs,
+ "&code=%s",
+ kps->code);
+ kps->kph = TALER_EXCHANGE_kyc_proof (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ h_payto,
+ kps->logic,
+ uargs,
+ &proof_kyc_cb,
+ kps);
+ GNUNET_free (uargs);
+ GNUNET_assert (NULL != kps->kph);
+}
+
+
+/**
+ * Cleanup the state from a "track transaction" CMD, and possibly
+ * cancel a operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+proof_kyc_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct KycProofGetState *kps = cls;
+
+ if (NULL != kps->kph)
+ {
+ TALER_TESTING_command_incomplete (kps->is,
+ cmd->label);
+ TALER_EXCHANGE_kyc_proof_cancel (kps->kph);
+ kps->kph = NULL;
+ }
+ GNUNET_free (kps->redirect_url);
+ GNUNET_free (kps);
+}
+
+
+/**
+ * Offer internal data from a "proof KYC" CMD.
+ *
+ * @param cls closure.
+ * @param[out] ret result (could be anything).
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+proof_kyc_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct KycProofGetState *kps = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_web_url (kps->redirect_url),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_proof_kyc_oauth2 (
+ const char *label,
+ const char *payment_target_reference,
+ const char *logic_section,
+ const char *code,
+ unsigned int expected_response_code)
+{
+ struct KycProofGetState *kps;
+
+ kps = GNUNET_new (struct KycProofGetState);
+ kps->code = code;
+ kps->logic = logic_section;
+ kps->payment_target_reference = payment_target_reference;
+ kps->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = kps,
+ .label = label,
+ .run = &proof_kyc_run,
+ .cleanup = &proof_kyc_cleanup,
+ .traits = &proof_kyc_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_kyc_proof.c */
diff --git a/src/testing/testing_api_cmd_kyc_wallet_get.c b/src/testing/testing_api_cmd_kyc_wallet_get.c
new file mode 100644
index 000000000..ffb143ffb
--- /dev/null
+++ b/src/testing/testing_api_cmd_kyc_wallet_get.c
@@ -0,0 +1,290 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_cmd_kyc_wallet_get.c
+ * @brief Implement the testing CMDs for the /kyc_wallet/ GET operations.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+/**
+ * State for a "/kyc-wallet" GET CMD.
+ */
+struct KycWalletGetState
+{
+
+ /**
+ * Private key of the reserve (account).
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Public key of the reserve (account).
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Payto URI of the reserve of the wallet.
+ */
+ char *reserve_payto_uri;
+
+ /**
+ * Our command.
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
+ * Command to get a reserve private key from.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Set to the KYC requirement payto hash *if* the exchange replied with a
+ * request for KYC (#MHD_HTTP_OK).
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC (#MHD_HTTP_OK).
+ */
+ uint64_t requirement_row;
+
+ /**
+ * Handle to the "track transaction" pending operation.
+ */
+ struct TALER_EXCHANGE_KycWalletHandle *kwh;
+
+ /**
+ * Balance to pass to the exchange.
+ */
+ struct TALER_Amount balance;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Handle response to the command.
+ *
+ * @param cls closure.
+ * @param wkr GET deposit response details
+ */
+static void
+wallet_kyc_cb (void *cls,
+ const struct TALER_EXCHANGE_WalletKycResponse *wkr)
+{
+ struct KycWalletGetState *kwg = cls;
+ struct TALER_TESTING_Interpreter *is = kwg->is;
+
+ kwg->kwh = NULL;
+ if (kwg->expected_response_code != wkr->http_status)
+ {
+ TALER_TESTING_unexpected_status (is,
+ wkr->http_status,
+ kwg->expected_response_code);
+ return;
+ }
+ switch (wkr->http_status)
+ {
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ kwg->requirement_row
+ = wkr->details.unavailable_for_legal_reasons.requirement_row;
+ kwg->h_payto
+ = wkr->details.unavailable_for_legal_reasons.h_payto;
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ TALER_TESTING_interpreter_next (kwg->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+wallet_kyc_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct KycWalletGetState *kwg = cls;
+ const char *exchange_url;
+
+ kwg->cmd = cmd;
+ kwg->is = is;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (NULL != kwg->reserve_reference)
+ {
+ const struct TALER_TESTING_Command *res_cmd;
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+
+ res_cmd = TALER_TESTING_interpreter_lookup_command (kwg->is,
+ kwg->reserve_reference);
+ if (NULL == res_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kwg->is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (res_cmd,
+ &reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (kwg->is);
+ return;
+ }
+ kwg->reserve_priv = *reserve_priv;
+ }
+ else
+ {
+ GNUNET_CRYPTO_eddsa_key_create (&kwg->reserve_priv.eddsa_priv);
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&kwg->reserve_priv.eddsa_priv,
+ &kwg->reserve_pub.eddsa_pub);
+ kwg->reserve_payto_uri
+ = TALER_reserve_make_payto (exchange_url,
+ &kwg->reserve_pub);
+ kwg->kwh = TALER_EXCHANGE_kyc_wallet (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ &kwg->reserve_priv,
+ &kwg->balance,
+ &wallet_kyc_cb,
+ kwg);
+ GNUNET_assert (NULL != kwg->kwh);
+}
+
+
+/**
+ * Cleanup the state from a "track transaction" CMD, and possibly
+ * cancel a operation thereof.
+ *
+ * @param cls closure with our `struct KycWalletGetState`
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+wallet_kyc_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct KycWalletGetState *kwg = cls;
+
+ if (NULL != kwg->kwh)
+ {
+ TALER_TESTING_command_incomplete (kwg->is,
+ cmd->label);
+ TALER_EXCHANGE_kyc_wallet_cancel (kwg->kwh);
+ kwg->kwh = NULL;
+ }
+ GNUNET_free (kwg->reserve_payto_uri);
+ GNUNET_free (kwg);
+}
+
+
+/**
+ * Offer internal data from a "wallet KYC" CMD.
+ *
+ * @param cls closure.
+ * @param[out] ret result (could be anything).
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+wallet_kyc_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct KycWalletGetState *kwg = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_reserve_priv (&kwg->reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (&kwg->reserve_pub),
+ TALER_TESTING_make_trait_legi_requirement_row (&kwg->requirement_row),
+ TALER_TESTING_make_trait_h_payto (&kwg->h_payto),
+ TALER_TESTING_make_trait_payto_uri (kwg->reserve_payto_uri),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wallet_kyc_get (const char *label,
+ const char *reserve_reference,
+ const char *threshold_balance,
+ unsigned int expected_response_code)
+{
+ struct KycWalletGetState *kwg;
+
+ kwg = GNUNET_new (struct KycWalletGetState);
+ kwg->reserve_reference = reserve_reference;
+ kwg->expected_response_code = expected_response_code;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (threshold_balance,
+ &kwg->balance));
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = kwg,
+ .label = label,
+ .run = &wallet_kyc_run,
+ .cleanup = &wallet_kyc_cleanup,
+ .traits = &wallet_kyc_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_kyc_wallet_get.c */
diff --git a/src/testing/testing_api_cmd_oauth.c b/src/testing/testing_api_cmd_oauth.c
new file mode 100644
index 000000000..80d38e4c8
--- /dev/null
+++ b/src/testing/testing_api_cmd_oauth.c
@@ -0,0 +1,412 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_cmd_oauth.c
+ * @brief Implement a CMD to run an OAuth service for faking the legitimation service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_mhd_lib.h"
+
+/**
+ * State for the oauth CMD.
+ */
+struct OAuthState
+{
+
+ /**
+ * Handle to the "oauth" service.
+ */
+ struct MHD_Daemon *mhd;
+
+ /**
+ * Birthdate that the oauth server should return in a response, may be NULL
+ */
+ const char *birthdate;
+
+ /**
+ * Port to listen on.
+ */
+ uint16_t port;
+};
+
+
+struct RequestCtx
+{
+ struct MHD_PostProcessor *pp;
+ char *code;
+ char *client_id;
+ char *redirect_uri;
+ char *client_secret;
+};
+
+
+static void
+append (char **target,
+ const char *data,
+ size_t size)
+{
+ char *tmp;
+
+ if (NULL == *target)
+ {
+ *target = GNUNET_strndup (data,
+ size);
+ return;
+ }
+ GNUNET_asprintf (&tmp,
+ "%s%.*s",
+ *target,
+ (int) size,
+ data);
+ GNUNET_free (*target);
+ *target = tmp;
+}
+
+
+static MHD_RESULT
+handle_post (void *cls,
+ enum MHD_ValueKind kind,
+ const char *key,
+ const char *filename,
+ const char *content_type,
+ const char *transfer_encoding,
+ const char *data,
+ uint64_t off,
+ size_t size)
+{
+ struct RequestCtx *rc = cls;
+
+ (void) kind;
+ (void) filename;
+ (void) content_type;
+ (void) transfer_encoding;
+ (void) off;
+ if (0 == strcmp (key,
+ "code"))
+ append (&rc->code,
+ data,
+ size);
+ if (0 == strcmp (key,
+ "client_id"))
+ append (&rc->client_id,
+ data,
+ size);
+ if (0 == strcmp (key,
+ "redirect_uri"))
+ append (&rc->redirect_uri,
+ data,
+ size);
+ if (0 == strcmp (key,
+ "client_secret"))
+ append (&rc->client_secret,
+ data,
+ size);
+ return MHD_YES;
+}
+
+
+/**
+ * A client has requested the given url using the given method
+ * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
+ * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback
+ * must call MHD callbacks to provide content to give back to the
+ * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
+ * #MHD_HTTP_NOT_FOUND, etc.).
+ *
+ * @param cls argument given together with the function
+ * pointer when the handler was registered with MHD
+ * @param connection the connection being handled
+ * @param url the requested url
+ * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
+ * #MHD_HTTP_METHOD_PUT, etc.)
+ * @param version the HTTP version string (i.e.
+ * MHD_HTTP_VERSION_1_1)
+ * @param upload_data the data being uploaded (excluding HEADERS,
+ * for a POST that fits into memory and that is encoded
+ * with a supported encoding, the POST data will NOT be
+ * given in upload_data and is instead available as
+ * part of MHD_get_connection_values(); very large POST
+ * data *will* be made available incrementally in
+ * @a upload_data)
+ * @param[in,out] upload_data_size set initially to the size of the
+ * @a upload_data provided; the method must update this
+ * value to the number of bytes NOT processed;
+ * @param[in,out] con_cls pointer that the callback can set to some
+ * address and that will be preserved by MHD for future
+ * calls for this request; since the access handler may
+ * be called many times (i.e., for a PUT/POST operation
+ * with plenty of upload data) this allows the application
+ * to easily associate some request-specific state.
+ * If necessary, this state can be cleaned up in the
+ * global MHD_RequestCompletedCallback (which
+ * can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
+ * Initially, `*con_cls` will be NULL.
+ * @return #MHD_YES if the connection was handled successfully,
+ * #MHD_NO if the socket must be closed due to a serious
+ * error while handling the request
+ */
+static MHD_RESULT
+handler_cb (void *cls,
+ struct MHD_Connection *connection,
+ const char *url,
+ const char *method,
+ const char *version,
+ const char *upload_data,
+ size_t *upload_data_size,
+ void **con_cls)
+{
+ struct RequestCtx *rc = *con_cls;
+ struct OAuthState *oas = cls;
+ unsigned int hc;
+ json_t *body;
+
+ (void) version;
+ if (0 == strcasecmp (method,
+ MHD_HTTP_METHOD_GET))
+ {
+ json_t *data =
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("id",
+ "XXXID12345678"),
+ GNUNET_JSON_pack_string ("first_name",
+ "Bob"),
+ GNUNET_JSON_pack_string ("last_name",
+ "Builder"));
+
+ if (NULL != oas->birthdate)
+ GNUNET_assert (0 ==
+ json_object_set_new (data,
+ "birthdate",
+ json_string_nocheck (
+ oas->birthdate)));
+
+ body = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string (
+ "status",
+ "success"),
+ GNUNET_JSON_pack_object_steal (
+ "data", data));
+ return TALER_MHD_reply_json_steal (connection,
+ body,
+ MHD_HTTP_OK);
+ }
+ if (0 != strcasecmp (method,
+ MHD_HTTP_METHOD_POST))
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ if (NULL == rc)
+ {
+ rc = GNUNET_new (struct RequestCtx);
+ *con_cls = rc;
+ rc->pp = MHD_create_post_processor (connection,
+ 4092,
+ &handle_post,
+ rc);
+ return MHD_YES;
+ }
+ if (0 != *upload_data_size)
+ {
+ MHD_RESULT ret;
+
+ ret = MHD_post_process (rc->pp,
+ upload_data,
+ *upload_data_size);
+ *upload_data_size = 0;
+ return ret;
+ }
+
+
+ /* NOTE: In the future, we MAY want to distinguish between
+ the different URLs and possibly return more information.
+ For now, just do the minimum: implement the main handler
+ that checks the code. */
+ if ( (NULL == rc->code) ||
+ (NULL == rc->client_id) ||
+ (NULL == rc->redirect_uri) ||
+ (NULL == rc->client_secret) )
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Bad request to Oauth faker: `%s' with %s/%s/%s/%s\n",
+ url,
+ rc->code,
+ rc->client_id,
+ rc->redirect_uri,
+ rc->client_secret);
+ return MHD_NO;
+ }
+ if (0 != strcmp (rc->client_id,
+ "taler-exchange"))
+ {
+ body = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("error",
+ "unknown_client"),
+ GNUNET_JSON_pack_string ("error_description",
+ "only 'taler-exchange' is allowed"));
+ hc = MHD_HTTP_NOT_FOUND;
+ }
+ else if (0 != strcmp (rc->client_secret,
+ "exchange-secret"))
+ {
+ body = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("error",
+ "invalid_client_secret"),
+ GNUNET_JSON_pack_string ("error_description",
+ "only 'exchange-secret' is valid"));
+ hc = MHD_HTTP_FORBIDDEN;
+ }
+ else
+ {
+ if (0 != strcmp (rc->code,
+ "pass"))
+ {
+ body = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("error",
+ "invalid_grant"),
+ GNUNET_JSON_pack_string ("error_description",
+ "only 'pass' shall pass"));
+ hc = MHD_HTTP_FORBIDDEN;
+ }
+ else
+ {
+ body = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("access_token",
+ "good"),
+ GNUNET_JSON_pack_string ("token_type",
+ "bearer"),
+ GNUNET_JSON_pack_uint64 ("expires_in",
+ 3600),
+ GNUNET_JSON_pack_string ("refresh_token",
+ "better"));
+ hc = MHD_HTTP_OK;
+ }
+ }
+ return TALER_MHD_reply_json_steal (connection,
+ body,
+ hc);
+}
+
+
+static void
+cleanup (void *cls,
+ struct MHD_Connection *connection,
+ void **con_cls,
+ enum MHD_RequestTerminationCode toe)
+{
+ struct RequestCtx *rc = *con_cls;
+
+ (void) cls;
+ (void) connection;
+ (void) toe;
+ if (NULL == rc)
+ return;
+ MHD_destroy_post_processor (rc->pp);
+ GNUNET_free (rc->code);
+ GNUNET_free (rc->client_id);
+ GNUNET_free (rc->redirect_uri);
+ GNUNET_free (rc->client_secret);
+ GNUNET_free (rc);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+oauth_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct OAuthState *oas = cls;
+
+ (void) cmd;
+ oas->mhd = MHD_start_daemon (MHD_USE_AUTO_INTERNAL_THREAD | MHD_USE_DEBUG,
+ oas->port,
+ NULL, NULL,
+ &handler_cb, oas,
+ MHD_OPTION_NOTIFY_COMPLETED, &cleanup, NULL,
+ NULL);
+ if (NULL == oas->mhd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Cleanup the state from a "oauth" CMD, and possibly cancel a operation
+ * thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+oauth_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct OAuthState *oas = cls;
+
+ (void) cmd;
+ if (NULL != oas->mhd)
+ {
+ MHD_stop_daemon (oas->mhd);
+ oas->mhd = NULL;
+ }
+ GNUNET_free (oas);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_oauth_with_birthdate (const char *label,
+ const char *birthdate,
+ uint16_t port)
+{
+ struct OAuthState *oas;
+
+ oas = GNUNET_new (struct OAuthState);
+ oas->port = port;
+ oas->birthdate = birthdate;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = oas,
+ .label = label,
+ .run = &oauth_run,
+ .cleanup = &oauth_cleanup,
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_oauth.c */
diff --git a/src/testing/testing_api_cmd_offline_sign_extensions.c b/src/testing/testing_api_cmd_offline_sign_extensions.c
new file mode 100644
index 000000000..f39679f97
--- /dev/null
+++ b/src/testing/testing_api_cmd_offline_sign_extensions.c
@@ -0,0 +1,164 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not,
+ see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_cmd_offline_sign_extensions.c
+ * @brief run the taler-exchange-offline command to sign extensions (and therefore activate them)
+ * @author Özgür Kesim
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "extensionssign" CMD.
+ */
+struct ExtensionsSignState
+{
+
+ /**
+ * Process for the "extensionssign" command.
+ */
+ struct GNUNET_OS_Process *extensionssign_proc;
+
+ /**
+ * Configuration file used by the command.
+ */
+ const char *config_filename;
+
+};
+
+
+/**
+ * Run the command; calls the `taler-exchange-offline' program.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+extensionssign_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ExtensionsSignState *ks = cls;
+
+ ks->extensionssign_proc
+ = GNUNET_OS_start_process (
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-offline",
+ "taler-exchange-offline",
+ "-c", ks->config_filename,
+ "-L", "INFO",
+ "extensions",
+ "sign",
+ "upload",
+ NULL);
+ if (NULL == ks->extensionssign_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "extensionssign" CMD, and possibly kills its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+extensionssign_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ExtensionsSignState *ks = cls;
+
+ (void) cmd;
+ if (NULL != ks->extensionssign_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ks->extensionssign_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ks->extensionssign_proc);
+ GNUNET_OS_process_destroy (ks->extensionssign_proc);
+ ks->extensionssign_proc = NULL;
+ }
+ GNUNET_free (ks);
+}
+
+
+/**
+ * Offer "extensionssign" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+extensionssign_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct ExtensionsSignState *ks = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (&ks->extensionssign_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_offline_sign_extensions (const char *label,
+ const char *config_filename)
+{
+ struct ExtensionsSignState *ks;
+
+ ks = GNUNET_new (struct ExtensionsSignState);
+ ks->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ks,
+ .label = label,
+ .run = &extensionssign_run,
+ .cleanup = &extensionssign_cleanup,
+ .traits = &extensionssign_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_offline_sign_extensions.c */
diff --git a/src/testing/testing_api_cmd_offline_sign_global_fees.c b/src/testing/testing_api_cmd_offline_sign_global_fees.c
new file mode 100644
index 000000000..db3916258
--- /dev/null
+++ b/src/testing/testing_api_cmd_offline_sign_global_fees.c
@@ -0,0 +1,230 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not,
+ see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_cmd_offline_sign_global_fees.c
+ * @brief run the taler-exchange-offline command to download, sign and upload global fees
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "offlinesign" CMD.
+ */
+struct OfflineSignState
+{
+
+ /**
+ * Process for the "offlinesign" command.
+ */
+ struct GNUNET_OS_Process *offlinesign_proc;
+
+ /**
+ * Configuration file used by the command.
+ */
+ const char *config_filename;
+
+ /**
+ * The history fee to sign.
+ */
+ const char *history_fee_s;
+
+ /**
+ * The account fee to sign.
+ */
+ const char *account_fee_s;
+
+ /**
+ * The purse fee to sign.
+ */
+ const char *purse_fee_s;
+
+ /**
+ * When MUST purses time out?
+ */
+ struct GNUNET_TIME_Relative purse_timeout;
+
+ /**
+ * How long do we keep the history?
+ */
+ struct GNUNET_TIME_Relative history_expiration;
+
+ /**
+ * Number of (free) purses per account.
+ */
+ unsigned int num_purses;
+};
+
+
+/**
+ * Run the command; calls the `taler-exchange-offline' program.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+offlinesign_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct OfflineSignState *ks = cls;
+ char num_purses[12];
+ char history_expiration[32];
+ char purse_timeout[32];
+
+ GNUNET_snprintf (num_purses,
+ sizeof (num_purses),
+ "%u",
+ ks->num_purses);
+ GNUNET_snprintf (history_expiration,
+ sizeof (history_expiration),
+ "%s",
+ GNUNET_TIME_relative2s (ks->history_expiration,
+ false));
+ GNUNET_snprintf (purse_timeout,
+ sizeof (purse_timeout),
+ "%s",
+ GNUNET_TIME_relative2s (ks->purse_timeout,
+ false));
+ ks->offlinesign_proc
+ = GNUNET_OS_start_process (
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-offline",
+ "taler-exchange-offline",
+ "-c", ks->config_filename,
+ "-L", "INFO",
+ "global-fee",
+ "now",
+ ks->history_fee_s,
+ ks->account_fee_s,
+ ks->purse_fee_s,
+ purse_timeout,
+ history_expiration,
+ num_purses,
+ "upload",
+ NULL);
+ if (NULL == ks->offlinesign_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "offlinesign" CMD, and possibly kills its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+offlinesign_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct OfflineSignState *ks = cls;
+
+ (void) cmd;
+ if (NULL != ks->offlinesign_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ks->offlinesign_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ks->offlinesign_proc);
+ GNUNET_OS_process_destroy (ks->offlinesign_proc);
+ ks->offlinesign_proc = NULL;
+ }
+ GNUNET_free (ks);
+}
+
+
+/**
+ * Offer "offlinesign" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+offlinesign_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct OfflineSignState *ks = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (&ks->offlinesign_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_offline_sign_global_fees (
+ const char *label,
+ const char *config_filename,
+ const char *history_fee,
+ const char *account_fee,
+ const char *purse_fee,
+ struct GNUNET_TIME_Relative purse_timeout,
+ struct GNUNET_TIME_Relative history_expiration,
+ unsigned int num_purses)
+{
+ struct OfflineSignState *ks;
+
+ ks = GNUNET_new (struct OfflineSignState);
+ ks->config_filename = config_filename;
+ ks->history_fee_s = history_fee;
+ ks->account_fee_s = account_fee;
+ ks->purse_fee_s = purse_fee;
+ ks->purse_timeout = purse_timeout;
+ ks->history_expiration = history_expiration;
+ ks->num_purses = num_purses;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ks,
+ .label = label,
+ .run = &offlinesign_run,
+ .cleanup = &offlinesign_cleanup,
+ .traits = &offlinesign_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_offline_sign_global_fees.c */
diff --git a/src/testing/testing_api_cmd_offline_sign_keys.c b/src/testing/testing_api_cmd_offline_sign_keys.c
index dd6170d90..2c99219b6 100644
--- a/src/testing/testing_api_cmd_offline_sign_keys.c
+++ b/src/testing/testing_api_cmd_offline_sign_keys.c
@@ -121,7 +121,7 @@ offlinesign_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
offlinesign_traits (void *cls,
const void **ret,
const char *trait,
@@ -129,8 +129,7 @@ offlinesign_traits (void *cls,
{
struct OfflineSignState *ks = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0,
- &ks->offlinesign_proc),
+ TALER_TESTING_make_trait_process (&ks->offlinesign_proc),
TALER_TESTING_trait_end ()
};
diff --git a/src/testing/testing_api_cmd_offline_sign_fees.c b/src/testing/testing_api_cmd_offline_sign_wire_fees.c
index 500953202..0fccbcd0a 100644
--- a/src/testing/testing_api_cmd_offline_sign_fees.c
+++ b/src/testing/testing_api_cmd_offline_sign_wire_fees.c
@@ -18,7 +18,7 @@
*/
/**
- * @file testing/testing_api_cmd_offline_sign_fees.c
+ * @file testing/testing_api_cmd_offline_sign_wire_fees.c
* @brief run the taler-exchange-offline command to download, sign and upload wire fees
* @author Marcello Stanisci
* @author Christian Grothoff
@@ -134,7 +134,7 @@ offlinesign_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
offlinesign_traits (void *cls,
const void **ret,
const char *trait,
@@ -142,8 +142,7 @@ offlinesign_traits (void *cls,
{
struct OfflineSignState *ks = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0,
- &ks->offlinesign_proc),
+ TALER_TESTING_make_trait_process (&ks->offlinesign_proc),
TALER_TESTING_trait_end ()
};
@@ -154,15 +153,6 @@ offlinesign_traits (void *cls,
}
-/**
- * Sign a wire fee.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @param wire_fee the wire fee to affirm (for the current year)
- * @param closing_fee the closing fee to affirm (for the current year)
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_exec_offline_sign_fees (const char *label,
const char *config_filename,
diff --git a/src/testing/testing_api_cmd_purse_create_deposit.c b/src/testing/testing_api_cmd_purse_create_deposit.c
new file mode 100644
index 000000000..4740f9801
--- /dev/null
+++ b/src/testing/testing_api_cmd_purse_create_deposit.c
@@ -0,0 +1,450 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_purse_create_deposit.c
+ * @brief command for testing /purses/$PID/create
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+/**
+ * Information we keep per deposited coin.
+ */
+struct Coin
+{
+ /**
+ * Reference to the respective command.
+ */
+ char *command_ref;
+
+ /**
+ * index of the specific coin in the traits of @e command_ref.
+ */
+ unsigned int coin_index;
+
+ /**
+ * Public key of the deposited coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * Amount to deposit (with fee).
+ */
+ struct TALER_Amount deposit_with_fee;
+
+ /**
+ * Entry in the coin's history generated by this operation.
+ */
+ struct TALER_EXCHANGE_CoinHistoryEntry che;
+
+};
+
+
+/**
+ * State for a "purse create deposit" CMD.
+ */
+struct PurseCreateDepositState
+{
+
+ /**
+ * Total purse target amount without fees.
+ */
+ struct TALER_Amount target_amount;
+
+ /**
+ * Reference to any command that is able to provide a coin.
+ */
+ struct Coin *coin_references;
+
+ /**
+ * JSON string describing what a proposal is about.
+ */
+ json_t *contract_terms;
+
+ /**
+ * Purse expiration time.
+ */
+ struct GNUNET_TIME_Timestamp purse_expiration;
+
+ /**
+ * Relative purse expiration time.
+ */
+ struct GNUNET_TIME_Relative rel_expiration;
+
+ /**
+ * Set (by the interpreter) to a fresh private key. This
+ * key will be used to create the purse.
+ */
+ struct TALER_PurseContractPrivateKeyP purse_priv;
+
+ /**
+ * Set (by the interpreter) to a fresh private key. This
+ * key will be used to merge the purse.
+ */
+ struct TALER_PurseMergePrivateKeyP merge_priv;
+
+ /**
+ * Set (by the interpreter) to a fresh private key. This
+ * key will be used to decrypt the contract.
+ */
+ struct TALER_ContractDiffiePrivateP contract_priv;
+
+ /**
+ * Signing key used by the exchange to sign the
+ * deposit confirmation.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * Signature from the exchange on the
+ * deposit confirmation.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+ /**
+ * Set (by the interpreter) to a public key corresponding
+ * to @e purse_priv.
+ */
+ struct TALER_PurseContractPublicKeyP purse_pub;
+
+ /**
+ * PurseCreateDeposit handle while operation is running.
+ */
+ struct TALER_EXCHANGE_PurseCreateDepositHandle *dh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Length of the @e coin_references array.
+ */
+ unsigned int num_coin_references;
+
+ /**
+ * Should we upload the contract?
+ */
+ bool upload_contract;
+
+};
+
+
+/**
+ * Callback to analyze the /purses/$PID/create response, just used to check if
+ * the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param dr deposit response details
+ */
+static void
+deposit_cb (void *cls,
+ const struct TALER_EXCHANGE_PurseCreateDepositResponse *dr)
+{
+ struct PurseCreateDepositState *ds = cls;
+
+ ds->dh = NULL;
+ if (ds->expected_response_code != dr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ dr->hr.http_status,
+ ds->expected_response_code);
+ return;
+ }
+ if (MHD_HTTP_OK == dr->hr.http_status)
+ {
+ ds->exchange_pub = dr->details.ok.exchange_pub;
+ ds->exchange_sig = dr->details.ok.exchange_sig;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+deposit_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PurseCreateDepositState *ds = cls;
+ struct TALER_EXCHANGE_PurseDeposit deposits[ds->num_coin_references];
+
+ (void) cmd;
+ ds->is = is;
+ GNUNET_CRYPTO_eddsa_key_create (&ds->purse_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_create (&ds->merge_priv.eddsa_priv);
+ GNUNET_CRYPTO_ecdhe_key_create (&ds->contract_priv.ecdhe_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->purse_priv.eddsa_priv,
+ &ds->purse_pub.eddsa_pub);
+
+ for (unsigned int i = 0; i<ds->num_coin_references; i++)
+ {
+ struct Coin *cr = &ds->coin_references[i];
+ struct TALER_EXCHANGE_PurseDeposit *pd = &deposits[i];
+ const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+ const struct TALER_DenominationSignature *denom_pub_sig;
+
+ coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ cr->command_ref);
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ cr->coin_index,
+ &coin_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
+ cr->coin_index,
+ &age_commitment_proof))
+ ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (coin_cmd,
+ cr->coin_index,
+ &denom_pub)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_sig (coin_cmd,
+ cr->coin_index,
+ &denom_pub_sig)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ pd->age_commitment_proof = age_commitment_proof;
+ pd->denom_sig = *denom_pub_sig;
+ pd->coin_priv = *coin_priv;
+ pd->amount = cr->deposit_with_fee;
+ pd->h_denom_pub = denom_pub->h_key;
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &cr->coin_pub.eddsa_pub);
+ cr->che.type = TALER_EXCHANGE_CTT_PURSE_DEPOSIT;
+ cr->che.amount = cr->deposit_with_fee;
+ GNUNET_CRYPTO_eddsa_key_get_public (
+ &ds->purse_priv.eddsa_priv,
+ &cr->che.details.purse_deposit.purse_pub.eddsa_pub);
+ cr->che.details.purse_deposit.exchange_base_url
+ = TALER_TESTING_get_exchange_url (is);
+ TALER_age_commitment_hash (
+ &age_commitment_proof->commitment,
+ &cr->che.details.purse_deposit.phac);
+ }
+
+ ds->purse_expiration =
+ GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_relative_to_absolute (ds->rel_expiration));
+ GNUNET_assert (0 ==
+ json_object_set_new (
+ ds->contract_terms,
+ "pay_deadline",
+ GNUNET_JSON_from_timestamp (ds->purse_expiration)));
+ ds->dh = TALER_EXCHANGE_purse_create_with_deposit (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ &ds->purse_priv,
+ &ds->merge_priv,
+ &ds->contract_priv,
+ ds->contract_terms,
+ ds->num_coin_references,
+ deposits,
+ ds->upload_contract,
+ &deposit_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not create purse with deposit\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "deposit" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct PurseCreateDepositState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+deposit_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PurseCreateDepositState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_purse_create_with_deposit_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ for (unsigned int i = 0; i<ds->num_coin_references; i++)
+ GNUNET_free (ds->coin_references[i].command_ref);
+ json_decref (ds->contract_terms);
+ GNUNET_free (ds->coin_references);
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data from a "deposit" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+deposit_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct PurseCreateDepositState *ds = cls;
+ if (index >= ds->num_coin_references)
+ return GNUNET_NO;
+
+ {
+ const struct Coin *co = &ds->coin_references[index];
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
+ TALER_TESTING_make_trait_contract_priv (&ds->contract_priv),
+ TALER_TESTING_make_trait_coin_history (index,
+ &co->che),
+ TALER_TESTING_make_trait_coin_pub (index,
+ &co->coin_pub),
+ TALER_TESTING_make_trait_purse_priv (&ds->purse_priv),
+ TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
+ TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
+ TALER_TESTING_make_trait_deposit_amount (0,
+ &ds->target_amount),
+ TALER_TESTING_make_trait_timestamp (index,
+ &ds->purse_expiration),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_purse_create_with_deposit (
+ const char *label,
+ unsigned int expected_http_status,
+ const char *contract_terms,
+ bool upload_contract,
+ struct GNUNET_TIME_Relative purse_expiration,
+ ...)
+{
+ struct PurseCreateDepositState *ds;
+
+ ds = GNUNET_new (struct PurseCreateDepositState);
+ ds->rel_expiration = purse_expiration;
+ ds->upload_contract = upload_contract;
+ ds->expected_response_code = expected_http_status;
+ ds->contract_terms = json_loads (contract_terms,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ if (NULL == ds->contract_terms)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse contract terms `%s' for CMD `%s'\n",
+ contract_terms,
+ label);
+ GNUNET_assert (0);
+ }
+ {
+ va_list ap;
+ unsigned int i;
+ const char *ref;
+ const char *val;
+
+ va_start (ap, purse_expiration);
+ while (NULL != (va_arg (ap, const char *)))
+ ds->num_coin_references++;
+ va_end (ap);
+ GNUNET_assert (0 == (ds->num_coin_references % 2));
+ ds->num_coin_references /= 2;
+ ds->coin_references = GNUNET_new_array (ds->num_coin_references,
+ struct Coin);
+ i = 0;
+ va_start (ap, purse_expiration);
+ while (NULL != (ref = va_arg (ap, const char *)))
+ {
+ struct Coin *c = &ds->coin_references[i++];
+
+ GNUNET_assert (NULL != (val = va_arg (ap, const char *)));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_parse_coin_reference (
+ ref,
+ &c->command_ref,
+ &c->coin_index));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (val,
+ &c->deposit_with_fee));
+ }
+ va_end (ap);
+ }
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &deposit_run,
+ .cleanup = &deposit_cleanup,
+ .traits = &deposit_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_purse_create_deposit.c */
diff --git a/src/testing/testing_api_cmd_purse_delete.c b/src/testing/testing_api_cmd_purse_delete.c
new file mode 100644
index 000000000..26037359e
--- /dev/null
+++ b/src/testing/testing_api_cmd_purse_delete.c
@@ -0,0 +1,189 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_purse_delete.c
+ * @brief command for testing /management/purse/disable.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "purse_delete" CMD.
+ */
+struct PurseDeleteState
+{
+
+ /**
+ * Purse delete handle while operation is running.
+ */
+ struct TALER_EXCHANGE_PurseDeleteHandle *pdh;
+
+ /**
+ * Our interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Command that created the purse we now want to
+ * delete.
+ */
+ const char *purse_cmd;
+};
+
+
+/**
+ * Callback to analyze the DELETE /purses/$PID response, just used to check if
+ * the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param pdr HTTP response details
+ */
+static void
+purse_delete_cb (void *cls,
+ const struct TALER_EXCHANGE_PurseDeleteResponse *pdr)
+{
+ struct PurseDeleteState *pds = cls;
+
+ pds->pdh = NULL;
+ if (pds->expected_response_code != pdr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (pds->is,
+ pdr->hr.http_status,
+ pds->expected_response_code);
+ return;
+ }
+ TALER_TESTING_interpreter_next (pds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+purse_delete_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PurseDeleteState *pds = cls;
+ const struct TALER_PurseContractPrivateKeyP *purse_priv;
+ const struct TALER_TESTING_Command *ref;
+ const char *exchange_url;
+
+ (void) cmd;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ pds->purse_cmd);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_purse_priv (ref,
+ &purse_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ pds->is = is;
+ pds->pdh = TALER_EXCHANGE_purse_delete (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ purse_priv,
+ &purse_delete_cb,
+ pds);
+ if (NULL == pds->pdh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "purse_delete" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct PurseDeleteState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+purse_delete_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PurseDeleteState *pds = cls;
+
+ if (NULL != pds->pdh)
+ {
+ TALER_TESTING_command_incomplete (pds->is,
+ cmd->label);
+ TALER_EXCHANGE_purse_delete_cancel (pds->pdh);
+ pds->pdh = NULL;
+ }
+ GNUNET_free (pds);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_purse_delete (const char *label,
+ unsigned int expected_http_status,
+ const char *purse_cmd)
+{
+ struct PurseDeleteState *ds;
+
+ ds = GNUNET_new (struct PurseDeleteState);
+ ds->expected_response_code = expected_http_status;
+ ds->purse_cmd = purse_cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &purse_delete_run,
+ .cleanup = &purse_delete_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_purse_delete.c */
diff --git a/src/testing/testing_api_cmd_purse_deposit.c b/src/testing/testing_api_cmd_purse_deposit.c
new file mode 100644
index 000000000..048c6d736
--- /dev/null
+++ b/src/testing/testing_api_cmd_purse_deposit.c
@@ -0,0 +1,491 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022, 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_purse_deposit.c
+ * @brief command for testing /purses/$PID/create
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+/**
+ * Information we keep per deposited coin.
+ */
+struct Coin
+{
+ /**
+ * Reference to the respective command.
+ */
+ char *command_ref;
+
+ /**
+ * Entry in the coin's history generated by this operation.
+ */
+ struct TALER_EXCHANGE_CoinHistoryEntry che;
+
+ /**
+ * Public key of the deposited coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ /**
+ * index of the specific coin in the traits of @e command_ref.
+ */
+ unsigned int coin_index;
+
+ /**
+ * Amount to deposit (with fee).
+ */
+ struct TALER_Amount deposit_with_fee;
+
+};
+
+
+/**
+ * State for a "purse deposit" CMD.
+ */
+struct PurseDepositState
+{
+
+ /**
+ * Total purse target amount without fees.
+ */
+ struct TALER_Amount target_amount;
+
+ /**
+ * Reference to any command that is able to provide a coin.
+ */
+ struct Coin *coin_references;
+
+ /**
+ * The purse's public key.
+ */
+ struct TALER_PurseContractPublicKeyP purse_pub;
+
+ /**
+ * The reserve we are being deposited into.
+ * Set as a trait once we know the reserve.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * PurseDeposit handle while operation is running.
+ */
+ struct TALER_EXCHANGE_PurseDepositHandle *dh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Reference to the command that established the purse.
+ */
+ const char *purse_ref;
+
+ /**
+ * Reserve history entry that corresponds to this operation.
+ * Will be of type #TALER_EXCHANGE_RTT_MERGE.
+ * Only valid if @e purse_complete is true.
+ */
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Length of the @e coin_references array.
+ */
+ unsigned int num_coin_references;
+
+ /**
+ * Minimum age to apply to all deposits.
+ */
+ uint8_t min_age;
+
+ /**
+ * Set to true if this deposit filled the purse.
+ */
+ bool purse_complete;
+};
+
+
+/**
+ * Callback to analyze the /purses/$PID/deposit response, just used to check if
+ * the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param dr deposit response details
+ */
+static void
+deposit_cb (void *cls,
+ const struct TALER_EXCHANGE_PurseDepositResponse *dr)
+{
+ struct PurseDepositState *ds = cls;
+
+ ds->dh = NULL;
+ if (ds->expected_response_code != dr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ dr->hr.http_status,
+ ds->expected_response_code);
+ return;
+ }
+ if (MHD_HTTP_OK == dr->hr.http_status)
+ {
+ if (-1 !=
+ TALER_amount_cmp (&dr->details.ok.total_deposited,
+ &dr->details.ok.purse_value_after_fees))
+ {
+ const struct TALER_TESTING_Command *purse_cmd;
+ const struct TALER_ReserveSignatureP *reserve_sig;
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+ const struct GNUNET_TIME_Timestamp *merge_timestamp;
+ const struct TALER_PurseMergePublicKeyP *merge_pub;
+
+ purse_cmd = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->purse_ref);
+ GNUNET_assert (NULL != purse_cmd);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_sig (purse_cmd,
+ &reserve_sig))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (purse_cmd,
+ &reserve_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_merge_pub (purse_cmd,
+ &merge_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ ds->reserve_pub = *reserve_pub;
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_timestamp (purse_cmd,
+ 0,
+ &merge_timestamp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+
+ /* Deposits complete, create trait! */
+ ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE;
+ {
+ struct TALER_EXCHANGE_Keys *keys;
+ const struct TALER_EXCHANGE_GlobalFee *gf;
+
+ keys = TALER_TESTING_get_keys (ds->is);
+ GNUNET_assert (NULL != keys);
+ gf = TALER_EXCHANGE_get_global_fee (keys,
+ *merge_timestamp);
+ GNUNET_assert (NULL != gf);
+
+ /* Note: change when flags below changes! */
+ ds->reserve_history.amount
+ = dr->details.ok.purse_value_after_fees;
+ if (true)
+ {
+ ds->reserve_history.details.merge_details.purse_fee = gf->fees.purse;
+ }
+ else
+ {
+ TALER_amount_set_zero (
+ ds->reserve_history.amount.currency,
+ &ds->reserve_history.details.merge_details.purse_fee);
+ }
+ }
+ ds->reserve_history.details.merge_details.h_contract_terms
+ = dr->details.ok.h_contract_terms;
+ ds->reserve_history.details.merge_details.merge_pub
+ = *merge_pub;
+ ds->reserve_history.details.merge_details.purse_pub
+ = ds->purse_pub;
+ ds->reserve_history.details.merge_details.reserve_sig
+ = *reserve_sig;
+ ds->reserve_history.details.merge_details.merge_timestamp
+ = *merge_timestamp;
+ ds->reserve_history.details.merge_details.purse_expiration
+ = dr->details.ok.purse_expiration;
+ ds->reserve_history.details.merge_details.min_age
+ = ds->min_age;
+ ds->reserve_history.details.merge_details.flags
+ = TALER_WAMF_MODE_CREATE_WITH_PURSE_FEE;
+ ds->purse_complete = true;
+ }
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+deposit_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PurseDepositState *ds = cls;
+ struct TALER_EXCHANGE_PurseDeposit deposits[ds->num_coin_references];
+ const struct TALER_PurseContractPublicKeyP *purse_pub;
+ const struct TALER_TESTING_Command *purse_cmd;
+
+ (void) cmd;
+ ds->is = is;
+ purse_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ ds->purse_ref);
+ GNUNET_assert (NULL != purse_cmd);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_purse_pub (purse_cmd,
+ &purse_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ds->purse_pub = *purse_pub;
+ for (unsigned int i = 0; i<ds->num_coin_references; i++)
+ {
+ struct Coin *cr = &ds->coin_references[i];
+ struct TALER_EXCHANGE_PurseDeposit *pd = &deposits[i];
+ const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+ const struct TALER_DenominationSignature *denom_pub_sig;
+
+ coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ cr->command_ref);
+ GNUNET_assert (NULL != coin_cmd);
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ cr->coin_index,
+ &coin_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_age_commitment_proof (coin_cmd,
+ cr->coin_index,
+ &age_commitment_proof))
+ ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (coin_cmd,
+ cr->coin_index,
+ &denom_pub)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_sig (coin_cmd,
+ cr->coin_index,
+ &denom_pub_sig)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &cr->coin_pub.eddsa_pub);
+ cr->che.type = TALER_EXCHANGE_CTT_PURSE_DEPOSIT;
+ cr->che.amount = cr->deposit_with_fee;
+ cr->che.details.purse_deposit.purse_pub = *purse_pub;
+ cr->che.details.purse_deposit.exchange_base_url
+ = TALER_TESTING_get_exchange_url (is);
+ TALER_age_commitment_hash (
+ &age_commitment_proof->commitment,
+ &cr->che.details.purse_deposit.phac);
+ pd->age_commitment_proof = age_commitment_proof;
+ pd->denom_sig = *denom_pub_sig;
+ pd->coin_priv = *coin_priv;
+ pd->amount = cr->deposit_with_fee;
+ pd->h_denom_pub = denom_pub->h_key;
+ }
+
+ ds->dh = TALER_EXCHANGE_purse_deposit (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ NULL, /* FIXME #7271: WADs support: purse exchange URL */
+ &ds->purse_pub,
+ ds->min_age,
+ ds->num_coin_references,
+ deposits,
+ &deposit_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not deposit into purse\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "deposit" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct PurseDepositState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+deposit_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PurseDepositState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_purse_deposit_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ for (unsigned int i = 0; i<ds->num_coin_references; i++)
+ GNUNET_free (ds->coin_references[i].command_ref);
+ GNUNET_free (ds->coin_references);
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data from a "deposit" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+deposit_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct PurseDepositState *ds = cls;
+
+ if (index >= ds->num_coin_references)
+ return GNUNET_NO;
+ {
+ const struct Coin *co = &ds->coin_references[index];
+ struct TALER_TESTING_Trait traits[] = {
+ /* history entry MUST be first due to response code logic below! */
+ TALER_TESTING_make_trait_reserve_history (0,
+ &ds->reserve_history),
+ TALER_TESTING_make_trait_coin_history (index,
+ &co->che),
+ TALER_TESTING_make_trait_coin_pub (index,
+ &co->coin_pub),
+ TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
+ TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (ds->purse_complete
+ ? &traits[0] /* we have reserve history */
+ : &traits[1], /* skip reserve history */
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_purse_deposit_coins (
+ const char *label,
+ unsigned int expected_http_status,
+ uint8_t min_age,
+ const char *purse_ref,
+ ...)
+{
+ struct PurseDepositState *ds;
+
+ ds = GNUNET_new (struct PurseDepositState);
+ ds->expected_response_code = expected_http_status;
+ ds->min_age = min_age;
+ ds->purse_ref = purse_ref;
+ {
+ va_list ap;
+ unsigned int i;
+ const char *ref;
+ const char *val;
+
+ va_start (ap, purse_ref);
+ while (NULL != (va_arg (ap, const char *)))
+ ds->num_coin_references++;
+ va_end (ap);
+ GNUNET_assert (0 == (ds->num_coin_references % 2));
+ ds->num_coin_references /= 2;
+ ds->coin_references = GNUNET_new_array (ds->num_coin_references,
+ struct Coin);
+ i = 0;
+ va_start (ap, purse_ref);
+ while (NULL != (ref = va_arg (ap, const char *)))
+ {
+ struct Coin *c = &ds->coin_references[i++];
+
+ GNUNET_assert (NULL != (val = va_arg (ap,
+ const char *)));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_parse_coin_reference (
+ ref,
+ &c->command_ref,
+ &c->coin_index));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (val,
+ &c->deposit_with_fee));
+ }
+ va_end (ap);
+ }
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &deposit_run,
+ .cleanup = &deposit_cleanup,
+ .traits = &deposit_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_purse_deposit.c */
diff --git a/src/testing/testing_api_cmd_purse_get.c b/src/testing/testing_api_cmd_purse_get.c
new file mode 100644
index 000000000..d5246660b
--- /dev/null
+++ b/src/testing/testing_api_cmd_purse_get.c
@@ -0,0 +1,367 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_purse_get.c
+ * @brief Implement the GET /purse/$RID test command.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "poll" CMD.
+ */
+struct PollState
+{
+
+ /**
+ * How long do we give the exchange to respond?
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * Label to the command which created the purse to check,
+ * needed to resort the purse key.
+ */
+ const char *poll_reference;
+
+ /**
+ * Timeout to wait for at most.
+ */
+ struct GNUNET_SCHEDULER_Task *tt;
+
+ /**
+ * The interpreter we are using.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * State for a "status" CMD.
+ */
+struct StatusState
+{
+
+ /**
+ * How long do we give the exchange to respond?
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * Poller waiting for us.
+ */
+ struct PollState *ps;
+
+ /**
+ * Label to the command which created the purse to check,
+ * needed to resort the purse key.
+ */
+ const char *purse_reference;
+
+ /**
+ * Handle to the "purse status" operation.
+ */
+ struct TALER_EXCHANGE_PurseGetHandle *pgh;
+
+ /**
+ * Expected purse balance.
+ */
+ const char *expected_balance;
+
+ /**
+ * Public key of the purse being analyzed.
+ */
+ const struct TALER_PurseContractPublicKeyP *purse_pub;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Are we waiting for a merge or a deposit?
+ */
+ bool wait_for_merge;
+
+};
+
+
+/**
+ * Check that the purse balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+purse_status_cb (void *cls,
+ const struct TALER_EXCHANGE_PurseGetResponse *rs)
+{
+ struct StatusState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+
+ ss->pgh = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ rs->hr.http_status,
+ __FILE__,
+ __LINE__);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ 0);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (MHD_HTTP_OK == ss->expected_response_code)
+ {
+ struct TALER_Amount eb;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (ss->expected_balance,
+ &eb));
+ if (0 != TALER_amount_cmp (&eb,
+ &rs->details.ok.balance))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected amount in purse: %s\n",
+ TALER_amount_to_string (&rs->details.ok.balance));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ }
+ if (NULL != ss->ps)
+ {
+ /* force continuation on long poller */
+ GNUNET_SCHEDULER_cancel (ss->ps->tt);
+ ss->ps->tt = NULL;
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ if (GNUNET_TIME_relative_is_zero (ss->timeout))
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+status_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct StatusState *ss = cls;
+ const struct TALER_TESTING_Command *create_purse;
+
+ ss->is = is;
+ create_purse
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ss->purse_reference);
+ GNUNET_assert (NULL != create_purse);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_purse_pub (create_purse,
+ &ss->purse_pub))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find purse_pub for status query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ss->pgh = TALER_EXCHANGE_purse_get (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ ss->purse_pub,
+ ss->timeout,
+ ss->wait_for_merge,
+ &purse_status_cb,
+ ss);
+ if (! GNUNET_TIME_relative_is_zero (ss->timeout))
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+}
+
+
+/**
+ * Cleanup the state from a "purse status" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+status_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct StatusState *ss = cls;
+
+ if (NULL != ss->pgh)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_purse_get_cancel (ss->pgh);
+ ss->pgh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_purse_poll (
+ const char *label,
+ unsigned int expected_http_status,
+ const char *purse_ref,
+ const char *expected_balance,
+ bool wait_for_merge,
+ struct GNUNET_TIME_Relative timeout)
+{
+ struct StatusState *ss;
+
+ GNUNET_assert (NULL != purse_ref);
+ ss = GNUNET_new (struct StatusState);
+ ss->purse_reference = purse_ref;
+ ss->expected_balance = expected_balance;
+ ss->expected_response_code = expected_http_status;
+ ss->timeout = timeout;
+ ss->wait_for_merge = wait_for_merge;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &status_run,
+ .cleanup = &status_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Long poller timed out. Fail the test.
+ *
+ * @param cls a `struct PollState`
+ */
+static void
+finish_timeout (void *cls)
+{
+ struct PollState *ps = cls;
+
+ ps->tt = NULL;
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ps->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+finish_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PollState *ps = cls;
+ const struct TALER_TESTING_Command *poll_purse;
+ struct StatusState *ss;
+
+ ps->is = is;
+ poll_purse
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ps->poll_reference);
+ GNUNET_assert (NULL != poll_purse);
+ GNUNET_assert (poll_purse->run == &status_run);
+ ss = poll_purse->cls;
+ if (NULL == ss->pgh)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_assert (NULL == ss->ps);
+ ss->ps = ps;
+ ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout,
+ &finish_timeout,
+ ps);
+}
+
+
+/**
+ * Cleanup the state from a "purse finish" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+finish_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PollState *ps = cls;
+
+ if (NULL != ps->tt)
+ {
+ GNUNET_SCHEDULER_cancel (ps->tt);
+ ps->tt = NULL;
+ }
+ GNUNET_free (ps);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_purse_poll_finish (const char *label,
+ struct GNUNET_TIME_Relative timeout,
+ const char *poll_reference)
+{
+ struct PollState *ps;
+
+ GNUNET_assert (NULL != poll_reference);
+ ps = GNUNET_new (struct PollState);
+ ps->timeout = timeout;
+ ps->poll_reference = poll_reference;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ps,
+ .label = label,
+ .run = &finish_run,
+ .cleanup = &finish_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_purse_merge.c b/src/testing/testing_api_cmd_purse_merge.c
new file mode 100644
index 000000000..cf9d4f996
--- /dev/null
+++ b/src/testing/testing_api_cmd_purse_merge.c
@@ -0,0 +1,436 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_purse_merge.c
+ * @brief command for testing /purses/$PID/merge
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "purse create deposit" CMD.
+ */
+struct PurseMergeState
+{
+
+ /**
+ * Merge time.
+ */
+ struct GNUNET_TIME_Timestamp merge_timestamp;
+
+ /**
+ * Reserve public key (to be merged into)
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Reserve private key (useful especially if
+ * @e reserve_ref is NULL).
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Handle while operation is running.
+ */
+ struct TALER_EXCHANGE_AccountMergeHandle *dh;
+
+ /**
+ * Reference to the merge capability.
+ */
+ const char *merge_ref;
+
+ /**
+ * Reference to the reserve, or NULL (!).
+ */
+ const char *reserve_ref;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Hash of the payto://-URI for the reserve we are
+ * merging into.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC.
+ */
+ uint64_t requirement_row;
+
+ /**
+ * Reserve history entry that corresponds to this operation.
+ * Will be of type #TALER_EXCHANGE_RTT_MERGE.
+ */
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
+
+ /**
+ * Public key of the purse.
+ */
+ struct TALER_PurseContractPublicKeyP purse_pub;
+
+ /**
+ * Public key of the merge capability.
+ */
+ struct TALER_PurseMergePublicKeyP merge_pub;
+
+ /**
+ * Contract value.
+ */
+ struct TALER_Amount value_after_fees;
+
+ /**
+ * Hash of the contract.
+ */
+ struct TALER_PrivateContractHashP h_contract_terms;
+
+ /**
+ * When does the purse expire.
+ */
+ struct GNUNET_TIME_Timestamp purse_expiration;
+
+ /**
+ * Minimum age of deposits into the purse.
+ */
+ uint32_t min_age;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+};
+
+
+/**
+ * Callback to analyze the /purses/$PID/merge response, just used to check if
+ * the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param dr merge response details
+ */
+static void
+merge_cb (void *cls,
+ const struct TALER_EXCHANGE_AccountMergeResponse *dr)
+{
+ struct PurseMergeState *ds = cls;
+
+ ds->dh = NULL;
+ switch (dr->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ ds->reserve_history.type = TALER_EXCHANGE_RTT_MERGE;
+ ds->reserve_history.amount = ds->value_after_fees;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_set_zero (
+ ds->value_after_fees.currency,
+ &ds->reserve_history.details.merge_details.purse_fee));
+ ds->reserve_history.details.merge_details.h_contract_terms
+ = ds->h_contract_terms;
+ ds->reserve_history.details.merge_details.merge_pub
+ = ds->merge_pub;
+ ds->reserve_history.details.merge_details.purse_pub
+ = ds->purse_pub;
+ ds->reserve_history.details.merge_details.reserve_sig
+ = *dr->reserve_sig;
+ ds->reserve_history.details.merge_details.merge_timestamp
+ = ds->merge_timestamp;
+ ds->reserve_history.details.merge_details.purse_expiration
+ = ds->purse_expiration;
+ ds->reserve_history.details.merge_details.min_age
+ = ds->min_age;
+ ds->reserve_history.details.merge_details.flags
+ = TALER_WAMF_MODE_MERGE_FULLY_PAID_PURSE;
+ break;
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ /* KYC required */
+ ds->requirement_row =
+ dr->details.unavailable_for_legal_reasons.requirement_row;
+ break;
+ }
+
+
+ if (ds->expected_response_code != dr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ dr->hr.http_status,
+ ds->expected_response_code);
+ return;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+merge_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PurseMergeState *ds = cls;
+ const struct TALER_PurseMergePrivateKeyP *merge_priv;
+ const json_t *ct;
+ const struct TALER_TESTING_Command *ref;
+
+ (void) cmd;
+ ds->is = is;
+ ref = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->merge_ref);
+ GNUNET_assert (NULL != ref);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_merge_priv (ref,
+ &merge_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ {
+ const struct TALER_PurseContractPublicKeyP *purse_pub;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_purse_pub (ref,
+ &purse_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ ds->purse_pub = *purse_pub;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_contract_terms (ref,
+ &ct))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_JSON_contract_hash (ct,
+ &ds->h_contract_terms))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_timestamp ("pay_deadline",
+ &ds->purse_expiration),
+ TALER_JSON_spec_amount_any ("amount",
+ &ds->value_after_fees),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("minimum_age",
+ &ds->min_age),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (ct,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ }
+
+ if (NULL == ds->reserve_ref)
+ {
+ GNUNET_CRYPTO_eddsa_key_create (&ds->reserve_priv.eddsa_priv);
+ }
+ else
+ {
+ const struct TALER_ReservePrivateKeyP *rp;
+
+ ref = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->reserve_ref);
+ GNUNET_assert (NULL != ref);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (ref,
+ &rp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ ds->reserve_priv = *rp;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->reserve_priv.eddsa_priv,
+ &ds->reserve_pub.eddsa_pub);
+ {
+ char *payto_uri;
+ const char *exchange_url;
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ payto_uri = TALER_reserve_make_payto (exchange_url,
+ &ds->reserve_pub);
+ TALER_payto_hash (payto_uri,
+ &ds->h_payto);
+ GNUNET_free (payto_uri);
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv,
+ &ds->merge_pub.eddsa_pub);
+ ds->merge_timestamp = GNUNET_TIME_timestamp_get ();
+ ds->dh = TALER_EXCHANGE_account_merge (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ NULL, /* no wad */
+ &ds->reserve_priv,
+ &ds->purse_pub,
+ merge_priv,
+ &ds->h_contract_terms,
+ ds->min_age,
+ &ds->value_after_fees,
+ ds->purse_expiration,
+ ds->merge_timestamp,
+ &merge_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not merge purse\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "merge" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct PurseMergeState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+merge_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PurseMergeState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_account_merge_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data from a "merge" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+merge_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct PurseMergeState *ds = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ /* history entry MUST be first due to response code logic below! */
+ TALER_TESTING_make_trait_reserve_history (0,
+ &ds->reserve_history),
+ TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
+ TALER_TESTING_make_trait_timestamp (0,
+ &ds->merge_timestamp),
+ TALER_TESTING_make_trait_legi_requirement_row (&ds->requirement_row),
+ TALER_TESTING_make_trait_h_payto (&ds->h_payto),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait ((ds->expected_response_code == MHD_HTTP_OK)
+ ? &traits[0] /* we have reserve history */
+ : &traits[1], /* skip reserve history */
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_purse_merge (
+ const char *label,
+ unsigned int expected_http_status,
+ const char *merge_ref,
+ const char *reserve_ref)
+{
+ struct PurseMergeState *ds;
+
+ ds = GNUNET_new (struct PurseMergeState);
+ ds->merge_ref = merge_ref;
+ ds->reserve_ref = reserve_ref;
+ ds->expected_response_code = expected_http_status;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &merge_run,
+ .cleanup = &merge_cleanup,
+ .traits = &merge_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_purse_merge.c */
diff --git a/src/testing/testing_api_cmd_recoup.c b/src/testing/testing_api_cmd_recoup.c
index 7c4204d9e..cefcd96bb 100644
--- a/src/testing/testing_api_cmd_recoup.c
+++ b/src/testing/testing_api_cmd_recoup.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2018 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -54,88 +54,44 @@ struct RecoupState
struct TALER_EXCHANGE_RecoupHandle *ph;
/**
- * NULL if coin was not refreshed, otherwise reference
- * to the melt operation underlying @a coin_reference.
+ * If the recoup filled a reserve, this is set to the reserve's public key.
*/
- const char *melt_reference;
+ struct TALER_ReservePublicKeyP reserve_pub;
/**
- * If the recoup filled a reserve, this is set to the reserve's public key.
+ * Entry in the coin's history generated by this operation.
*/
- struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_EXCHANGE_CoinHistoryEntry che;
+
+ /**
+ * Public key of the refunded coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin;
/**
* Reserve history entry, set if this recoup actually filled up a reserve.
* Otherwise `reserve_history.type` will be zero.
*/
- struct TALER_EXCHANGE_ReserveHistory reserve_history;
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
};
/**
- * Parser reference to a coin.
- *
- * @param coin_reference of format $LABEL['#' $INDEX]?
- * @param[out] cref where we return a copy of $LABEL
- * @param[out] idx where we set $INDEX
- * @return #GNUNET_SYSERR if $INDEX is present but not numeric
- */
-static int
-parse_coin_reference (const char *coin_reference,
- char **cref,
- unsigned int *idx)
-{
- const char *index;
-
- /* We allow command references of the form "$LABEL#$INDEX" or
- just "$LABEL", which implies the index is 0. Figure out
- which one it is. */
- index = strchr (coin_reference, '#');
- if (NULL == index)
- {
- *idx = 0;
- *cref = GNUNET_strdup (coin_reference);
- return GNUNET_OK;
- }
- *cref = GNUNET_strndup (coin_reference,
- index - coin_reference);
- if (1 != sscanf (index + 1,
- "%u",
- idx))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Numeric index (not `%s') required after `#' in command reference of command in %s:%u\n",
- index,
- __FILE__,
- __LINE__);
- GNUNET_free (*cref);
- *cref = NULL;
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
* Check the result of the recoup request: checks whether
* the HTTP response code is good, and that the coin that
* was paid back belonged to the right reserve.
*
* @param cls closure
- * @param hr HTTP response details
- * @param reserve_pub public key of the reserve receiving the recoup, NULL if refreshed or on error
- * @param old_coin_pub public key of the dirty coin, NULL if not refreshed or on error
+ * @param rr response details
*/
static void
recoup_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_CoinSpendPublicKeyP *old_coin_pub)
+ const struct TALER_EXCHANGE_RecoupResponse *rr)
{
struct RecoupState *ps = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr;
struct TALER_TESTING_Interpreter *is = ps->is;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
const struct TALER_TESTING_Command *reserve_cmd;
char *cref;
unsigned int idx;
@@ -143,29 +99,22 @@ recoup_cb (void *cls,
ps->ph = NULL;
if (ps->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- fprintf (stderr, "\n");
- TALER_TESTING_interpreter_fail (is);
+ TALER_TESTING_unexpected_status (is,
+ hr->http_status,
+ ps->expected_response_code);
return;
}
if (GNUNET_OK !=
- parse_coin_reference (ps->coin_reference,
- &cref,
- &idx))
+ TALER_TESTING_parse_coin_reference (
+ ps->coin_reference,
+ &cref,
+ &idx))
{
TALER_TESTING_interpreter_fail (is);
return;
}
+ (void) idx; /* do NOT use! We ignore 'idx', must be 0 for melt! */
reserve_cmd = TALER_TESTING_interpreter_lookup_command (is,
cref);
@@ -182,52 +131,11 @@ recoup_cb (void *cls,
{
case MHD_HTTP_OK:
/* check old_coin_pub or reserve_pub, respectively */
- if (NULL != ps->melt_reference)
- {
- const struct TALER_TESTING_Command *melt_cmd;
- const struct TALER_CoinSpendPrivateKeyP *dirty_priv;
- struct TALER_CoinSpendPublicKeyP oc;
-
- melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
- ps->melt_reference);
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (melt_cmd,
- 0,
- &dirty_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv,
- &oc.eddsa_pub);
- if (0 != GNUNET_memcmp (&oc,
- old_coin_pub))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- }
- else
{
const struct TALER_ReservePrivateKeyP *reserve_priv;
- if (NULL == reserve_pub)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_priv (reserve_cmd,
- idx,
&reserve_priv))
{
GNUNET_break (0);
@@ -236,7 +144,7 @@ recoup_cb (void *cls,
}
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
&ps->reserve_pub.eddsa_pub);
- if (0 != GNUNET_memcmp (reserve_pub,
+ if (0 != GNUNET_memcmp (&rr->details.ok.reserve_pub,
&ps->reserve_pub))
{
GNUNET_break (0);
@@ -247,6 +155,7 @@ recoup_cb (void *cls,
TALER_amount_is_valid (&ps->reserve_history.amount))
ps->reserve_history.type = TALER_EXCHANGE_RTT_RECOUP;
/* ps->reserve_history.details.recoup_details.coin_pub; // initialized earlier */
+ ps->che.details.recoup.reserve_pub = ps->reserve_pub;
}
break;
case MHD_HTTP_NOT_FOUND:
@@ -279,18 +188,20 @@ recoup_run (void *cls,
struct RecoupState *ps = cls;
const struct TALER_TESTING_Command *coin_cmd;
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- const struct TALER_DenominationBlindingKeyP *blinding_key;
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
const struct TALER_DenominationSignature *coin_sig;
- struct TALER_PlanchetSecretsP planchet;
+ const struct TALER_PlanchetMasterSecretP *planchet;
char *cref;
unsigned int idx;
+ const struct TALER_ExchangeWithdrawValues *ewv;
+ struct TALER_DenominationHashP h_denom_pub;
ps->is = is;
if (GNUNET_OK !=
- parse_coin_reference (ps->coin_reference,
- &cref,
- &idx))
+ TALER_TESTING_parse_coin_reference (
+ ps->coin_reference,
+ &cref,
+ &idx))
{
TALER_TESTING_interpreter_fail (is);
return;
@@ -306,7 +217,6 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
-
if (GNUNET_OK !=
TALER_TESTING_get_trait_coin_priv (coin_cmd,
idx,
@@ -316,18 +226,25 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
-
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &ps->coin.eddsa_pub);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_exchange_wd_value (coin_cmd,
+ idx,
+ &ewv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
if (GNUNET_OK !=
- TALER_TESTING_get_trait_blinding_key (coin_cmd,
- idx,
- &blinding_key))
+ TALER_TESTING_get_trait_planchet_secret (coin_cmd,
+ &planchet))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
- planchet.coin_priv = *coin_priv;
- planchet.blinding_key = *blinding_key;
GNUNET_CRYPTO_eddsa_key_get_public (
&coin_priv->eddsa_priv,
&ps->reserve_history.details.recoup_details.coin_pub.eddsa_pub);
@@ -341,7 +258,6 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
-
if (GNUNET_OK !=
TALER_TESTING_get_trait_denom_sig (coin_cmd,
idx,
@@ -351,18 +267,30 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
-
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Trying to recoup denomination '%s'\n",
TALER_B2S (&denom_pub->h_key));
-
- ps->ph = TALER_EXCHANGE_recoup (is->exchange,
- denom_pub,
- coin_sig,
- &planchet,
- NULL != ps->melt_reference,
- recoup_cb,
- ps);
+ ps->che.type = TALER_EXCHANGE_CTT_RECOUP;
+ ps->che.amount = ps->reserve_history.amount;
+ TALER_planchet_blinding_secret_create (planchet,
+ ewv,
+ &ps->che.details.recoup.coin_bks);
+ TALER_denom_pub_hash (&denom_pub->key,
+ &h_denom_pub);
+ TALER_wallet_recoup_sign (&h_denom_pub,
+ &ps->che.details.recoup.coin_bks,
+ coin_priv,
+ &ps->che.details.recoup.coin_sig);
+ ps->ph = TALER_EXCHANGE_recoup (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ denom_pub,
+ coin_sig,
+ ewv,
+ planchet,
+ &recoup_cb,
+ ps);
GNUNET_assert (NULL != ps->ph);
}
@@ -398,7 +326,7 @@ recoup_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
recoup_traits (void *cls,
const void **ret,
const char *trait,
@@ -410,10 +338,13 @@ recoup_traits (void *cls,
return GNUNET_SYSERR; /* no traits */
{
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_reserve_pub (0,
- &ps->reserve_pub),
+ TALER_TESTING_make_trait_reserve_pub (&ps->reserve_pub),
TALER_TESTING_make_trait_reserve_history (0,
&ps->reserve_history),
+ TALER_TESTING_make_trait_coin_history (0,
+ &ps->che),
+ TALER_TESTING_make_trait_coin_pub (0,
+ &ps->coin),
TALER_TESTING_trait_end ()
};
@@ -425,22 +356,10 @@ recoup_traits (void *cls,
}
-/**
- * Make a "recoup" command.
- *
- * @param label the command label
- * @param expected_response_code expected HTTP status code
- * @param coin_reference reference to any command which
- * offers a coin & reserve private key.
- * @param melt_reference NULL if coin was not refreshed
- * @param amount how much do we expect to recoup?
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_recoup (const char *label,
unsigned int expected_response_code,
const char *coin_reference,
- const char *melt_reference,
const char *amount)
{
struct RecoupState *ps;
@@ -448,11 +367,9 @@ TALER_TESTING_cmd_recoup (const char *label,
ps = GNUNET_new (struct RecoupState);
ps->expected_response_code = expected_response_code;
ps->coin_reference = coin_reference;
- ps->melt_reference = melt_reference;
- if ( (NULL != amount) &&
- (GNUNET_OK !=
- TALER_string_to_amount (amount,
- &ps->reserve_history.amount)) )
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &ps->reserve_history.amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %s\n",
diff --git a/src/testing/testing_api_cmd_recoup_refresh.c b/src/testing/testing_api_cmd_recoup_refresh.c
new file mode 100644
index 000000000..68d267be4
--- /dev/null
+++ b/src/testing/testing_api_cmd_recoup_refresh.c
@@ -0,0 +1,441 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_recoup_refresh.c
+ * @brief Implement the /recoup-refresh test command.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "pay back" CMD.
+ */
+struct RecoupRefreshState
+{
+ /**
+ * 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;
+
+ /**
+ * Entry in the old coin's history generated by this operation.
+ */
+ struct TALER_EXCHANGE_CoinHistoryEntry che_old;
+
+ /**
+ * Entry in the recouped coin's history generated by this operation.
+ */
+ struct TALER_EXCHANGE_CoinHistoryEntry che_new;
+
+ /**
+ * Public key of the refunded coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub_old;
+
+ /**
+ * Public key of the refunded coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin_pub_new;
+
+ /**
+ * Amount to be recouped.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Handle to the ongoing operation.
+ */
+ struct TALER_EXCHANGE_RecoupRefreshHandle *ph;
+
+ /**
+ * NULL if coin was not refreshed, otherwise reference
+ * to the melt operation underlying @a coin_reference.
+ */
+ const char *melt_reference;
+
+};
+
+
+/**
+ * Check the result of the recoup_refresh request: checks whether
+ * the HTTP response code is good, and that the coin that
+ * was paid back belonged to the right old coin.
+ *
+ * @param cls closure
+ * @param rrr response details
+ */
+static void
+recoup_refresh_cb (void *cls,
+ const struct TALER_EXCHANGE_RecoupRefreshResponse *rrr)
+{
+ struct RecoupRefreshState *rrs = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &rrr->hr;
+ struct TALER_TESTING_Interpreter *is = rrs->is;
+ char *cref;
+ unsigned int idx;
+
+ rrs->ph = NULL;
+ if (rrs->expected_response_code != hr->http_status)
+ {
+ TALER_TESTING_unexpected_status (is,
+ hr->http_status,
+ rrs->expected_response_code);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_parse_coin_reference (
+ rrs->coin_reference,
+ &cref,
+ &idx))
+ {
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ (void) idx; /* do NOT use! We ignore 'idx', must be 0 for melt! */
+
+ GNUNET_free (cref);
+ switch (hr->http_status)
+ {
+ case MHD_HTTP_OK:
+ /* check old_coin_pub */
+ {
+ const struct TALER_TESTING_Command *melt_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *dirty_priv;
+ struct TALER_CoinSpendPublicKeyP oc;
+
+ melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ rrs->melt_reference);
+ if (NULL == melt_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (melt_cmd,
+ 0,
+ &dirty_priv))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Coin %u not found in command %s\n",
+ 0,
+ rrs->melt_reference);
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv,
+ &oc.eddsa_pub);
+ if (0 != GNUNET_memcmp (&oc,
+ &rrr->details.ok.old_coin_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ break;
+ case MHD_HTTP_CONFLICT:
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unmanaged HTTP status code %u/%d.\n",
+ hr->http_status,
+ (int) hr->ec);
+ break;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+recoup_refresh_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RecoupRefreshState *rrs = cls;
+ const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_TESTING_Command *melt_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv_old;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+ const struct TALER_DenominationSignature *coin_sig;
+ const struct TALER_RefreshMasterSecretP *rplanchet;
+ const struct TALER_PlanchetMasterSecretP *planchet;
+ const struct TALER_ExchangeWithdrawValues *ewv;
+ char *cref;
+ unsigned int idx;
+ struct TALER_DenominationHashP h_denom_pub;
+
+ rrs->is = is;
+ if (GNUNET_OK !=
+ TALER_TESTING_parse_coin_reference (
+ rrs->coin_reference,
+ &cref,
+ &idx))
+ {
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ cref);
+ GNUNET_free (cref);
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ rrs->melt_reference);
+ if (NULL == melt_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ idx,
+ &coin_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (melt_cmd,
+ 0,
+ &coin_priv_old))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (
+ &coin_priv->eddsa_priv,
+ &rrs->coin_pub_new.eddsa_pub);
+ GNUNET_CRYPTO_eddsa_key_get_public (
+ &coin_priv_old->eddsa_priv,
+ &rrs->coin_pub_old.eddsa_pub);
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_exchange_wd_value (melt_cmd,
+ idx,
+ &ewv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_planchet_secrets (coin_cmd,
+ idx,
+ &planchet))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_refresh_secret (melt_cmd,
+ &rplanchet))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (coin_cmd,
+ idx,
+ &denom_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_sig (coin_cmd,
+ idx,
+ &coin_sig))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Trying to recoup_refresh denomination '%s'\n",
+ TALER_B2S (&denom_pub->h_key));
+ rrs->che_old.type
+ = TALER_EXCHANGE_CTT_OLD_COIN_RECOUP;
+ rrs->che_old.amount
+ = rrs->amount;
+ rrs->che_old.details.old_coin_recoup.new_coin_pub
+ = rrs->coin_pub_new;
+ rrs->che_new.type
+ = TALER_EXCHANGE_CTT_RECOUP_REFRESH;
+ rrs->che_new.amount
+ = rrs->amount;
+ rrs->che_new.details.recoup_refresh.old_coin_pub
+ = rrs->coin_pub_old;
+ TALER_planchet_blinding_secret_create (
+ planchet,
+ ewv,
+ &rrs->che_new.details.recoup_refresh.coin_bks);
+ TALER_denom_pub_hash (&denom_pub->key,
+ &h_denom_pub);
+ TALER_wallet_recoup_refresh_sign (
+ &h_denom_pub,
+ &rrs->che_new.details.recoup_refresh.coin_bks,
+ coin_priv,
+ &rrs->che_new.details.recoup_refresh.coin_sig);
+ rrs->ph = TALER_EXCHANGE_recoup_refresh (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ denom_pub,
+ coin_sig,
+ ewv,
+ rplanchet,
+ planchet,
+ idx,
+ &recoup_refresh_cb,
+ rrs);
+ GNUNET_assert (NULL != rrs->ph);
+}
+
+
+/**
+ * Cleanup the "recoup_refresh" CMD state, and possibly cancel
+ * a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+recoup_refresh_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RecoupRefreshState *rrs = cls;
+ if (NULL != rrs->ph)
+ {
+ TALER_EXCHANGE_recoup_refresh_cancel (rrs->ph);
+ rrs->ph = NULL;
+ }
+ GNUNET_free (rrs);
+}
+
+
+/**
+ * Offer internal data from a "recoup-refresh" CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+recoup_refresh_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RecoupRefreshState *rrs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_coin_history (0,
+ &rrs->che_old),
+ TALER_TESTING_make_trait_coin_pub (0,
+ &rrs->coin_pub_old),
+ TALER_TESTING_make_trait_coin_history (1,
+ &rrs->che_new),
+ TALER_TESTING_make_trait_coin_pub (1,
+ &rrs->coin_pub_new),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_recoup_refresh (const char *label,
+ unsigned int expected_response_code,
+ const char *coin_reference,
+ const char *melt_reference,
+ const char *amount)
+{
+ struct RecoupRefreshState *rrs;
+
+ rrs = GNUNET_new (struct RecoupRefreshState);
+ rrs->expected_response_code = expected_response_code;
+ rrs->coin_reference = coin_reference;
+ rrs->melt_reference = melt_reference;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &rrs->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %s\n",
+ amount,
+ label);
+ GNUNET_assert (0);
+ }
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rrs,
+ .label = label,
+ .run = &recoup_refresh_run,
+ .cleanup = &recoup_refresh_cleanup,
+ .traits = &recoup_refresh_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c
index fcf8540c0..111e9118f 100644
--- a/src/testing/testing_api_cmd_refresh.c
+++ b/src/testing/testing_api_cmd_refresh.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2022 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
@@ -70,10 +70,17 @@ struct TALER_TESTING_FreshCoinData
*/
struct TALER_CoinSpendPrivateKeyP coin_priv;
+ /*
+ * Fresh age commitment for the coin with proof and its hash, NULL if not
+ * applicable.
+ */
+ struct TALER_AgeCommitmentProof *age_commitment_proof;
+ struct TALER_AgeCommitmentHash h_age_commitment;
+
/**
* The blinding key (needed for recoup operations).
*/
- struct TALER_DenominationBlindingKeyP blinding_key;
+ union GNUNET_CRYPTO_BlindingSecretP blinding_key;
};
@@ -91,9 +98,14 @@ struct RefreshMeltState
const char *coin_reference;
/**
- * "Crypto data" used in the refresh operation.
+ * Data used in the refresh operation.
+ */
+ struct TALER_EXCHANGE_RefreshData refresh_data;
+
+ /**
+ * Our command.
*/
- char *refresh_data;
+ const struct TALER_TESTING_Command *cmd;
/**
* Reference to a previous melt command.
@@ -106,6 +118,12 @@ struct RefreshMeltState
struct TALER_EXCHANGE_MeltHandle *rmh;
/**
+ * Expected entry in the coin history created by this
+ * operation.
+ */
+ struct TALER_EXCHANGE_CoinHistoryEntry che;
+
+ /**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
@@ -117,11 +135,27 @@ struct RefreshMeltState
struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
/**
+ * Array of @e num_fresh_coins of results from
+ * the melt operation.
+ */
+ struct TALER_EXCHANGE_MeltBlindingDetail *mbds;
+
+ /**
+ * Entropy seed for the refresh-melt operation.
+ */
+ struct TALER_RefreshMasterSecretP rms;
+
+ /**
* Private key of the dirty coin being melted.
*/
const struct TALER_CoinSpendPrivateKeyP *melt_priv;
/**
+ * Public key of the dirty coin being melted.
+ */
+ struct TALER_CoinSpendPublicKeyP melt_pub;
+
+ /**
* Task scheduled to try later.
*/
struct GNUNET_SCHEDULER_Task *retry_task;
@@ -137,11 +171,6 @@ struct RefreshMeltState
struct GNUNET_TIME_Relative total_backoff;
/**
- * Number of bytes in @e refresh_data.
- */
- size_t refresh_data_length;
-
- /**
* Amounts to be generated during melt.
*/
const char **melt_fresh_amounts;
@@ -167,7 +196,7 @@ struct RefreshMeltState
* exchange to pick any previous /rerfesh/melt operation from
* the database.
*/
- unsigned int double_melt;
+ bool double_melt;
/**
* How often should we retry on (transient) failures?
@@ -197,6 +226,11 @@ struct RefreshRevealState
struct TALER_EXCHANGE_RefreshesRevealHandle *rrh;
/**
+ * Our command.
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
* Convenience struct to keep in one place all the
* data related to one fresh coin, set by the reveal callback
* as it comes from the exchange.
@@ -204,6 +238,12 @@ struct RefreshRevealState
struct TALER_TESTING_FreshCoinData *fresh_coins;
/**
+ * Array of @e num_fresh_coins planchet secrets derived
+ * from the transfer secret per fresh coin.
+ */
+ struct TALER_PlanchetMasterSecretP *psa;
+
+ /**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
@@ -254,6 +294,11 @@ struct RefreshLinkState
const char *reveal_reference;
/**
+ * Our command.
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
* Handle to the ongoing operation.
*/
struct TALER_EXCHANGE_LinkHandle *rlh;
@@ -315,8 +360,7 @@ do_reveal_retry (void *cls)
struct RefreshRevealState *rrs = cls;
rrs->retry_task = NULL;
- rrs->is->commands[rrs->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (rrs->is);
refresh_reveal_run (rrs,
NULL,
rrs->is);
@@ -329,23 +373,14 @@ do_reveal_retry (void *cls)
* coming from the exchange, namely the fresh coins.
*
* @param cls closure, a `struct RefreshRevealState`
- * @param hr HTTP response details
- * @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 rr HTTP response details
*/
static void
reveal_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- unsigned int num_coins,
- const struct TALER_PlanchetSecretsP *coin_privs,
- const struct TALER_DenominationSignature *sigs)
+ const struct TALER_EXCHANGE_RevealResult *rr)
{
struct RefreshRevealState *rrs = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr;
const struct TALER_TESTING_Command *melt_cmd;
rrs->rrh = NULL;
@@ -370,24 +405,16 @@ reveal_cb (void *cls,
MAX_BACKOFF);
rrs->total_backoff = GNUNET_TIME_relative_add (rrs->total_backoff,
rrs->backoff);
- rrs->is->commands[rrs->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (rrs->is);
rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff,
&do_reveal_retry,
rrs);
return;
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- rrs->is->commands[rrs->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (rrs->is);
+ TALER_TESTING_unexpected_status (rrs->is,
+ hr->http_status,
+ rrs->expected_response_code);
return;
}
melt_cmd = TALER_TESTING_interpreter_lookup_command (rrs->is,
@@ -398,16 +425,22 @@ reveal_cb (void *cls,
TALER_TESTING_interpreter_fail (rrs->is);
return;
}
- rrs->num_fresh_coins = num_coins;
switch (hr->http_status)
{
case MHD_HTTP_OK:
- rrs->fresh_coins = GNUNET_new_array (num_coins,
+ rrs->num_fresh_coins = rr->details.ok.num_coins;
+ rrs->psa = GNUNET_new_array (rrs->num_fresh_coins,
+ struct TALER_PlanchetMasterSecretP);
+ rrs->fresh_coins = GNUNET_new_array (rrs->num_fresh_coins,
struct TALER_TESTING_FreshCoinData);
- for (unsigned int i = 0; i<num_coins; i++)
+ for (unsigned int i = 0; i<rrs->num_fresh_coins; i++)
{
+ const struct TALER_EXCHANGE_RevealedCoinInfo *coin
+ = &rr->details.ok.coins[i];
struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i];
+ rrs->psa[i] = coin->ps;
+ fc->blinding_key = coin->bks;
if (GNUNET_OK !=
TALER_TESTING_get_trait_denom_pub (melt_cmd,
i,
@@ -417,18 +450,25 @@ reveal_cb (void *cls,
TALER_TESTING_interpreter_fail (rrs->is);
return;
}
- fc->coin_priv = coin_privs[i].coin_priv;
- fc->blinding_key = coin_privs[i].blinding_key;
- fc->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup
- (sigs[i].rsa_signature);
+ fc->coin_priv = coin->coin_priv;
+
+ if (NULL != coin->age_commitment_proof)
+ {
+ fc->age_commitment_proof =
+ TALER_age_commitment_proof_duplicate (coin->age_commitment_proof);
+ fc->h_age_commitment = coin->h_age_commitment;
+ }
+
+ TALER_denom_sig_copy (&fc->sig,
+ &coin->sig);
}
if (0 != rrs->total_backoff.rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Total reveal backoff for %s was %s\n",
- rrs->is->commands[rrs->is->ip].label,
+ rrs->cmd->label,
GNUNET_STRINGS_relative_time_to_string (rrs->total_backoff,
- GNUNET_YES));
+ true));
}
break;
default:
@@ -449,6 +489,19 @@ reveal_cb (void *cls,
* @param is the interpreter state.
*/
static void
+melt_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
refresh_reveal_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
@@ -457,6 +510,7 @@ refresh_reveal_run (void *cls,
struct RefreshMeltState *rms;
const struct TALER_TESTING_Command *melt_cmd;
+ rrs->cmd = cmd;
rrs->is = is;
melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
rrs->melt_reference);
@@ -466,14 +520,24 @@ refresh_reveal_run (void *cls,
TALER_TESTING_interpreter_fail (rrs->is);
return;
}
+ GNUNET_assert (melt_cmd->run == &melt_run);
rms = melt_cmd->cls;
- rrs->rrh = TALER_EXCHANGE_refreshes_reveal (is->exchange,
- rms->refresh_data_length,
- rms->refresh_data,
- rms->noreveal_index,
- &reveal_cb,
- rrs);
-
+ {
+ struct TALER_ExchangeWithdrawValues alg_values[rms->num_fresh_coins];
+
+ for (unsigned int i = 0; i<rms->num_fresh_coins; i++)
+ alg_values[i] = rms->mbds[i].alg_value;
+ rrs->rrh = TALER_EXCHANGE_refreshes_reveal (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ &rms->rms,
+ &rms->refresh_data,
+ rms->num_fresh_coins,
+ alg_values,
+ rms->noreveal_index,
+ &reveal_cb,
+ rrs);
+ }
if (NULL == rrs->rrh)
{
GNUNET_break (0);
@@ -496,12 +560,11 @@ refresh_reveal_cleanup (void *cls,
{
struct RefreshRevealState *rrs = cls;
+ (void) cmd;
if (NULL != rrs->rrh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rrs->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (rrs->is,
+ cmd->label);
TALER_EXCHANGE_refreshes_reveal_cancel (rrs->rrh);
rrs->rrh = NULL;
}
@@ -512,10 +575,14 @@ refresh_reveal_cleanup (void *cls,
}
for (unsigned int j = 0; j < rrs->num_fresh_coins; j++)
- GNUNET_CRYPTO_rsa_signature_free (rrs->fresh_coins[j].sig.rsa_signature);
+ {
+ TALER_denom_sig_free (&rrs->fresh_coins[j].sig);
+ TALER_age_commitment_proof_free (rrs->fresh_coins[j].age_commitment_proof);
+ GNUNET_free (rrs->fresh_coins[j].age_commitment_proof);
+ }
GNUNET_free (rrs->fresh_coins);
- rrs->fresh_coins = NULL;
+ GNUNET_free (rrs->psa);
rrs->num_fresh_coins = 0;
GNUNET_free (rrs);
}
@@ -545,8 +612,7 @@ do_link_retry (void *cls)
struct RefreshLinkState *rls = cls;
rls->retry_task = NULL;
- rls->is->commands[rls->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (rls->is);
refresh_link_run (rls,
NULL,
rls->is);
@@ -559,29 +625,15 @@ do_link_retry (void *cls)
* withdrawn by the "refresh reveal" CMD.
*
* @param cls closure.
- * @param hr HTTP response details
- * @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 lr HTTP response details
*/
static void
link_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const struct TALER_DenominationPublicKey *pubs)
+ const struct TALER_EXCHANGE_LinkResult *lr)
{
-
struct RefreshLinkState *rls = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &lr->hr;
const struct TALER_TESTING_Command *reveal_cmd;
- struct TALER_TESTING_Command *link_cmd = &rls->is->commands[rls->is->ip];
unsigned int found;
const unsigned int *num_fresh_coins;
@@ -607,24 +659,16 @@ link_cb (void *cls,
MAX_BACKOFF);
rls->total_backoff = GNUNET_TIME_relative_add (rls->total_backoff,
rls->backoff);
- rls->is->commands[rls->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (rls->is);
rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff,
&do_link_retry,
rls);
return;
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- link_cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (rls->is);
+ TALER_TESTING_unexpected_status (rls->is,
+ hr->http_status,
+ rls->expected_response_code);
return;
}
reveal_cmd = TALER_TESTING_interpreter_lookup_command (rls->is,
@@ -641,19 +685,18 @@ link_cb (void *cls,
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))
+ TALER_TESTING_get_trait_array_length (reveal_cmd,
+ &num_fresh_coins))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rls->is);
return;
}
- if (num_coins != *num_fresh_coins)
+ if (lr->details.ok.num_coins != *num_fresh_coins)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected number of fresh coins: %d vs %d in %s:%u\n",
- num_coins,
+ lr->details.ok.num_coins,
*num_fresh_coins,
__FILE__,
__LINE__);
@@ -661,22 +704,21 @@ link_cb (void *cls,
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++)
+ for (unsigned int i = 0; i<lr->details.ok.num_coins; i++)
+ for (unsigned int j = i + 1; j<lr->details.ok.num_coins; j++)
if (0 ==
- GNUNET_memcmp (&coin_privs[i],
- &coin_privs[j]))
+ GNUNET_memcmp (&lr->details.ok.coins[i].coin_priv,
+ &lr->details.ok.coins[j].coin_priv))
GNUNET_break (0);
/* Note: coins might be legitimately permutated in here... */
found = 0;
/* Will point to the pointer inside the cmd state. */
{
- const struct TALER_TESTING_FreshCoinData *fc = NULL;
+ const struct TALER_TESTING_FreshCoinData **fc = NULL;
if (GNUNET_OK !=
TALER_TESTING_get_trait_fresh_coins (reveal_cmd,
- 0,
&fc))
{
GNUNET_break (0);
@@ -684,29 +726,38 @@ link_cb (void *cls,
return;
}
- for (unsigned int i = 0; i<num_coins; i++)
- for (unsigned int j = 0; j<num_coins; j++)
+ for (unsigned int i = 0; i<lr->details.ok.num_coins; i++)
+ {
+ const struct TALER_EXCHANGE_LinkedCoinInfo *lci_i
+ = &lr->details.ok.coins[i];
+
+ for (unsigned int j = 0; j<lr->details.ok.num_coins; j++)
{
+ const struct TALER_TESTING_FreshCoinData *fcj
+ = &(*fc)[j];
+
if ( (0 ==
- GNUNET_memcmp (&coin_privs[i],
- &fc[j].coin_priv)) &&
+ GNUNET_memcmp (&fcj->coin_priv,
+ &lci_i->coin_priv)) &&
(0 ==
- GNUNET_CRYPTO_rsa_signature_cmp (fc[i].sig.rsa_signature,
- sigs[j].rsa_signature)) &&
+ TALER_denom_sig_cmp (&fcj->sig,
+ &lci_i->sig)) &&
(0 ==
- GNUNET_CRYPTO_rsa_public_key_cmp (fc[i].pk->key.rsa_public_key,
- pubs[j].rsa_public_key)) )
+ TALER_denom_pub_cmp (&fcj->pk->key,
+ &lci_i->pub)) )
{
found++;
break;
}
- }
+ } /* for j*/
+ } /* for i */
}
- if (found != num_coins)
+ if (found != lr->details.ok.num_coins)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Only %u/%u coins match expectations\n",
- found, num_coins);
+ found,
+ lr->details.ok.num_coins);
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rls->is);
return;
@@ -715,9 +766,9 @@ link_cb (void *cls,
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Total link backoff for %s was %s\n",
- rls->is->commands[rls->is->ip].label,
+ rls->cmd->label,
GNUNET_STRINGS_relative_time_to_string (rls->total_backoff,
- GNUNET_YES));
+ true));
}
break;
default:
@@ -748,8 +799,16 @@ refresh_link_run (void *cls,
const struct TALER_TESTING_Command *reveal_cmd;
const struct TALER_TESTING_Command *melt_cmd;
const struct TALER_TESTING_Command *coin_cmd;
+ const char *exchange_url;
+ rls->cmd = cmd;
rls->is = is;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
reveal_cmd = TALER_TESTING_interpreter_lookup_command (rls->is,
rls->reveal_reference);
if (NULL == reveal_cmd)
@@ -769,21 +828,22 @@ refresh_link_run (void *cls,
}
/* find reserve_withdraw command */
+ GNUNET_assert (melt_cmd->run == &melt_run);
+ rms = melt_cmd->cls;
+ coin_cmd = TALER_TESTING_interpreter_lookup_command (rls->is,
+ rms->coin_reference);
+ if (NULL == coin_cmd)
{
- rms = melt_cmd->cls;
- coin_cmd = TALER_TESTING_interpreter_lookup_command (rls->is,
- rms->coin_reference);
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
}
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
- (coin_cmd, 0, &coin_priv))
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ 0,
+ &coin_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rls->is);
@@ -791,10 +851,13 @@ refresh_link_run (void *cls,
}
/* finally, use private key from withdraw sign command */
- rls->rlh = TALER_EXCHANGE_link (is->exchange,
- coin_priv,
- &link_cb,
- rls);
+ rls->rlh = TALER_EXCHANGE_link (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ coin_priv,
+ rms->refresh_data.melt_age_commitment_proof,
+ &link_cb,
+ rls);
if (NULL == rls->rlh)
{
@@ -820,11 +883,8 @@ refresh_link_cleanup (void *cls,
if (NULL != rls->rlh)
{
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rls->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (rls->is,
+ cmd->label);
TALER_EXCHANGE_link_cancel (rls->rlh);
rls->rlh = NULL;
}
@@ -838,19 +898,6 @@ refresh_link_cleanup (void *cls,
/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-melt_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
* Task scheduled to re-try #melt_run.
*
* @param cls a `struct RefreshMeltState`
@@ -861,8 +908,7 @@ do_melt_retry (void *cls)
struct RefreshMeltState *rms = cls;
rms->retry_task = NULL;
- rms->is->commands[rms->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (rms->is);
melt_run (rms,
NULL,
rms->is);
@@ -875,18 +921,14 @@ do_melt_retry (void *cls)
* CMD was set to do so.
*
* @param cls closure.
- * @param hr HTTP response details
- * @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 mr melt response details
*/
static void
melt_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- uint32_t noreveal_index,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
+ const struct TALER_EXCHANGE_MeltResponse *mr)
{
struct RefreshMeltState *rms = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &mr->hr;
rms->rmh = NULL;
if (rms->expected_response_code != hr->http_status)
@@ -910,45 +952,57 @@ melt_cb (void *cls,
MAX_BACKOFF);
rms->total_backoff = GNUNET_TIME_relative_add (rms->total_backoff,
rms->backoff);
- rms->is->commands[rms->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (rms->is);
rms->retry_task = GNUNET_SCHEDULER_add_delayed (rms->backoff,
&do_melt_retry,
rms);
return;
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- rms->is->commands[rms->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (rms->is);
+ TALER_TESTING_unexpected_status_with_body (rms->is,
+ hr->http_status,
+ rms->expected_response_code,
+ hr->reply);
return;
}
- rms->noreveal_index = noreveal_index;
+ if (MHD_HTTP_OK == hr->http_status)
+ {
+ rms->noreveal_index = mr->details.ok.noreveal_index;
+ if (mr->details.ok.num_mbds != rms->num_fresh_coins)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ GNUNET_free (rms->mbds);
+ rms->mbds = GNUNET_new_array (
+ mr->details.ok.num_mbds,
+ struct TALER_EXCHANGE_MeltBlindingDetail);
+ for (unsigned int i = 0; i<mr->details.ok.num_mbds; i++)
+ TALER_denom_ewv_copy (&rms->mbds[i].alg_value,
+ &mr->details.ok.mbds[i].alg_value);
+ }
if (0 != rms->total_backoff.rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Total melt backoff for %s was %s\n",
- rms->is->commands[rms->is->ip].label,
+ rms->cmd->label,
GNUNET_STRINGS_relative_time_to_string (rms->total_backoff,
- GNUNET_YES));
+ true));
}
- if (GNUNET_YES == rms->double_melt)
+ if (rms->double_melt)
{
TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
- rms->is->commands[rms->is->ip].label);
- rms->rmh = TALER_EXCHANGE_melt (rms->is->exchange,
- rms->refresh_data_length,
- rms->refresh_data,
- &melt_cb,
- rms);
- rms->double_melt = GNUNET_NO;
+ rms->cmd->label);
+ rms->rmh = TALER_EXCHANGE_melt (
+ TALER_TESTING_interpreter_get_context (rms->is),
+ TALER_TESTING_get_exchange_url (rms->is),
+ TALER_TESTING_get_keys (rms->is),
+ &rms->rms,
+ &rms->refresh_data,
+ &melt_cb,
+ rms);
+ rms->double_melt = false;
return;
}
TALER_TESTING_interpreter_next (rms->is);
@@ -975,36 +1029,53 @@ melt_run (void *cls,
};
const char **melt_fresh_amounts;
+ rms->cmd = cmd;
if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts))
melt_fresh_amounts = default_melt_fresh_amounts;
rms->is = is;
rms->noreveal_index = UINT16_MAX;
+ TALER_refresh_master_setup_random (&rms->rms);
for (num_fresh_coins = 0;
NULL != melt_fresh_amounts[num_fresh_coins];
num_fresh_coins++)
;
rms->num_fresh_coins = num_fresh_coins;
- rms->fresh_pks = GNUNET_new_array
- (num_fresh_coins,
- struct TALER_EXCHANGE_DenomPublicKey);
+ rms->fresh_pks = GNUNET_new_array (
+ num_fresh_coins,
+ struct TALER_EXCHANGE_DenomPublicKey);
{
struct TALER_Amount melt_amount;
struct TALER_Amount fresh_amount;
+ const struct TALER_AgeCommitmentProof *age_commitment_proof = NULL;
+ const struct TALER_AgeCommitmentHash *h_age_commitment = NULL;
const struct TALER_DenominationSignature *melt_sig;
const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
const struct TALER_TESTING_Command *coin_command;
+ bool age_restricted_denom;
if (NULL == (coin_command
- = TALER_TESTING_interpreter_lookup_command
- (is, rms->coin_reference)))
+ = TALER_TESTING_interpreter_lookup_command (
+ is,
+ rms->coin_reference)))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
- if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
- (coin_command, 0, &rms->melt_priv))
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_command,
+ 0,
+ &rms->melt_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_age_commitment_proof (coin_command,
+ 0,
+ &age_commitment_proof))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
@@ -1012,6 +1083,15 @@ melt_run (void *cls,
}
if (GNUNET_OK !=
+ TALER_TESTING_get_trait_h_age_commitment (coin_command,
+ 0,
+ &h_age_commitment))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ if (GNUNET_OK !=
TALER_TESTING_get_trait_denom_sig (coin_command,
0,
&melt_sig))
@@ -1020,32 +1100,42 @@ melt_run (void *cls,
TALER_TESTING_interpreter_fail (rms->is);
return;
}
- if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
- (coin_command, 0, &melt_denom_pub))
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (coin_command,
+ 0,
+ &melt_denom_pub))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
+
/* Melt amount starts with the melt fee of the old coin; we'll add the
values and withdraw fees of the fresh coins next */
- melt_amount = melt_denom_pub->fee_refresh;
+ melt_amount = melt_denom_pub->fees.refresh;
+ age_restricted_denom = melt_denom_pub->key.age_mask.bits != 0;
+ GNUNET_assert (age_restricted_denom == (NULL != age_commitment_proof));
+ GNUNET_assert ((NULL == age_commitment_proof) ||
+ (0 < age_commitment_proof->commitment.num));
for (unsigned int i = 0; i<num_fresh_coins; i++)
{
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
- if (GNUNET_OK != TALER_string_to_amount
- (melt_fresh_amounts[i], &fresh_amount))
+ 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);
+ melt_fresh_amounts[i],
+ i);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
- fresh_pk = TALER_TESTING_find_pk
- (TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount);
+ fresh_pk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (rms->is),
+ &fresh_amount,
+ age_restricted_denom);
if (NULL == fresh_pk)
{
GNUNET_break (0);
@@ -1060,32 +1150,49 @@ melt_run (void *cls,
GNUNET_assert (0 <=
TALER_amount_add (&melt_amount,
&melt_amount,
- &fresh_pk->fee_withdraw));
+ &fresh_pk->fees.withdraw));
rms->fresh_pks[i] = *fresh_pk;
/* Make a deep copy of the RSA key */
- rms->fresh_pks[i].key.rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pk->key.rsa_public_key);
- }
- rms->refresh_data
- = TALER_EXCHANGE_refresh_prepare (rms->melt_priv,
- &melt_amount,
- melt_sig,
- melt_denom_pub,
- num_fresh_coins,
- rms->fresh_pks,
- &rms->refresh_data_length);
-
- if (NULL == rms->refresh_data)
+ TALER_denom_pub_copy (&rms->fresh_pks[i].key,
+ &fresh_pk->key);
+ } /* end for */
+
+ rms->refresh_data.melt_priv = *rms->melt_priv;
+ GNUNET_CRYPTO_eddsa_key_get_public (&rms->melt_priv->eddsa_priv,
+ &rms->melt_pub.eddsa_pub);
+ rms->refresh_data.melt_amount = melt_amount;
+ rms->refresh_data.melt_sig = *melt_sig;
+ rms->refresh_data.melt_pk = *melt_denom_pub;
+
+ if (NULL != age_commitment_proof)
{
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
+ GNUNET_assert (NULL != h_age_commitment);
+ rms->refresh_data.melt_age_commitment_proof = age_commitment_proof;
+ rms->refresh_data.melt_h_age_commitment = h_age_commitment;
}
- rms->rmh = TALER_EXCHANGE_melt (is->exchange,
- rms->refresh_data_length,
- rms->refresh_data,
- &melt_cb,
- rms);
+ rms->refresh_data.fresh_pks = rms->fresh_pks;
+ rms->refresh_data.fresh_pks_len = num_fresh_coins;
+
+ GNUNET_assert (age_restricted_denom ==
+ (NULL != age_commitment_proof));
+ GNUNET_assert ((NULL == age_commitment_proof) ||
+ (0 < age_commitment_proof->commitment.num));
+
+ rms->che.type = TALER_EXCHANGE_CTT_MELT;
+ rms->che.amount = melt_amount;
+ if (NULL != age_commitment_proof)
+ rms->che.details.melt.h_age_commitment = *h_age_commitment;
+ else
+ rms->che.details.melt.no_hac = true;
+
+ rms->rmh = TALER_EXCHANGE_melt (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ &rms->rms,
+ &rms->refresh_data,
+ &melt_cb,
+ rms);
if (NULL == rms->rmh)
{
@@ -1110,11 +1217,11 @@ melt_cleanup (void *cls,
{
struct RefreshMeltState *rms = cls;
+ (void) cmd;
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_TESTING_command_incomplete (rms->is,
+ cmd->label);
TALER_EXCHANGE_melt_cancel (rms->rmh);
rms->rmh = NULL;
}
@@ -1126,13 +1233,15 @@ melt_cleanup (void *cls,
if (NULL != rms->fresh_pks)
{
for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
- GNUNET_CRYPTO_rsa_public_key_free (rms->fresh_pks[i].key.rsa_public_key);
+ TALER_denom_pub_free (&rms->fresh_pks[i].key);
+ GNUNET_free (rms->fresh_pks);
+ }
+ if (NULL != rms->mbds)
+ {
+ for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
+ TALER_denom_ewv_free (&rms->mbds[i].alg_value);
+ GNUNET_free (rms->mbds);
}
- GNUNET_free (rms->fresh_pks);
- rms->fresh_pks = NULL;
- GNUNET_free (rms->refresh_data);
- rms->refresh_data = NULL;
- rms->refresh_data_length = 0;
GNUNET_free (rms->melt_fresh_amounts);
GNUNET_free (rms);
}
@@ -1147,7 +1256,7 @@ melt_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
melt_traits (void *cls,
const void **ret,
const char *trait,
@@ -1162,8 +1271,25 @@ melt_traits (void *cls,
}
{
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]),
- TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv),
+ TALER_TESTING_make_trait_denom_pub (index,
+ &rms->fresh_pks[index]),
+ TALER_TESTING_make_trait_coin_priv (0,
+ rms->melt_priv),
+ TALER_TESTING_make_trait_coin_pub (0,
+ &rms->melt_pub),
+ TALER_TESTING_make_trait_coin_history (0,
+ &rms->che),
+ TALER_TESTING_make_trait_age_commitment_proof (
+ index,
+ rms->refresh_data.melt_age_commitment_proof),
+ TALER_TESTING_make_trait_h_age_commitment (
+ index,
+ rms->refresh_data.melt_h_age_commitment),
+ TALER_TESTING_make_trait_refresh_secret (&rms->rms),
+ (NULL != rms->mbds)
+ ? TALER_TESTING_make_trait_exchange_wd_value (index,
+ &rms->mbds[index].alg_value)
+ : TALER_TESTING_trait_end (),
TALER_TESTING_trait_end ()
};
@@ -1182,7 +1308,7 @@ melt_traits (void *cls,
* @param ap NULL-termianted list of amounts to be melted (one per fresh coin)
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_amounts (struct RefreshMeltState *rms,
va_list ap)
{
@@ -1225,16 +1351,6 @@ parse_amounts (struct RefreshMeltState *rms,
}
-/**
- * Create a "refresh melt" command.
- *
- * @param label command label.
- * @param coin_reference reference to a command
- * that will provide a coin to refresh.
- * @param expected_response_code expected HTTP code.
- * @param ... NULL-terminated list of amounts to be melted
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_melt (const char *label,
const char *coin_reference,
@@ -1247,7 +1363,8 @@ TALER_TESTING_cmd_melt (const char *label,
rms = GNUNET_new (struct RefreshMeltState);
rms->coin_reference = coin_reference;
rms->expected_response_code = expected_response_code;
- va_start (ap, expected_response_code);
+ va_start (ap,
+ expected_response_code);
GNUNET_assert (GNUNET_OK ==
parse_amounts (rms, ap));
va_end (ap);
@@ -1265,18 +1382,6 @@ TALER_TESTING_cmd_melt (const char *label,
}
-/**
- * Create a "refresh melt" CMD that does TWO /refresh/melt
- * requests. This was needed to test the replay of a valid melt
- * request, see #5312.
- *
- * @param label command label
- * @param coin_reference reference to a command that will provide
- * a coin to refresh
- * @param expected_response_code expected HTTP code
- * @param ... NULL-terminated list of amounts to be melted
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_melt_double (const char *label,
const char *coin_reference,
@@ -1289,8 +1394,9 @@ TALER_TESTING_cmd_melt_double (const char *label,
rms = GNUNET_new (struct RefreshMeltState);
rms->coin_reference = coin_reference;
rms->expected_response_code = expected_response_code;
- rms->double_melt = GNUNET_YES;
- va_start (ap, expected_response_code);
+ rms->double_melt = true;
+ va_start (ap,
+ expected_response_code);
GNUNET_assert (GNUNET_OK ==
parse_amounts (rms, ap));
va_end (ap);
@@ -1308,12 +1414,6 @@ TALER_TESTING_cmd_melt_double (const char *label,
}
-/**
- * Modify a "refresh melt" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_melt_with_retry (struct TALER_TESTING_Command cmd)
{
@@ -1335,65 +1435,54 @@ TALER_TESTING_cmd_melt_with_retry (struct TALER_TESTING_Command cmd)
* @param index index number of the object to offer.
* @return #GNUNET_OK on success.
*/
-static int
+static enum GNUNET_GenericReturnValue
refresh_reveal_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct RefreshRevealState *rrs = cls;
- unsigned int num_coins = rrs->num_fresh_coins;
-#define NUM_TRAITS ((num_coins * 4) + 3)
- struct TALER_TESTING_Trait traits[NUM_TRAITS];
-
- /* Making coin privs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[i] = TALER_TESTING_make_trait_coin_priv
- (i, &rrs->fresh_coins[i].coin_priv);
-
- /* Making denom pubs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[num_coins + i]
- = TALER_TESTING_make_trait_denom_pub
- (i, rrs->fresh_coins[i].pk);
-
- /* Making denom sigs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[(num_coins * 2) + i]
- = TALER_TESTING_make_trait_denom_sig
- (i, &rrs->fresh_coins[i].sig);
- /* blinding key traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[(num_coins * 3) + i]
- = TALER_TESTING_make_trait_blinding_key (i,
- &rrs->fresh_coins[i].blinding_key),
-
- /* number of fresh coins */
- traits[(num_coins * 4)] = TALER_TESTING_make_trait_uint
- (0, &rrs->num_fresh_coins);
-
- /* whole array of fresh coins */
- traits[(num_coins * 4) + 1]
- = TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins),
-
- /* end of traits */
- traits[(num_coins * 4) + 2] = TALER_TESTING_trait_end ();
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
+
+ if (index >= rrs->num_fresh_coins)
+ return GNUNET_SYSERR;
+
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_coin_priv (
+ index,
+ &rrs->fresh_coins[index].coin_priv),
+ TALER_TESTING_make_trait_age_commitment_proof (
+ index,
+ rrs->fresh_coins[index].age_commitment_proof),
+ TALER_TESTING_make_trait_h_age_commitment (
+ index,
+ &rrs->fresh_coins[index].h_age_commitment),
+ TALER_TESTING_make_trait_denom_pub (
+ index,
+ rrs->fresh_coins[index].pk),
+ TALER_TESTING_make_trait_denom_sig (
+ index,
+ &rrs->fresh_coins[index].sig),
+ TALER_TESTING_make_trait_blinding_key (
+ index,
+ &rrs->fresh_coins[index].blinding_key),
+ TALER_TESTING_make_trait_array_length (
+ &rrs->num_fresh_coins),
+ TALER_TESTING_make_trait_fresh_coins (
+ (const struct TALER_TESTING_FreshCoinData **) &rrs->fresh_coins),
+ TALER_TESTING_make_trait_planchet_secrets (index,
+ &rrs->psa[index]),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+ }
}
-/**
- * Create a "refresh reveal" command.
- *
- * @param label command label.
- * @param melt_reference reference to a "refresh melt" command.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_refresh_reveal (const char *label,
const char *melt_reference,
@@ -1418,12 +1507,6 @@ TALER_TESTING_cmd_refresh_reveal (const char *label,
}
-/**
- * Modify a "refresh reveal" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd)
{
@@ -1436,14 +1519,6 @@ TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd)
}
-/**
- * Create a "refresh link" command.
- *
- * @param label command label.
- * @param reveal_reference reference to a "refresh reveal" CMD.
- * @param expected_response_code expected HTTP response code
- * @return the "refresh link" command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_refresh_link (const char *label,
const char *reveal_reference,
@@ -1467,12 +1542,6 @@ TALER_TESTING_cmd_refresh_link (const char *label,
}
-/**
- * Modify a "refresh link" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_refresh_link_with_retry (struct TALER_TESTING_Command cmd)
{
diff --git a/src/testing/testing_api_cmd_refund.c b/src/testing/testing_api_cmd_refund.c
index 30f257696..29b68ef08 100644
--- a/src/testing/testing_api_cmd_refund.c
+++ b/src/testing/testing_api_cmd_refund.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -54,9 +54,14 @@ struct RefundState
uint64_t refund_transaction_id;
/**
- * Connection to the exchange.
+ * Entry in the coin's history generated by this operation.
*/
- struct TALER_EXCHANGE_Handle *exchange;
+ struct TALER_EXCHANGE_CoinHistoryEntry che;
+
+ /**
+ * Public key of the refunded coin.
+ */
+ struct TALER_CoinSpendPublicKeyP coin;
/**
* Handle to the refund operation.
@@ -75,38 +80,51 @@ struct RefundState
* response code is acceptable.
*
* @param cls closure
- * @param hr HTTP response details
- * @param exchange_pub public key the exchange
- * used for signing @a obj.
- * @param exchange_sig actual signature confirming the refund
+ * @param rr response details
*/
static void
refund_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const struct TALER_ExchangeSignatureP *exchange_sig)
+ const struct TALER_EXCHANGE_RefundResponse *rr)
{
-
struct RefundState *rs = cls;
- struct TALER_TESTING_Command *refund_cmd;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr;
- refund_cmd = &rs->is->commands[rs->is->ip];
rs->rh = NULL;
if (rs->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- hr->ec,
- refund_cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (rs->is);
+ TALER_TESTING_unexpected_status (rs->is,
+ hr->http_status,
+ rs->expected_response_code);
return;
}
+ if (MHD_HTTP_OK == hr->http_status)
+ {
+ struct TALER_Amount refund_amount;
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (rs->refund_amount,
+ &refund_amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s'\n",
+ rs->refund_amount);
+ TALER_TESTING_interpreter_fail (rs->is);
+ return;
+ }
+ if (0 >
+ TALER_amount_subtract (&rs->che.amount,
+ &refund_amount,
+ &rs->che.details.refund.refund_fee))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to subtract %s from %s\n",
+ TALER_amount2s (&rs->che.details.refund.refund_fee),
+ rs->refund_amount);
+ TALER_TESTING_interpreter_fail (rs->is);
+ return;
+ }
+ }
TALER_TESTING_interpreter_next (rs->is);
}
@@ -125,24 +143,21 @@ refund_run (void *cls,
{
struct RefundState *rs = cls;
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- struct TALER_CoinSpendPublicKeyP coin;
const json_t *contract_terms;
- struct GNUNET_HashCode h_contract_terms;
+ struct TALER_PrivateContractHashP h_contract_terms;
struct TALER_Amount refund_amount;
const struct TALER_MerchantPrivateKeyP *merchant_priv;
const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
- 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",
+ "Failed to parse amount `%s' at %s\n",
rs->refund_amount,
- is->ip,
cmd->label);
TALER_TESTING_interpreter_fail (is);
return;
@@ -157,7 +172,6 @@ refund_run (void *cls,
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_contract_terms (coin_cmd,
- 0,
&contract_terms))
{
GNUNET_break (0);
@@ -169,10 +183,15 @@ refund_run (void *cls,
&h_contract_terms));
/* Hunting for a coin .. */
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (coin_cmd,
- 0,
- &coin_priv))
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ 0,
+ &coin_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (coin_cmd,
+ 0,
+ &denom_pub)) )
+
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
@@ -180,29 +199,76 @@ refund_run (void *cls,
}
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin.eddsa_pub);
+ &rs->coin.eddsa_pub);
if (GNUNET_OK !=
TALER_TESTING_get_trait_merchant_priv (coin_cmd,
- 0,
&merchant_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
- rs->rh = TALER_EXCHANGE_refund (rs->exchange,
- &refund_amount,
- &h_contract_terms,
- &coin,
- rs->refund_transaction_id,
- merchant_priv,
- &refund_cb,
- rs);
+ rs->che.type = TALER_EXCHANGE_CTT_REFUND;
+ rs->che.details.refund.h_contract_terms = h_contract_terms;
+ GNUNET_CRYPTO_eddsa_key_get_public (
+ &merchant_priv->eddsa_priv,
+ &rs->che.details.refund.merchant_pub.eddsa_pub);
+ rs->che.details.refund.refund_fee = denom_pub->fees.refund;
+ rs->che.details.refund.sig_amount = refund_amount;
+ rs->che.details.refund.rtransaction_id = rs->refund_transaction_id;
+ TALER_merchant_refund_sign (&rs->coin,
+ &h_contract_terms,
+ rs->refund_transaction_id,
+ &refund_amount,
+ merchant_priv,
+ &rs->che.details.refund.sig);
+ rs->rh = TALER_EXCHANGE_refund (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ &refund_amount,
+ &h_contract_terms,
+ &rs->coin,
+ rs->refund_transaction_id,
+ merchant_priv,
+ &refund_cb,
+ rs);
GNUNET_assert (NULL != rs->rh);
}
/**
+ * Offer internal data from a "refund" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+refund_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RefundState *rs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_coin_history (0,
+ &rs->che),
+ TALER_TESTING_make_trait_coin_pub (0,
+ &rs->coin),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
* Free the state from a "refund" CMD, and possibly cancel
* a pending operation thereof.
*
@@ -217,10 +283,8 @@ refund_cleanup (void *cls,
if (NULL != rs->rh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rs->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (rs->is,
+ cmd->label);
TALER_EXCHANGE_refund_cancel (rs->rh);
rs->rh = NULL;
}
@@ -228,17 +292,6 @@ refund_cleanup (void *cls,
}
-/**
- * Create a "refund" command.
- *
- * @param label command label.
- * @param expected_response_code expected HTTP status code.
- * @param refund_amount the amount to ask a refund for.
- * @param coin_reference reference to a command that can
- * provide a coin to be refunded.
- *
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_refund (const char *label,
unsigned int expected_response_code,
@@ -248,7 +301,6 @@ TALER_TESTING_cmd_refund (const char *label,
struct RefundState *rs;
rs = GNUNET_new (struct RefundState);
-
rs->expected_response_code = expected_response_code;
rs->refund_amount = refund_amount;
rs->coin_reference = coin_reference;
@@ -257,7 +309,8 @@ TALER_TESTING_cmd_refund (const char *label,
.cls = rs,
.label = label,
.run = &refund_run,
- .cleanup = &refund_cleanup
+ .cleanup = &refund_cleanup,
+ .traits = &refund_traits
};
return cmd;
@@ -265,23 +318,9 @@ TALER_TESTING_cmd_refund (const char *label,
}
-/**
- * Create a "refund" command, allow to specify refund transaction
- * id. Mainly used to create conflicting requests.
- *
- * @param label command label.
- * @param expected_response_code expected HTTP status code.
- * @param refund_amount the amount to ask a refund for.
- * @param coin_reference reference to a command that can
- * provide a coin to be refunded.
- * @param refund_transaction_id transaction id to use
- * in the request.
- *
- * @return the command.
- */
struct TALER_TESTING_Command
-TALER_TESTING_cmd_refund_with_id
- (const char *label,
+TALER_TESTING_cmd_refund_with_id (
+ const char *label,
unsigned int expected_response_code,
const char *refund_amount,
const char *coin_reference,
@@ -299,7 +338,8 @@ TALER_TESTING_cmd_refund_with_id
.cls = rs,
.label = label,
.run = &refund_run,
- .cleanup = &refund_cleanup
+ .cleanup = &refund_cleanup,
+ .traits = &refund_traits
};
return cmd;
diff --git a/src/testing/testing_api_cmd_reserve_attest.c b/src/testing/testing_api_cmd_reserve_attest.c
new file mode 100644
index 000000000..cf4b3a0c2
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_attest.c
@@ -0,0 +1,263 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_reserve_attest.c
+ * @brief Implement the /reserve/$RID/attest test command.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+/**
+ * State for a "attest" CMD.
+ */
+struct AttestState
+{
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Handle to the "reserve attest" operation.
+ */
+ struct TALER_EXCHANGE_ReservesAttestHandle *rsh;
+
+ /**
+ * Private key of the reserve being analyzed.
+ */
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+
+ /**
+ * Public key of the reserve being analyzed.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Array of attributes to request, of length @e attrs_len.
+ */
+ const char **attrs;
+
+ /**
+ * Length of the @e attrs array.
+ */
+ unsigned int attrs_len;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /* TODO: expose fields below as traits... */
+
+ /**
+ * Attested attributes returned by the exchange.
+ */
+ json_t *attributes;
+
+ /**
+ * Expiration time of the attested attributes.
+ */
+ struct GNUNET_TIME_Timestamp expiration_time;
+
+ /**
+ * Signature by the exchange affirming the attributes.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+ /**
+ * Online signing key used by the exchange.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+};
+
+
+/**
+ * Check that the reserve balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+reserve_attest_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_ReservePostAttestResult *rs)
+{
+ struct AttestState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+
+ ss->rsh = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ rs->hr.http_status,
+ __FILE__,
+ __LINE__);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (MHD_HTTP_OK != rs->hr.http_status)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ ss->attributes = json_incref ((json_t*) rs->details.ok.attributes);
+ ss->expiration_time = rs->details.ok.expiration_time;
+ ss->exchange_pub = rs->details.ok.exchange_pub;
+ ss->exchange_sig = rs->details.ok.exchange_sig;
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+attest_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AttestState *ss = cls;
+ const struct TALER_TESTING_Command *create_reserve;
+ const char *exchange_url;
+
+ ss->is = is;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ 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,
+ &ss->reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find reserve_priv for attest query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
+ &ss->reserve_pub.eddsa_pub);
+ ss->rsh = TALER_EXCHANGE_reserves_attest (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ TALER_TESTING_get_keys (is),
+ ss->reserve_priv,
+ ss->attrs_len,
+ ss->attrs,
+ &reserve_attest_cb,
+ ss);
+}
+
+
+/**
+ * Cleanup the state from a "reserve attest" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+attest_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AttestState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_reserves_attest_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ json_decref (ss->attributes);
+ GNUNET_free (ss->attrs);
+ GNUNET_free (ss);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_attest (const char *label,
+ const char *reserve_reference,
+ unsigned int expected_response_code,
+ ...)
+{
+ struct AttestState *ss;
+ unsigned int num_args;
+ const char *ea;
+ va_list ap;
+
+ num_args = 0;
+ va_start (ap, expected_response_code);
+ while (NULL != va_arg (ap, const char *))
+ num_args++;
+ va_end (ap);
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct AttestState);
+ ss->reserve_reference = reserve_reference;
+ ss->expected_response_code = expected_response_code;
+ ss->attrs_len = num_args;
+ ss->attrs = GNUNET_new_array (num_args,
+ const char *);
+ num_args = 0;
+ va_start (ap, expected_response_code);
+ while (NULL != (ea = va_arg (ap, const char *)))
+ ss->attrs[num_args++] = ea;
+ va_end (ap);
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &attest_run,
+ .cleanup = &attest_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_reserve_close.c b/src/testing/testing_api_cmd_reserve_close.c
new file mode 100644
index 000000000..8e272f547
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_close.c
@@ -0,0 +1,260 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_reserve_close.c
+ * @brief Implement the /reserve/$RID/close test command.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "close" CMD.
+ */
+struct CloseState
+{
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Handle to the "reserve close" operation.
+ */
+ struct TALER_EXCHANGE_ReservesCloseHandle *rsh;
+
+ /**
+ * payto://-URI where to wire the funds.
+ */
+ const char *target_account;
+
+ /**
+ * Private key of the reserve being analyzed.
+ */
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+
+ /**
+ * Public key of the reserve being analyzed.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Set to the KYC requirement payto hash *if* the exchange replied with a
+ * request for KYC.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC.
+ */
+ uint64_t requirement_row;
+};
+
+
+/**
+ * Check that the reserve balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+reserve_close_cb (void *cls,
+ const struct TALER_EXCHANGE_ReserveCloseResult *rs)
+{
+ struct CloseState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+
+ ss->rsh = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ rs->hr.http_status,
+ __FILE__,
+ __LINE__);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ switch (rs->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ break;
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ /* nothing to check */
+ ss->requirement_row
+ = rs->details.unavailable_for_legal_reasons.requirement_row;
+ ss->h_payto
+ = rs->details.unavailable_for_legal_reasons.h_payto;
+ break;
+ default:
+ break;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+close_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct CloseState *ss = cls;
+ const struct TALER_TESTING_Command *create_reserve;
+
+ ss->is = is;
+ create_reserve
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ss->reserve_reference);
+
+ if (NULL == create_reserve)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (create_reserve,
+ &ss->reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find reserve_priv for close query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
+ &ss->reserve_pub.eddsa_pub);
+ ss->rsh = TALER_EXCHANGE_reserves_close (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ ss->reserve_priv,
+ ss->target_account,
+ &reserve_close_cb,
+ ss);
+}
+
+
+/**
+ * Cleanup the state from a "reserve close" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+close_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct CloseState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_reserves_close_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+/**
+ * Offer internal data to a "close" CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+close_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct CloseState *cs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_legi_requirement_row (
+ &cs->requirement_row),
+ TALER_TESTING_make_trait_h_payto (
+ &cs->h_payto),
+ TALER_TESTING_trait_end ()
+ };
+
+ if (cs->expected_response_code != MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS)
+ return GNUNET_NO;
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_close (const char *label,
+ const char *reserve_reference,
+ const char *target_account,
+ unsigned int expected_response_code)
+{
+ struct CloseState *ss;
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct CloseState);
+ ss->reserve_reference = reserve_reference;
+ ss->target_account = target_account;
+ ss->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &close_run,
+ .cleanup = &close_cleanup,
+ .traits = &close_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_reserve_get.c b/src/testing/testing_api_cmd_reserve_get.c
new file mode 100644
index 000000000..9a938cf82
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_get.c
@@ -0,0 +1,390 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_reserve_get.c
+ * @brief Implement the GET /reserve/$RID test command.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "poll" CMD.
+ */
+struct PollState
+{
+
+ /**
+ * How long do we give the exchange to respond?
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *poll_reference;
+
+ /**
+ * Timeout to wait for at most.
+ */
+ struct GNUNET_SCHEDULER_Task *tt;
+
+ /**
+ * The interpreter we are using.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * State for a "status" CMD.
+ */
+struct StatusState
+{
+
+ /**
+ * How long do we give the exchange to respond?
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+ /**
+ * Poller waiting for us.
+ */
+ struct PollState *ps;
+
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Handle to the "reserve status" operation.
+ */
+ struct TALER_EXCHANGE_ReservesGetHandle *rsh;
+
+ /**
+ * Expected reserve balance.
+ */
+ const char *expected_balance;
+
+ /**
+ * Public key of the reserve being analyzed.
+ */
+ const struct TALER_ReservePublicKeyP *reserve_pubp;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+};
+
+
+/**
+ * Check that the reserve balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+reserve_status_cb (void *cls,
+ const struct TALER_EXCHANGE_ReserveSummary *rs)
+{
+ struct StatusState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+ struct TALER_Amount eb;
+
+ ss->rsh = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ rs->hr.http_status,
+ __FILE__,
+ __LINE__);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ 0);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (MHD_HTTP_OK == ss->expected_response_code)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (ss->expected_balance,
+ &eb));
+ if (0 != TALER_amount_cmp (&eb,
+ &rs->details.ok.balance))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected amount %s in reserve, wanted %s\n",
+ TALER_amount_to_string (&rs->details.ok.balance),
+ ss->expected_balance);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ }
+ if (NULL != ss->ps)
+ {
+ /* force continuation on long poller */
+ GNUNET_SCHEDULER_cancel (ss->ps->tt);
+ ss->ps->tt = NULL;
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ if (GNUNET_TIME_relative_is_zero (ss->timeout))
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+status_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct StatusState *ss = cls;
+ const struct TALER_TESTING_Command *create_reserve;
+ const char *exchange_url;
+
+ ss->is = is;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ create_reserve
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ss->reserve_reference);
+ GNUNET_assert (NULL != create_reserve);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (create_reserve,
+ &ss->reserve_pubp))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ss->rsh = TALER_EXCHANGE_reserves_get (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ ss->reserve_pubp,
+ ss->timeout,
+ &reserve_status_cb,
+ ss);
+ if (! GNUNET_TIME_relative_is_zero (ss->timeout))
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+}
+
+
+/**
+ * Cleanup the state from a "reserve status" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+status_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct StatusState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_reserves_get_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_status (const char *label,
+ const char *reserve_reference,
+ const char *expected_balance,
+ unsigned int expected_response_code)
+{
+ struct StatusState *ss;
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct StatusState);
+ ss->reserve_reference = reserve_reference;
+ ss->expected_balance = expected_balance;
+ ss->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &status_run,
+ .cleanup = &status_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_poll (const char *label,
+ const char *reserve_reference,
+ const char *expected_balance,
+ struct GNUNET_TIME_Relative timeout,
+ unsigned int expected_response_code)
+{
+ struct StatusState *ss;
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct StatusState);
+ ss->reserve_reference = reserve_reference;
+ ss->expected_balance = expected_balance;
+ ss->expected_response_code = expected_response_code;
+ ss->timeout = timeout;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &status_run,
+ .cleanup = &status_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Long poller timed out. Fail the test.
+ *
+ * @param cls a `struct PollState`
+ */
+static void
+finish_timeout (void *cls)
+{
+ struct PollState *ps = cls;
+
+ ps->tt = NULL;
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ps->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+finish_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PollState *ps = cls;
+ const struct TALER_TESTING_Command *poll_reserve;
+ struct StatusState *ss;
+
+ ps->is = is;
+ poll_reserve
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ps->poll_reference);
+ GNUNET_assert (NULL != poll_reserve);
+ GNUNET_assert (poll_reserve->run == &status_run);
+ ss = poll_reserve->cls;
+ if (NULL == ss->rsh)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_assert (NULL == ss->ps);
+ ss->ps = ps;
+ ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout,
+ &finish_timeout,
+ ps);
+}
+
+
+/**
+ * Cleanup the state from a "reserve finish" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+finish_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PollState *ps = cls;
+
+ if (NULL != ps->tt)
+ {
+ GNUNET_SCHEDULER_cancel (ps->tt);
+ ps->tt = NULL;
+ }
+ GNUNET_free (ps);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_poll_finish (const char *label,
+ struct GNUNET_TIME_Relative timeout,
+ const char *poll_reference)
+{
+ struct PollState *ps;
+
+ GNUNET_assert (NULL != poll_reference);
+ ps = GNUNET_new (struct PollState);
+ ps->timeout = timeout;
+ ps->poll_reference = poll_reference;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ps,
+ .label = label,
+ .run = &finish_run,
+ .cleanup = &finish_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_reserve_get_attestable.c b/src/testing/testing_api_cmd_reserve_get_attestable.c
new file mode 100644
index 000000000..ed1eb1355
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_get_attestable.c
@@ -0,0 +1,242 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_reserve_get_attestable.c
+ * @brief Implement the /reserve/$RID/get_attestable test command.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "get_attestable" CMD.
+ */
+struct GetAttestableState
+{
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Handle to the "reserve get_attestable" operation.
+ */
+ struct TALER_EXCHANGE_ReservesGetAttestHandle *rgah;
+
+ /**
+ * Expected attestable attributes.
+ */
+ const char **expected_attestables;
+
+ /**
+ * Length of the @e expected_attestables array.
+ */
+ unsigned int expected_attestables_length;
+
+ /**
+ * Public key of the reserve being analyzed.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Check that the reserve balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+reserve_get_attestable_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_ReserveGetAttestResult *rs)
+{
+ struct GetAttestableState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+
+ ss->rgah = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ rs->hr.http_status,
+ __FILE__,
+ __LINE__);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (MHD_HTTP_OK != rs->hr.http_status)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ // FIXME: check returned list matches expectations!
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+get_attestable_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct GetAttestableState *ss = cls;
+ const struct TALER_TESTING_Command *ref_reserve;
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+ const char *exchange_url;
+
+ ss->is = is;
+ exchange_url = TALER_TESTING_get_exchange_url (is);
+ if (NULL == exchange_url)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ ref_reserve
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ss->reserve_reference);
+
+ if (NULL == ref_reserve)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK ==
+ TALER_TESTING_get_trait_reserve_priv (ref_reserve,
+ &reserve_priv))
+ {
+ GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
+ &ss->reserve_pub.eddsa_pub);
+ }
+ else
+ {
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (ref_reserve,
+ &reserve_pub))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR (
+ "Failed to find reserve_priv for get_attestable query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ss->reserve_pub = *reserve_pub;
+ }
+ ss->rgah = TALER_EXCHANGE_reserves_get_attestable (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ &ss->reserve_pub,
+ &reserve_get_attestable_cb,
+ ss);
+}
+
+
+/**
+ * Cleanup the state from a "reserve get_attestable" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+get_attestable_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct GetAttestableState *ss = cls;
+
+ if (NULL != ss->rgah)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_reserves_get_attestable_cancel (ss->rgah);
+ ss->rgah = NULL;
+ }
+ GNUNET_free (ss->expected_attestables);
+ GNUNET_free (ss);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_get_attestable (const char *label,
+ const char *reserve_reference,
+ unsigned int expected_response_code,
+ ...)
+{
+ struct GetAttestableState *ss;
+ va_list ap;
+ unsigned int num_expected;
+ const char *ea;
+
+ num_expected = 0;
+ va_start (ap, expected_response_code);
+ while (NULL != va_arg (ap, const char *))
+ num_expected++;
+ va_end (ap);
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct GetAttestableState);
+ ss->reserve_reference = reserve_reference;
+ ss->expected_response_code = expected_response_code;
+ ss->expected_attestables_length = num_expected;
+ ss->expected_attestables = GNUNET_new_array (num_expected,
+ const char *);
+ num_expected = 0;
+ va_start (ap, expected_response_code);
+ while (NULL != (ea = va_arg (ap, const char *)))
+ ss->expected_attestables[num_expected++] = ea;
+ va_end (ap);
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &get_attestable_run,
+ .cleanup = &get_attestable_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_reserve_history.c b/src/testing/testing_api_cmd_reserve_history.c
new file mode 100644
index 000000000..ecb236a54
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_history.c
@@ -0,0 +1,586 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_reserve_history.c
+ * @brief Implement the /reserve/history test command.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "history" CMD.
+ */
+struct HistoryState
+{
+
+ /**
+ * Public key of the reserve being analyzed.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Handle to the "reserve history" operation.
+ */
+ struct TALER_EXCHANGE_ReservesHistoryHandle *rsh;
+
+ /**
+ * Expected reserve balance.
+ */
+ const char *expected_balance;
+
+ /**
+ * Private key of the reserve being analyzed.
+ */
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+};
+
+
+/**
+ * Closure for analysis_cb().
+ */
+struct AnalysisContext
+{
+ /**
+ * Reserve public key we are looking at.
+ */
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+
+ /**
+ * Length of the @e history array.
+ */
+ unsigned int history_length;
+
+ /**
+ * Array of history items to match.
+ */
+ const struct TALER_EXCHANGE_ReserveHistoryEntry *history;
+
+ /**
+ * Array of @e history_length of matched entries.
+ */
+ bool *found;
+
+ /**
+ * Set to true if an entry could not be found.
+ */
+ bool failure;
+};
+
+
+/**
+ * Compare @a h1 and @a h2.
+ *
+ * @param h1 a history entry
+ * @param h2 a history entry
+ * @return 0 if @a h1 and @a h2 are equal
+ */
+static int
+history_entry_cmp (
+ const struct TALER_EXCHANGE_ReserveHistoryEntry *h1,
+ const struct TALER_EXCHANGE_ReserveHistoryEntry *h2)
+{
+ if (h1->type != h2->type)
+ return 1;
+ switch (h1->type)
+ {
+ case TALER_EXCHANGE_RTT_CREDIT:
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (0 == strcasecmp (h1->details.in_details.sender_url,
+ h2->details.in_details.sender_url)) &&
+ (h1->details.in_details.wire_reference ==
+ h2->details.in_details.wire_reference) &&
+ (GNUNET_TIME_timestamp_cmp (h1->details.in_details.timestamp,
+ ==,
+ h2->details.in_details.timestamp)) )
+ return 0;
+ return 1;
+ case TALER_EXCHANGE_RTT_WITHDRAWAL:
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (0 ==
+ TALER_amount_cmp (&h1->details.withdraw.fee,
+ &h2->details.withdraw.fee)) )
+ /* testing_api_cmd_withdraw doesn't set the out_authorization_sig,
+ so we cannot test for it here. but if the amount matches,
+ that should be good enough. */
+ return 0;
+ return 1;
+ case TALER_EXCHANGE_RTT_AGEWITHDRAWAL:
+ /* testing_api_cmd_age_withdraw doesn't set the out_authorization_sig,
+ so we cannot test for it here. but if the amount matches,
+ that should be good enough. */
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (0 ==
+ TALER_amount_cmp (&h1->details.age_withdraw.fee,
+ &h2->details.age_withdraw.fee)) &&
+ (h1->details.age_withdraw.max_age ==
+ h2->details.age_withdraw.max_age))
+ return 0;
+ return 1;
+ case TALER_EXCHANGE_RTT_RECOUP:
+ /* exchange_sig, exchange_pub and timestamp are NOT available
+ from the original recoup response, hence here NOT check(able/ed) */
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.recoup_details.coin_pub,
+ &h2->details.recoup_details.coin_pub)) )
+ return 0;
+ return 1;
+ case TALER_EXCHANGE_RTT_CLOSING:
+ /* testing_api_cmd_exec_closer doesn't set the
+ receiver_account_details, exchange_sig, exchange_pub or wtid or timestamp
+ so we cannot test for it here. but if the amount matches,
+ that should be good enough. */
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (0 ==
+ TALER_amount_cmp (&h1->details.close_details.fee,
+ &h2->details.close_details.fee)) )
+ return 0;
+ return 1;
+ case TALER_EXCHANGE_RTT_MERGE:
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (0 ==
+ TALER_amount_cmp (&h1->details.merge_details.purse_fee,
+ &h2->details.merge_details.purse_fee)) &&
+ (GNUNET_TIME_timestamp_cmp (h1->details.merge_details.merge_timestamp,
+ ==,
+ h2->details.merge_details.merge_timestamp))
+ &&
+ (GNUNET_TIME_timestamp_cmp (h1->details.merge_details.purse_expiration,
+ ==,
+ h2->details.merge_details.purse_expiration))
+ &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.merge_details.merge_pub,
+ &h2->details.merge_details.merge_pub)) &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.merge_details.h_contract_terms,
+ &h2->details.merge_details.h_contract_terms)) &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.merge_details.purse_pub,
+ &h2->details.merge_details.purse_pub)) &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.merge_details.reserve_sig,
+ &h2->details.merge_details.reserve_sig)) &&
+ (h1->details.merge_details.min_age ==
+ h2->details.merge_details.min_age) &&
+ (h1->details.merge_details.flags ==
+ h2->details.merge_details.flags) )
+ return 0;
+ return 1;
+ case TALER_EXCHANGE_RTT_OPEN:
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (GNUNET_TIME_timestamp_cmp (
+ h1->details.open_request.request_timestamp,
+ ==,
+ h2->details.open_request.request_timestamp)) &&
+ (GNUNET_TIME_timestamp_cmp (
+ h1->details.open_request.reserve_expiration,
+ ==,
+ h2->details.open_request.reserve_expiration)) &&
+ (h1->details.open_request.purse_limit ==
+ h2->details.open_request.purse_limit) &&
+ (0 ==
+ TALER_amount_cmp (&h1->details.open_request.reserve_payment,
+ &h2->details.open_request.reserve_payment)) &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.open_request.reserve_sig,
+ &h2->details.open_request.reserve_sig)) )
+ return 0;
+ return 1;
+ case TALER_EXCHANGE_RTT_CLOSE:
+ if ( (0 ==
+ TALER_amount_cmp (&h1->amount,
+ &h2->amount)) &&
+ (GNUNET_TIME_timestamp_cmp (
+ h1->details.close_request.request_timestamp,
+ ==,
+ h2->details.close_request.request_timestamp)) &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.close_request.target_account_h_payto,
+ &h2->details.close_request.target_account_h_payto)) &&
+ (0 ==
+ GNUNET_memcmp (&h1->details.close_request.reserve_sig,
+ &h2->details.close_request.reserve_sig)) )
+ return 0;
+ return 1;
+ }
+ GNUNET_assert (0);
+ return 1;
+}
+
+
+/**
+ * Check if @a cmd changed the reserve, if so, find the
+ * entry in our history and set the respective index in found
+ * to true. If the entry is not found, set failure.
+ *
+ * @param cls our `struct AnalysisContext *`
+ * @param cmd command to analyze for impact on history
+ */
+static void
+analyze_command (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AnalysisContext *ac = cls;
+ const struct TALER_ReservePublicKeyP *reserve_pub = ac->reserve_pub;
+ const struct TALER_EXCHANGE_ReserveHistoryEntry *history = ac->history;
+ unsigned int history_length = ac->history_length;
+ bool *found = ac->found;
+
+ if (TALER_TESTING_cmd_is_batch (cmd))
+ {
+ struct TALER_TESTING_Command *cur;
+ struct TALER_TESTING_Command *bcmd;
+
+ cur = TALER_TESTING_cmd_batch_get_current (cmd);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_batch_cmds (cmd,
+ &bcmd))
+ {
+ GNUNET_break (0);
+ ac->failure = true;
+ return;
+ }
+ for (unsigned int i = 0; NULL != bcmd[i].label; i++)
+ {
+ struct TALER_TESTING_Command *step = &bcmd[i];
+
+ analyze_command (ac,
+ step);
+ if (ac->failure)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Entry for batch step `%s' missing in history\n",
+ step->label);
+ return;
+ }
+ if (step == cur)
+ break; /* if *we* are in a batch, make sure not to analyze commands past 'now' */
+ }
+ return;
+ }
+
+ {
+ const struct TALER_ReservePublicKeyP *rp;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (cmd,
+ &rp))
+ return; /* command does nothing for reserves */
+ if (0 !=
+ GNUNET_memcmp (rp,
+ reserve_pub))
+ return; /* command affects some _other_ reserve */
+ for (unsigned int j = 0; true; j++)
+ {
+ const struct TALER_EXCHANGE_ReserveHistoryEntry *he;
+ bool matched = false;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_history (cmd,
+ j,
+ &he))
+ {
+ /* NOTE: only for debugging... */
+ if (0 == j)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Command `%s' has the reserve_pub, but lacks reserve history trait\n",
+ cmd->label);
+ return; /* command does nothing for reserves */
+ }
+ for (unsigned int i = 0; i<history_length; i++)
+ {
+ if (found[i])
+ continue; /* already found, skip */
+ if (0 ==
+ history_entry_cmp (he,
+ &history[i]))
+ {
+ found[i] = true;
+ matched = true;
+ break;
+ }
+ }
+ if (! matched)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Command `%s' reserve history entry #%u not found\n",
+ cmd->label,
+ j);
+ ac->failure = true;
+ return;
+ }
+ }
+ }
+}
+
+
+/**
+ * Check that the reserve balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+reserve_history_cb (void *cls,
+ const struct TALER_EXCHANGE_ReserveHistory *rs)
+{
+ struct HistoryState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+ struct TALER_Amount eb;
+
+ ss->rsh = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ rs->hr.http_status,
+ __FILE__,
+ __LINE__);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ 0);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (MHD_HTTP_OK != rs->hr.http_status)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (ss->expected_balance,
+ &eb));
+
+ if (0 != TALER_amount_cmp (&eb,
+ &rs->details.ok.balance))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected amount in reserve: %s\n",
+ TALER_amount_to_string (&rs->details.ok.balance));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected balance of: %s\n",
+ TALER_amount_to_string (&eb));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ {
+ bool found[rs->details.ok.history_len];
+ struct AnalysisContext ac = {
+ .reserve_pub = &ss->reserve_pub,
+ .history = rs->details.ok.history,
+ .history_length = rs->details.ok.history_len,
+ .found = found
+ };
+
+ memset (found,
+ 0,
+ sizeof (found));
+ TALER_TESTING_iterate (is,
+ true,
+ &analyze_command,
+ &ac);
+ if (ac.failure)
+ {
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ for (unsigned int i = 0; i<rs->details.ok.history_len; i++)
+ {
+ if (found[i])
+ continue;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "History entry at index %u of type %d not justified by command history\n",
+ i,
+ rs->details.ok.history[i].type);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+history_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct HistoryState *ss = cls;
+ const struct TALER_TESTING_Command *create_reserve;
+
+ ss->is = is;
+ create_reserve
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ss->reserve_reference);
+ if (NULL == create_reserve)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (create_reserve,
+ &ss->reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find reserve_priv for history query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
+ &ss->reserve_pub.eddsa_pub);
+ ss->rsh = TALER_EXCHANGE_reserves_history (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ ss->reserve_priv,
+ 0,
+ &reserve_history_cb,
+ ss);
+}
+
+
+/**
+ * Offer internal data from a "history" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+history_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct HistoryState *hs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_reserve_pub (&hs->reserve_pub),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Cleanup the state from a "reserve history" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+history_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct HistoryState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_reserves_history_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_history (const char *label,
+ const char *reserve_reference,
+ const char *expected_balance,
+ unsigned int expected_response_code)
+{
+ struct HistoryState *ss;
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct HistoryState);
+ ss->reserve_reference = reserve_reference;
+ ss->expected_balance = expected_balance;
+ ss->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &history_run,
+ .cleanup = &history_cleanup,
+ .traits = &history_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_reserve_open.c b/src/testing/testing_api_cmd_reserve_open.c
new file mode 100644
index 000000000..189d06b26
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_open.c
@@ -0,0 +1,349 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_reserve_open.c
+ * @brief Implement the /reserve/$RID/open test command.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * Information we track per coin used to pay for opening the
+ * reserve.
+ */
+struct CoinDetail
+{
+ /**
+ * Name of the command and index of the coin to use.
+ */
+ const char *name;
+
+ /**
+ * Amount to charge to this coin.
+ */
+ struct TALER_Amount amount;
+};
+
+
+/**
+ * State for a "open" CMD.
+ */
+struct OpenState
+{
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Requested expiration time.
+ */
+ struct GNUNET_TIME_Relative req_expiration_time;
+
+ /**
+ * Requested minimum number of purses.
+ */
+ uint32_t min_purses;
+
+ /**
+ * Amount to pay for the opening from the reserve balance.
+ */
+ struct TALER_Amount reserve_pay;
+
+ /**
+ * Handle to the "reserve open" operation.
+ */
+ struct TALER_EXCHANGE_ReservesOpenHandle *rsh;
+
+ /**
+ * Expected reserve balance.
+ */
+ const char *expected_balance;
+
+ /**
+ * Length of the @e cd array.
+ */
+ unsigned int cpl;
+
+ /**
+ * Coin details, array of length @e cpl.
+ */
+ struct CoinDetail *cd;
+
+ /**
+ * Private key of the reserve being analyzed.
+ */
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+
+ /**
+ * Public key of the reserve being analyzed.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Check that the reserve balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param rs HTTP response details
+ */
+static void
+reserve_open_cb (void *cls,
+ const struct TALER_EXCHANGE_ReserveOpenResult *rs)
+{
+ struct OpenState *ss = cls;
+ struct TALER_TESTING_Interpreter *is = ss->is;
+
+ ss->rsh = NULL;
+ if (ss->expected_response_code != rs->hr.http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ rs->hr.http_status,
+ __FILE__,
+ __LINE__);
+ json_dumpf (rs->hr.reply,
+ stderr,
+ JSON_INDENT (2));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (MHD_HTTP_OK != rs->hr.http_status)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+open_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct OpenState *ss = cls;
+ const struct TALER_TESTING_Command *create_reserve;
+ struct TALER_EXCHANGE_PurseDeposit cp[GNUNET_NZL (ss->cpl)];
+
+ ss->is = is;
+ create_reserve
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ss->reserve_reference);
+
+ if (NULL == create_reserve)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (create_reserve,
+ &ss->reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find reserve_priv for open query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ss->reserve_priv->eddsa_priv,
+ &ss->reserve_pub.eddsa_pub);
+ for (unsigned int i = 0; i<ss->cpl; i++)
+ {
+ struct TALER_EXCHANGE_PurseDeposit *cpi = &cp[i];
+ const struct TALER_TESTING_Command *cmdi;
+ const struct TALER_AgeCommitmentProof *age_commitment_proof;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_DenominationSignature *denom_sig;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+ char *cref;
+ unsigned int cidx;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_parse_coin_reference (ss->cd[i].name,
+ &cref,
+ &cidx))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to parse coin reference `%s'\n",
+ ss->cd[i].name);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ cmdi = TALER_TESTING_interpreter_lookup_command (is,
+ cref);
+ GNUNET_free (cref);
+ if (NULL == cmdi)
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Command `%s' not found\n",
+ ss->cd[i].name);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_age_commitment_proof (cmdi,
+ cidx,
+ &age_commitment_proof))
+ ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (cmdi,
+ cidx,
+ &coin_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_sig (cmdi,
+ cidx,
+ &denom_sig)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (cmdi,
+ cidx,
+ &denom_pub)) )
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Coin trait not found in `%s'\n",
+ ss->cd[i].name);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ cpi->age_commitment_proof = age_commitment_proof;
+ cpi->coin_priv = *coin_priv;
+ cpi->denom_sig = *denom_sig;
+ cpi->amount = ss->cd[i].amount;
+ cpi->h_denom_pub = denom_pub->h_key;
+ }
+ ss->rsh = TALER_EXCHANGE_reserves_open (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ ss->reserve_priv,
+ &ss->reserve_pay,
+ ss->cpl,
+ cp,
+ GNUNET_TIME_relative_to_timestamp (ss->req_expiration_time),
+ ss->min_purses,
+ &reserve_open_cb,
+ ss);
+}
+
+
+/**
+ * Cleanup the state from a "reserve open" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+open_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct OpenState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ TALER_TESTING_command_incomplete (ss->is,
+ cmd->label);
+ TALER_EXCHANGE_reserves_open_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_reserve_open (const char *label,
+ const char *reserve_reference,
+ const char *reserve_pay,
+ struct GNUNET_TIME_Relative expiration_time,
+ uint32_t min_purses,
+ unsigned int expected_response_code,
+ ...)
+{
+ struct OpenState *ss;
+ va_list ap;
+ const char *name;
+ unsigned int i;
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct OpenState);
+ ss->reserve_reference = reserve_reference;
+ ss->req_expiration_time = expiration_time;
+ ss->min_purses = min_purses;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (reserve_pay,
+ &ss->reserve_pay));
+ ss->expected_response_code = expected_response_code;
+ va_start (ap,
+ expected_response_code);
+ while (NULL != (name = va_arg (ap, const char *)))
+ ss->cpl++;
+ va_end (ap);
+ GNUNET_assert (0 == (ss->cpl % 2));
+ ss->cpl /= 2; /* name and amount per coin */
+ ss->cd = GNUNET_new_array (ss->cpl,
+ struct CoinDetail);
+ i = 0;
+ va_start (ap,
+ expected_response_code);
+ while (NULL != (name = va_arg (ap, const char *)))
+ {
+ struct CoinDetail *cd = &ss->cd[i];
+ cd->name = name;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (va_arg (ap,
+ const char *),
+ &cd->amount));
+ i++;
+ }
+ va_end (ap);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &open_run,
+ .cleanup = &open_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_reserve_purse.c b/src/testing/testing_api_cmd_reserve_purse.c
new file mode 100644
index 000000000..ef6964f26
--- /dev/null
+++ b/src/testing/testing_api_cmd_reserve_purse.c
@@ -0,0 +1,371 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_reserve_purse.c
+ * @brief command for testing /reserves/$PID/purse
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "purse create with merge" CMD.
+ */
+struct ReservePurseState
+{
+
+ /**
+ * Merge time (local time when the command was
+ * executed).
+ */
+ struct GNUNET_TIME_Timestamp merge_timestamp;
+
+ /**
+ * Reserve private key.
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Reserve public key.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Reserve signature generated for the request
+ * (client-side).
+ */
+ struct TALER_ReserveSignatureP reserve_sig;
+
+ /**
+ * Private key of the purse.
+ */
+ struct TALER_PurseContractPrivateKeyP purse_priv;
+
+ /**
+ * Public key of the purse.
+ */
+ struct TALER_PurseContractPublicKeyP purse_pub;
+
+ /**
+ * Private key with the merge capability.
+ */
+ struct TALER_PurseMergePrivateKeyP merge_priv;
+
+ /**
+ * Public key of the merge capability.
+ */
+ struct TALER_PurseMergePublicKeyP merge_pub;
+
+ /**
+ * Private key to decrypt the contract.
+ */
+ struct TALER_ContractDiffiePrivateP contract_priv;
+
+ /**
+ * Handle while operation is running.
+ */
+ struct TALER_EXCHANGE_PurseCreateMergeHandle *dh;
+
+ /**
+ * When will the purse expire?
+ */
+ struct GNUNET_TIME_Relative expiration_rel;
+
+ /**
+ * When will the purse expire?
+ */
+ struct GNUNET_TIME_Timestamp purse_expiration;
+
+ /**
+ * Hash of the payto://-URI for the reserve we are
+ * merging into.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC.
+ */
+ uint64_t requirement_row;
+
+ /**
+ * Contract terms for the purse.
+ */
+ json_t *contract_terms;
+
+ /**
+ * Reference to the reserve, or NULL (!).
+ */
+ const char *reserve_ref;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * True to pay the purse fee.
+ */
+ bool pay_purse_fee;
+};
+
+
+/**
+ * Callback to analyze the /reserves/$PID/purse response, just used to check if
+ * the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param dr purse response details
+ */
+static void
+purse_cb (void *cls,
+ const struct TALER_EXCHANGE_PurseCreateMergeResponse *dr)
+{
+ struct ReservePurseState *ds = cls;
+
+ ds->dh = NULL;
+ ds->reserve_sig = *dr->reserve_sig;
+ if (ds->expected_response_code != dr->hr.http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ dr->hr.http_status,
+ ds->expected_response_code);
+ return;
+ }
+ switch (dr->hr.http_status)
+ {
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ /* KYC required */
+ ds->requirement_row =
+ dr->details.unavailable_for_legal_reasons.requirement_row;
+ break;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+purse_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ReservePurseState *ds = cls;
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+ const struct TALER_TESTING_Command *ref;
+
+ (void) cmd;
+ ds->is = is;
+ ref = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->reserve_ref);
+ GNUNET_assert (NULL != ref);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (ref,
+ &reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ ds->reserve_priv = *reserve_priv;
+ GNUNET_CRYPTO_eddsa_key_create (&ds->purse_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->purse_priv.eddsa_priv,
+ &ds->purse_pub.eddsa_pub);
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->reserve_priv.eddsa_priv,
+ &ds->reserve_pub.eddsa_pub);
+ GNUNET_CRYPTO_eddsa_key_create (&ds->merge_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->merge_priv.eddsa_priv,
+ &ds->merge_pub.eddsa_pub);
+ GNUNET_CRYPTO_ecdhe_key_create (&ds->contract_priv.ecdhe_priv);
+ ds->purse_expiration = GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_relative_to_absolute (ds->expiration_rel));
+
+ {
+ char *payto_uri;
+ const char *exchange_url;
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ payto_uri = TALER_reserve_make_payto (exchange_url,
+ &ds->reserve_pub);
+ TALER_payto_hash (payto_uri,
+ &ds->h_payto);
+ GNUNET_free (payto_uri);
+ }
+
+ GNUNET_assert (0 ==
+ json_object_set_new (
+ ds->contract_terms,
+ "pay_deadline",
+ GNUNET_JSON_from_timestamp (ds->purse_expiration)));
+ ds->merge_timestamp = GNUNET_TIME_timestamp_get ();
+ ds->dh = TALER_EXCHANGE_purse_create_with_merge (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ &ds->reserve_priv,
+ &ds->purse_priv,
+ &ds->merge_priv,
+ &ds->contract_priv,
+ ds->contract_terms,
+ true /* upload contract */,
+ ds->pay_purse_fee,
+ ds->merge_timestamp,
+ &purse_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not purse reserve\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "purse" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct ReservePurseState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+purse_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ReservePurseState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_purse_create_with_merge_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ json_decref (ds->contract_terms);
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data from a "purse" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static enum GNUNET_GenericReturnValue
+purse_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct ReservePurseState *ds = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_timestamp (0,
+ &ds->merge_timestamp),
+ TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
+ TALER_TESTING_make_trait_purse_priv (&ds->purse_priv),
+ TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
+ TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
+ TALER_TESTING_make_trait_merge_pub (&ds->merge_pub),
+ TALER_TESTING_make_trait_contract_priv (&ds->contract_priv),
+ TALER_TESTING_make_trait_reserve_priv (&ds->reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (&ds->reserve_pub),
+ TALER_TESTING_make_trait_reserve_sig (&ds->reserve_sig),
+ TALER_TESTING_make_trait_legi_requirement_row (&ds->requirement_row),
+ TALER_TESTING_make_trait_h_payto (&ds->h_payto),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_purse_create_with_reserve (
+ const char *label,
+ unsigned int expected_http_status,
+ const char *contract_terms,
+ bool upload_contract,
+ bool pay_purse_fee,
+ struct GNUNET_TIME_Relative expiration,
+ const char *reserve_ref)
+{
+ struct ReservePurseState *ds;
+ json_error_t err;
+
+ ds = GNUNET_new (struct ReservePurseState);
+ ds->expiration_rel = expiration;
+ ds->contract_terms = json_loads (contract_terms,
+ 0 /* flags */,
+ &err);
+ GNUNET_assert (NULL != ds->contract_terms);
+ ds->pay_purse_fee = pay_purse_fee;
+ ds->reserve_ref = reserve_ref;
+ ds->expected_response_code = expected_http_status;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &purse_run,
+ .cleanup = &purse_cleanup,
+ .traits = &purse_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_reserve_purse.c */
diff --git a/src/testing/testing_api_cmd_revoke.c b/src/testing/testing_api_cmd_revoke.c
index 9f904454e..f734be1a4 100644
--- a/src/testing/testing_api_cmd_revoke.c
+++ b/src/testing/testing_api_cmd_revoke.c
@@ -100,7 +100,7 @@ revoke_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
revoke_traits (void *cls,
const void **ret,
const char *trait,
@@ -110,8 +110,7 @@ revoke_traits (void *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_make_trait_process (&rs->revoke_proc),
TALER_TESTING_trait_end ()
};
@@ -142,14 +141,12 @@ revoke_run (void *cls,
/* 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,
@@ -183,16 +180,6 @@ revoke_run (void *cls,
}
-/**
- * Make a "revoke" command.
- *
- * @param label the command label.
- * @param expected_response_code expected HTTP status code.
- * @param coin_reference reference to a CMD that will offer the
- * denomination to revoke.
- * @param config_filename configuration file name.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_revoke (const char *label,
unsigned int expected_response_code,
diff --git a/src/testing/testing_api_cmd_revoke_denom_key.c b/src/testing/testing_api_cmd_revoke_denom_key.c
index 7c77c3566..2663c538f 100644
--- a/src/testing/testing_api_cmd_revoke_denom_key.c
+++ b/src/testing/testing_api_cmd_revoke_denom_key.c
@@ -65,28 +65,22 @@ struct RevokeState
* Function called with information about the post revocation operation result.
*
* @param cls closure with a `struct RevokeState *`
- * @param hr HTTP response data
+ * @param rdr response data
*/
static void
success_cb (
void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+ const struct TALER_EXCHANGE_ManagementRevokeDenominationResponse *rdr)
{
struct RevokeState *rs = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &rdr->hr;
rs->kh = NULL;
if (rs->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- rs->is->commands[rs->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (rs->is);
+ TALER_TESTING_unexpected_status (rs->is,
+ hr->http_status,
+ rs->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (rs->is);
@@ -158,7 +152,23 @@ revoke_run (void *cls,
const struct TALER_TESTING_Command *coin_cmd;
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
struct TALER_MasterSignatureP master_sig;
+ const char *exchange_url;
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
rs->is = is;
/* Get denom pub from trait */
coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
@@ -185,13 +195,27 @@ revoke_run (void *cls,
}
else
{
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
TALER_exchange_offline_denomination_revoke_sign (&denom_pub->h_key,
- &is->master_priv,
+ master_priv,
&master_sig);
}
rs->kh = TALER_EXCHANGE_management_revoke_denomination_key (
- is->ctx,
- is->exchange_url,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
&denom_pub->h_key,
&master_sig,
&success_cb,
diff --git a/src/testing/testing_api_cmd_revoke_sign_key.c b/src/testing/testing_api_cmd_revoke_sign_key.c
index 9745d728d..65b80b4c9 100644
--- a/src/testing/testing_api_cmd_revoke_sign_key.c
+++ b/src/testing/testing_api_cmd_revoke_sign_key.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -65,28 +65,22 @@ struct RevokeState
* Function called with information about the post revocation operation result.
*
* @param cls closure with a `struct RevokeState *`
- * @param hr HTTP response data
+ * @param rsr response data
*/
static void
success_cb (
void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+ const struct TALER_EXCHANGE_ManagementRevokeSigningKeyResponse *rsr)
{
struct RevokeState *rs = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &rsr->hr;
rs->kh = NULL;
if (rs->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- rs->is->commands[rs->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (rs->is);
+ TALER_TESTING_unexpected_status (rs->is,
+ hr->http_status,
+ rs->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (rs->is);
@@ -158,7 +152,23 @@ revoke_run (void *cls,
const struct TALER_TESTING_Command *coin_cmd;
const struct TALER_ExchangePublicKeyP *exchange_pub;
struct TALER_MasterSignatureP master_sig;
+ const char *exchange_url;
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
rs->is = is;
/* Get sign pub from trait */
coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
@@ -185,13 +195,27 @@ revoke_run (void *cls,
}
else
{
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
TALER_exchange_offline_signkey_revoke_sign (exchange_pub,
- &is->master_priv,
+ master_priv,
&master_sig);
}
rs->kh = TALER_EXCHANGE_management_revoke_signing_key (
- is->ctx,
- is->exchange_url,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
exchange_pub,
&master_sig,
&success_cb,
diff --git a/src/testing/testing_api_cmd_rewind.c b/src/testing/testing_api_cmd_rewind.c
deleted file mode 100644
index 979607cd7..000000000
--- a/src/testing/testing_api_cmd_rewind.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_rewind.c
- * @brief command to rewind the instruction pointer.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_exchange_service.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "rewind" CMD.
- */
-struct RewindIpState
-{
- /**
- * Instruction pointer to set into the interpreter.
- */
- const char *target_label;
-
- /**
- * How many times this set should take place. However, this value lives at
- * the calling process, and this CMD is only in charge of checking and
- * decremeting it.
- */
- unsigned int counter;
-};
-
-
-/**
- * Only defined to respect the API.
- */
-static void
-rewind_ip_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- (void) cls;
- (void) cmd;
-}
-
-
-/**
- * Seek for the @a target command in @a batch (and rewind to it
- * if successful).
- *
- * @param is the interpreter state (for failures)
- * @param cmd batch to search for @a target
- * @param target command to search for
- * @return #GNUNET_OK on success, #GNUNET_NO if target was not found,
- * #GNUNET_SYSERR if target is in the future and we failed
- */
-static int
-seek_batch (struct TALER_TESTING_Interpreter *is,
- const struct TALER_TESTING_Command *cmd,
- const struct TALER_TESTING_Command *target)
-{
- unsigned int new_ip;
-#define BATCH_INDEX 1
- struct TALER_TESTING_Command *batch;
- struct TALER_TESTING_Command *current;
- struct TALER_TESTING_Command *icmd;
- const struct TALER_TESTING_Command *match;
-
- current = TALER_TESTING_cmd_batch_get_current (cmd);
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_cmd (cmd,
- BATCH_INDEX,
- &batch));
- match = NULL;
- for (new_ip = 0;
- NULL != (icmd = &batch[new_ip]);
- new_ip++)
- {
- if (current == target)
- current = NULL;
- if (icmd == target)
- {
- match = icmd;
- break;
- }
- if (TALER_TESTING_cmd_is_batch (icmd))
- {
- int ret = seek_batch (is,
- icmd,
- target);
- if (GNUNET_SYSERR == ret)
- return GNUNET_SYSERR; /* failure! */
- if (GNUNET_OK == ret)
- {
- match = icmd;
- break;
- }
- }
- }
- if (NULL == current)
- {
- /* refuse to jump forward */
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
- }
- if (NULL == match)
- return GNUNET_NO; /* not found */
- TALER_TESTING_cmd_batch_set_current (cmd,
- new_ip);
- return GNUNET_OK;
-}
-
-
-/**
- * Run the "rewind" CMD.
- *
- * @param cls closure.
- * @param cmd command being executed now.
- * @param is the interpreter state.
- */
-static void
-rewind_ip_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RewindIpState *ris = cls;
- const struct TALER_TESTING_Command *target;
- unsigned int new_ip;
-
- (void) cmd;
- if (0 == ris->counter)
- {
- TALER_TESTING_interpreter_next (is);
- return;
- }
- target
- = TALER_TESTING_interpreter_lookup_command (is,
- ris->target_label);
- if (NULL == target)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- ris->counter--;
- for (new_ip = 0;
- NULL != is->commands[new_ip].label;
- new_ip++)
- {
- const struct TALER_TESTING_Command *cmd = &is->commands[new_ip];
-
- if (cmd == target)
- break;
- if (TALER_TESTING_cmd_is_batch (cmd))
- {
- int ret = seek_batch (is,
- cmd,
- target);
- if (GNUNET_SYSERR == ret)
- return; /* failure! */
- if (GNUNET_OK == ret)
- break;
- }
- }
- if (new_ip > is->ip)
- {
- /* refuse to jump forward */
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- is->ip = new_ip - 1; /* -1 because the next function will advance by one */
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Make the instruction pointer point to @a new_ip
- * only if @a counter is greater than zero.
- *
- * @param label command label
- * @param target_label label of the new instruction pointer's destination after the jump;
- * must be before the current instruction
- * @param counter counts how many times the rewinding is to happen.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_rewind_ip (const char *label,
- const char *target_label,
- unsigned int counter)
-{
- struct RewindIpState *ris;
-
- ris = GNUNET_new (struct RewindIpState);
- ris->target_label = target_label;
- ris->counter = counter;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ris,
- .label = label,
- .run = &rewind_ip_run,
- .cleanup = &rewind_ip_cleanup
- };
-
- return cmd;
- }
-}
diff --git a/src/testing/testing_api_cmd_run_fakebank.c b/src/testing/testing_api_cmd_run_fakebank.c
new file mode 100644
index 000000000..7739d3c0c
--- /dev/null
+++ b/src/testing/testing_api_cmd_run_fakebank.c
@@ -0,0 +1,214 @@
+/*
+ This file is part of TALER
+ (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_run_fakebank.c
+ * @brief Command to run fakebank in-process
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+/**
+ * State for a "run fakebank" CMD.
+ */
+struct RunFakebankState
+{
+
+ /**
+ * Our interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Handle to the fakebank we are running.
+ */
+ struct TALER_FAKEBANK_Handle *fakebank;
+
+ /**
+ * URL of the bank.
+ */
+ char *bank_url;
+
+ /**
+ * Currency to use.
+ */
+ char *currency;
+
+ /**
+ * Data for access control.
+ */
+ struct TALER_BANK_AuthenticationData ba;
+
+ /**
+ * Port to use.
+ */
+ uint16_t port;
+};
+
+
+/**
+ * Run the "get_exchange" command.
+ *
+ * @param cls closure.
+ * @param cmd the command currently being executed.
+ * @param is the interpreter state.
+ */
+static void
+run_fakebank_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RunFakebankState *rfs = cls;
+
+ (void) cmd;
+ rfs->fakebank = TALER_FAKEBANK_start (rfs->port,
+ rfs->currency);
+ if (NULL == rfs->fakebank)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Cleanup the state.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+run_fakebank_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RunFakebankState *rfs = cls;
+
+ if (NULL != rfs->fakebank)
+ {
+ TALER_FAKEBANK_stop (rfs->fakebank);
+ rfs->fakebank = NULL;
+ }
+ GNUNET_free (rfs->ba.wire_gateway_url);
+ GNUNET_free (rfs->bank_url);
+ GNUNET_free (rfs->currency);
+ GNUNET_free (rfs);
+}
+
+
+/**
+ * Offer internal data to a "run_fakebank" CMD state to other commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+run_fakebank_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RunFakebankState *rfs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_bank_auth_data (&rfs->ba),
+ TALER_TESTING_make_trait_fakebank (rfs->fakebank),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_run_fakebank (
+ const char *label,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *exchange_account_section)
+{
+ struct RunFakebankState *rfs;
+ unsigned long long fakebank_port;
+ char *exchange_payto_uri;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "BANK",
+ "HTTP_PORT",
+ &fakebank_port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "BANK",
+ "HTTP_PORT");
+ GNUNET_assert (0);
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ exchange_account_section,
+ "PAYTO_URI",
+ &exchange_payto_uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ exchange_account_section,
+ "PAYTO_URI");
+ GNUNET_assert (0);
+ }
+ rfs = GNUNET_new (struct RunFakebankState);
+ rfs->port = (uint16_t) fakebank_port;
+ GNUNET_asprintf (&rfs->bank_url,
+ "http://localhost:%u/",
+ (unsigned int) rfs->port);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_config_get_currency (cfg,
+ &rfs->currency));
+ {
+ char *exchange_xtalerbank_account;
+
+ exchange_xtalerbank_account
+ = TALER_xtalerbank_account_from_payto (exchange_payto_uri);
+ GNUNET_assert (NULL != exchange_xtalerbank_account);
+ GNUNET_asprintf (&rfs->ba.wire_gateway_url,
+ "http://localhost:%u/%s/",
+ (unsigned int) fakebank_port,
+ exchange_xtalerbank_account);
+ GNUNET_free (exchange_xtalerbank_account);
+ GNUNET_free (exchange_payto_uri);
+ }
+ GNUNET_free (exchange_payto_uri);
+ rfs->ba.method = TALER_BANK_AUTH_NONE;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rfs,
+ .label = label,
+ .run = &run_fakebank_run,
+ .cleanup = &run_fakebank_cleanup,
+ .traits = &run_fakebank_traits,
+ .name = "fakebank"
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_serialize_keys.c b/src/testing/testing_api_cmd_serialize_keys.c
deleted file mode 100644
index 82df0f064..000000000
--- a/src/testing/testing_api_cmd_serialize_keys.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- This file is part of TALER
- (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_serialize_keys.c
- * @brief Lets tests use the keys serialization API.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include <jansson.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * Internal state for a serialize-keys CMD.
- */
-struct SerializeKeysState
-{
- /**
- * Serialized keys.
- */
- json_t *keys;
-
- /**
- * Exchange URL. Needed because the exchange gets disconnected
- * from, after keys serialization. This value is then needed by
- * subsequent commands that have to reconnect to the exchange.
- */
- char *exchange_url;
-};
-
-
-/**
- * Internal state for a connect-with-state CMD.
- */
-struct ConnectWithStateState
-{
-
- /**
- * Reference to a CMD that offers a serialized key-state
- * that will be used in the reconnection.
- */
- const char *state_reference;
-
- /**
- * If set to GNUNET_YES, then the /keys callback has already
- * been passed the control to the next CMD. This is necessary
- * because it is not uncommon that the /keys callback gets
- * invoked multiple times, and without this flag, we would keep
- * going "next" CMD upon every invocation (causing impredictable
- * behaviour as for the instruction pointer.)
- */
- unsigned int consumed;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-serialize_keys_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct SerializeKeysState *sks = cls;
-
- sks->keys = TALER_EXCHANGE_serialize_data (is->exchange);
- if (NULL == sks->keys)
- TALER_TESTING_interpreter_fail (is);
-
- sks->exchange_url = GNUNET_strdup
- (TALER_EXCHANGE_get_base_url (is->exchange));
- TALER_EXCHANGE_disconnect (is->exchange);
- is->exchange = NULL;
- is->working = GNUNET_NO;
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state of a "serialize keys" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-serialize_keys_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct SerializeKeysState *sks = cls;
-
- if (NULL != sks->keys)
- {
- json_decref (sks->keys);
- }
- GNUNET_free (sks->exchange_url);
- GNUNET_free (sks);
-}
-
-
-/**
- * Offer serialized keys as trait.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-serialize_keys_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct SerializeKeysState *sks = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_exchange_keys (0, sks->keys),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- sks->exchange_url),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-connect_with_state_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct ConnectWithStateState *cwss = cls;
- const struct TALER_TESTING_Command *state_cmd;
- const json_t *serialized_keys;
- const char *exchange_url;
-
- /* This command usually gets rescheduled after serialized
- * reconnection. */
- if (GNUNET_YES == cwss->consumed)
- {
- TALER_TESTING_interpreter_next (is);
- return;
- }
-
- cwss->is = is;
- state_cmd = TALER_TESTING_interpreter_lookup_command
- (is, cwss->state_reference);
-
- /* Command providing serialized keys not found. */
- if (NULL == state_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_exchange_keys (state_cmd,
- 0,
- &serialized_keys));
- {
- char *dump;
-
- dump = json_dumps (serialized_keys,
- JSON_INDENT (1));
- TALER_LOG_DEBUG ("Serialized key-state: %s\n",
- dump);
- free (dump);
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_url (state_cmd,
- TALER_TESTING_UT_EXCHANGE_BASE_URL,
- &exchange_url));
- is->exchange = TALER_EXCHANGE_connect (is->ctx,
- exchange_url,
- &TALER_TESTING_cert_cb,
- cwss,
- TALER_EXCHANGE_OPTION_DATA,
- serialized_keys,
- TALER_EXCHANGE_OPTION_END);
- cwss->consumed = GNUNET_YES;
-}
-
-
-/**
- * Cleanup the state of a "connect with state" CMD. Just
- * a placeholder to avoid jumping on an invalid address.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-connect_with_state_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct ConnectWithStateState *cwss = cls;
-
- GNUNET_free (cwss);
-}
-
-
-/**
- * Make a serialize-keys CMD. It will ask for
- * keys serialization __and__ disconnect from the
- * exchange.
- *
- * @param label CMD label
- * @return the CMD.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_serialize_keys (const char *label)
-{
- struct SerializeKeysState *sks;
-
- sks = GNUNET_new (struct SerializeKeysState);
- {
- struct TALER_TESTING_Command cmd = {
- .cls = sks,
- .label = label,
- .run = serialize_keys_run,
- .cleanup = serialize_keys_cleanup,
- .traits = serialize_keys_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make a connect-with-state CMD. This command
- * will use a serialized key state to reconnect
- * to the exchange.
- *
- * @param label command label
- * @param state_reference label of a CMD offering
- * a serialized key state.
- * @return the CMD.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_connect_with_state (const char *label,
- const char *state_reference)
-{
- struct ConnectWithStateState *cwss;
-
- cwss = GNUNET_new (struct ConnectWithStateState);
- cwss->state_reference = state_reference;
- cwss->consumed = GNUNET_NO;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = cwss,
- .label = label,
- .run = connect_with_state_run,
- .cleanup = connect_with_state_cleanup
- };
-
- return cmd;
- }
-}
diff --git a/src/testing/testing_api_cmd_set_officer.c b/src/testing/testing_api_cmd_set_officer.c
new file mode 100644
index 000000000..4fbe5e368
--- /dev/null
+++ b/src/testing/testing_api_cmd_set_officer.c
@@ -0,0 +1,301 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_set_officer.c
+ * @brief command for testing /management/aml-officers
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "set_officer" CMD.
+ */
+struct SetOfficerState
+{
+
+ /**
+ * Update AML officer handle while operation is running.
+ */
+ struct TALER_EXCHANGE_ManagementUpdateAmlOfficer *dh;
+
+ /**
+ * Our interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Reference to command to previous set officer
+ * to update, or NULL.
+ */
+ const char *ref_cmd;
+
+ /**
+ * Name to use for the officer.
+ */
+ const char *name;
+
+ /**
+ * Private key of the AML officer.
+ */
+ struct TALER_AmlOfficerPrivateKeyP officer_priv;
+
+ /**
+ * Public key of the AML officer.
+ */
+ struct TALER_AmlOfficerPublicKeyP officer_pub;
+
+ /**
+ * Is the officer supposed to be enabled?
+ */
+ bool is_active;
+
+ /**
+ * Is access supposed to be read-only?
+ */
+ bool read_only;
+
+};
+
+
+/**
+ * Callback to analyze the /management/XXX response, just used to check
+ * if the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param ar response details
+ */
+static void
+set_officer_cb (void *cls,
+ const struct
+ TALER_EXCHANGE_ManagementUpdateAmlOfficerResponse *ar)
+{
+ struct SetOfficerState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &ar->hr;
+
+ ds->dh = NULL;
+ if (MHD_HTTP_NO_CONTENT != hr->http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ MHD_HTTP_NO_CONTENT);
+ return;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+set_officer_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct SetOfficerState *ds = cls;
+ struct GNUNET_TIME_Timestamp now;
+ struct TALER_MasterSignatureP master_sig;
+ const char *exchange_url;
+
+ (void) cmd;
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
+ now = GNUNET_TIME_timestamp_get ();
+ ds->is = is;
+ if (NULL == ds->ref_cmd)
+ {
+ GNUNET_CRYPTO_eddsa_key_create (&ds->officer_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->officer_priv.eddsa_priv,
+ &ds->officer_pub.eddsa_pub);
+ }
+ else
+ {
+ const struct TALER_TESTING_Command *ref;
+ const struct TALER_AmlOfficerPrivateKeyP *officer_priv;
+ const struct TALER_AmlOfficerPublicKeyP *officer_pub;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ ds->ref_cmd);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_officer_pub (ref,
+ &officer_pub));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_officer_priv (ref,
+ &officer_priv));
+ ds->officer_pub = *officer_pub;
+ ds->officer_priv = *officer_priv;
+ }
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
+
+ TALER_exchange_offline_aml_officer_status_sign (&ds->officer_pub,
+ ds->name,
+ now,
+ ds->is_active,
+ ds->read_only,
+ master_priv,
+ &master_sig);
+ }
+ ds->dh = TALER_EXCHANGE_management_update_aml_officer (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ &ds->officer_pub,
+ ds->name,
+ now,
+ ds->is_active,
+ ds->read_only,
+ &master_sig,
+ &set_officer_cb,
+ ds);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "set_officer" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct SetOfficerState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+set_officer_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct SetOfficerState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_management_update_aml_officer_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data of a "set officer" CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+set_officer_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct SetOfficerState *ws = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_officer_pub (&ws->officer_pub),
+ TALER_TESTING_make_trait_officer_priv (&ws->officer_priv),
+ TALER_TESTING_make_trait_officer_name (ws->name),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_set_officer (
+ const char *label,
+ const char *ref_cmd,
+ const char *name,
+ bool is_active,
+ bool read_only)
+{
+ struct SetOfficerState *ds;
+
+ ds = GNUNET_new (struct SetOfficerState);
+ ds->ref_cmd = ref_cmd;
+ ds->name = name;
+ ds->is_active = is_active;
+ ds->read_only = read_only;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &set_officer_run,
+ .cleanup = &set_officer_cleanup,
+ .traits = &set_officer_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_set_officer.c */
diff --git a/src/testing/testing_api_cmd_set_wire_fee.c b/src/testing/testing_api_cmd_set_wire_fee.c
index 613e0f713..460a71e40 100644
--- a/src/testing/testing_api_cmd_set_wire_fee.c
+++ b/src/testing/testing_api_cmd_set_wire_fee.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020 Taler Systems SA
+ Copyright (C) 2020, 2022 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
@@ -77,27 +77,21 @@ struct WireFeeState
* if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
+ * @param sfr response details
*/
static void
wire_add_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+ const struct TALER_EXCHANGE_ManagementSetWireFeeResponse *sfr)
{
struct WireFeeState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &sfr->hr;
ds->dh = NULL;
if (ds->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ds->is);
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ ds->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (ds->is);
@@ -119,25 +113,41 @@ wire_add_run (void *cls,
struct WireFeeState *ds = cls;
struct TALER_MasterSignatureP master_sig;
struct GNUNET_TIME_Absolute now;
- struct GNUNET_TIME_Absolute start_time;
- struct GNUNET_TIME_Absolute end_time;
- struct TALER_Amount wire_fee;
- struct TALER_Amount closing_fee;
+ struct GNUNET_TIME_Timestamp start_time;
+ struct GNUNET_TIME_Timestamp end_time;
+ struct TALER_WireFeeSet fees;
+ const char *exchange_url;
(void) cmd;
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
ds->is = is;
now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
- start_time = GNUNET_TIME_absolute_subtract (now,
- GNUNET_TIME_UNIT_HOURS);
- end_time = GNUNET_TIME_absolute_add (now,
- GNUNET_TIME_UNIT_HOURS);
+ start_time = GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_absolute_subtract (now,
+ GNUNET_TIME_UNIT_HOURS));
+ end_time = GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_absolute_add (now,
+ GNUNET_TIME_UNIT_HOURS));
if ( (GNUNET_OK !=
TALER_string_to_amount (ds->closing_fee,
- &closing_fee)) ||
+ &fees.closing)) ||
(GNUNET_OK !=
TALER_string_to_amount (ds->wire_fee,
- &wire_fee)) )
+ &fees.wire)) )
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
@@ -152,22 +162,34 @@ wire_add_run (void *cls,
}
else
{
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
TALER_exchange_offline_wire_fee_sign (ds->wire_method,
start_time,
end_time,
- &wire_fee,
- &closing_fee,
- &is->master_priv,
+ &fees,
+ master_priv,
&master_sig);
}
ds->dh = TALER_EXCHANGE_management_set_wire_fees (
- is->ctx,
- is->exchange_url,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
ds->wire_method,
start_time,
end_time,
- &wire_fee,
- &closing_fee,
+ &fees,
&master_sig,
&wire_add_cb,
ds);
@@ -195,10 +217,8 @@ wire_add_cleanup (void *cls,
if (NULL != ds->dh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ds->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
TALER_EXCHANGE_management_set_wire_fees_cancel (ds->dh);
ds->dh = NULL;
}
@@ -206,26 +226,6 @@ wire_add_cleanup (void *cls,
}
-/**
- * Offer internal data from a "wire_add" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-wire_add_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- return GNUNET_NO;
-}
-
-
struct TALER_TESTING_Command
TALER_TESTING_cmd_set_wire_fee (const char *label,
const char *wire_method,
@@ -247,8 +247,7 @@ TALER_TESTING_cmd_set_wire_fee (const char *label,
.cls = ds,
.label = label,
.run = &wire_add_run,
- .cleanup = &wire_add_cleanup,
- .traits = &wire_add_traits
+ .cleanup = &wire_add_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_stat.c b/src/testing/testing_api_cmd_stat.c
index 9461a22cf..8723aac0d 100644
--- a/src/testing/testing_api_cmd_stat.c
+++ b/src/testing/testing_api_cmd_stat.c
@@ -28,43 +28,16 @@
/**
- * Cleanup the state from a "stat service" CMD.
+ * Run a "stat" CMD.
*
* @param cls closure.
- * @param cmd the command which is being cleaned up.
+ * @param cmd the command being run.
+ * @param is the interpreter state.
*/
static void
-stat_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- (void) cls;
- (void) cmd;
- /* nothing to clean. */
-}
-
-
-/**
- * No traits to offer, just provide a stub to be called when
- * some CMDs iterates through the list of all the commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the trait to return.
- * @return #GNUNET_OK on success.
- */
-static int
-stat_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- return GNUNET_NO;
-}
+stat_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
/**
@@ -80,9 +53,20 @@ stat_cmd (struct TALER_TESTING_Timer *timings,
struct GNUNET_TIME_Relative duration;
struct GNUNET_TIME_Relative lat;
- if (cmd->start_time.abs_value_us > cmd->finish_time.abs_value_us)
+ if (GNUNET_TIME_absolute_cmp (cmd->start_time,
+ >,
+ cmd->finish_time))
{
- GNUNET_break (0);
+ /* This is a problem, except of course for
+ this command itself, as we clearly did not yet
+ finish... */
+ if (cmd->run != &stat_run)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Bad timings for `%s'\n",
+ cmd->label);
+ GNUNET_break (0);
+ }
return;
}
duration = GNUNET_TIME_absolute_get_difference (cmd->start_time,
@@ -114,36 +98,35 @@ stat_cmd (struct TALER_TESTING_Timer *timings,
/**
* Obtain statistics for @a timings of @a cmd
*
- * @param timings what timings to get
+ * @param[in,out] cls what timings to get
* @param cmd command to process
*/
static void
-do_stat (struct TALER_TESTING_Timer *timings,
+do_stat (void *cls,
const struct TALER_TESTING_Command *cmd)
{
+ struct TALER_TESTING_Timer *timings = cls;
+
if (TALER_TESTING_cmd_is_batch (cmd))
{
-#define BATCH_INDEX 1
struct TALER_TESTING_Command *bcmd;
if (GNUNET_OK !=
- TALER_TESTING_get_trait_cmd (cmd,
- BATCH_INDEX,
- &bcmd))
+ TALER_TESTING_get_trait_batch_cmds (cmd,
+ &bcmd))
{
GNUNET_break (0);
return;
}
-
- for (unsigned int j = 0; NULL != bcmd[j].label; j++)
+ for (unsigned int j = 0;
+ NULL != bcmd[j].label;
+ j++)
do_stat (timings,
&bcmd[j]);
+ return;
}
- else
- {
- stat_cmd (timings,
- cmd);
- }
+ stat_cmd (timings,
+ cmd);
}
@@ -161,31 +144,20 @@ stat_run (void *cls,
{
struct TALER_TESTING_Timer *timings = cls;
- for (unsigned int i = 0; NULL != is->commands[i].label; i++)
- {
- if (cmd == &is->commands[i])
- break; /* skip at our current command */
- do_stat (timings,
- &is->commands[i]);
- }
+ TALER_TESTING_iterate (is,
+ true,
+ &do_stat,
+ timings);
TALER_TESTING_interpreter_next (is);
}
-/**
- * Obtain performance data from the interpreter.
- *
- * @param timers what commands (by label) to obtain runtimes for
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_stat (struct TALER_TESTING_Timer *timers)
{
struct TALER_TESTING_Command cmd = {
.label = "stat",
- .run = stat_run,
- .cleanup = stat_cleanup,
- .traits = stat_traits,
+ .run = &stat_run,
.cls = (void *) timers
};
@@ -193,4 +165,4 @@ TALER_TESTING_cmd_stat (struct TALER_TESTING_Timer *timers)
}
-/* end of testing_api_cmd_sleep.c */
+/* end of testing_api_cmd_stat.c */
diff --git a/src/testing/testing_api_cmd_status.c b/src/testing/testing_api_cmd_status.c
deleted file mode 100644
index 6acfcc75b..000000000
--- a/src/testing/testing_api_cmd_status.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_cmd_status.c
- * @brief Implement the /reserve/status test command.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "status" CMD.
- */
-struct StatusState
-{
- /**
- * Label to the command which created the reserve to check,
- * needed to resort the reserve key.
- */
- const char *reserve_reference;
-
- /**
- * Handle to the "reserve status" operation.
- */
- struct TALER_EXCHANGE_ReservesGetHandle *rsh;
-
- /**
- * Expected reserve balance.
- */
- const char *expected_balance;
-
- /**
- * Public key of the reserve being analyzed.
- */
- const struct TALER_ReservePublicKeyP *reserve_pubp;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * Compare @a h1 and @a h2.
- *
- * @param h1 a history entry
- * @param h2 a history entry
- * @return 0 if @a h1 and @a h2 are equal
- */
-static int
-history_entry_cmp (const struct TALER_EXCHANGE_ReserveHistory *h1,
- const struct TALER_EXCHANGE_ReserveHistory *h2)
-{
- if (h1->type != h2->type)
- return 1;
- switch (h1->type)
- {
- case TALER_EXCHANGE_RTT_CREDIT:
- if ( (0 ==
- TALER_amount_cmp (&h1->amount,
- &h2->amount)) &&
- (0 == strcasecmp (h1->details.in_details.sender_url,
- h2->details.in_details.sender_url)) &&
- (h1->details.in_details.wire_reference ==
- h2->details.in_details.wire_reference) &&
- (h1->details.in_details.timestamp.abs_value_us ==
- h2->details.in_details.timestamp.abs_value_us) )
- return 0;
- return 1;
- case TALER_EXCHANGE_RTT_WITHDRAWAL:
- if ( (0 ==
- TALER_amount_cmp (&h1->amount,
- &h2->amount)) &&
- (0 ==
- TALER_amount_cmp (&h1->details.withdraw.fee,
- &h2->details.withdraw.fee)) )
- /* testing_api_cmd_withdraw doesn't set the out_authorization_sig,
- so we cannot test for it here. but if the amount matches,
- that should be good enough. */
- return 0;
- return 1;
- case TALER_EXCHANGE_RTT_RECOUP:
- /* exchange_sig, exchange_pub and timestamp are NOT available
- from the original recoup response, hence here NOT check(able/ed) */
- if ( (0 ==
- TALER_amount_cmp (&h1->amount,
- &h2->amount)) &&
- (0 ==
- GNUNET_memcmp (&h1->details.recoup_details.coin_pub,
- &h2->details.recoup_details.coin_pub)) )
- return 0;
- return 1;
- case TALER_EXCHANGE_RTT_CLOSE:
- /* testing_api_cmd_exec_closer doesn't set the
- receiver_account_details, exchange_sig, exchange_pub or wtid or timestamp
- so we cannot test for it here. but if the amount matches,
- that should be good enough. */
- if ( (0 ==
- TALER_amount_cmp (&h1->amount,
- &h2->amount)) &&
- (0 ==
- TALER_amount_cmp (&h1->details.close_details.fee,
- &h2->details.close_details.fee)) )
- return 0;
- return 1;
- }
- GNUNET_assert (0);
- return 1;
-}
-
-
-/**
- * Check if @a cmd changed the reserve, if so, find the
- * entry in @a history and set the respective index in @a found
- * to #GNUNET_YES. If the entry is not found, return #GNUNET_SYSERR.
- *
- * @param reserve_pub public key of the reserve for which we have the @a history
- * @param cmd command to analyze for impact on history
- * @param history_length number of entries in @a history and @a found
- * @param history history to check
- * @param[in,out] found array to update
- * @return #GNUNET_OK if @a cmd action on reserve was found in @a history
- */
-static int
-analyze_command (const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_TESTING_Command *cmd,
- unsigned int history_length,
- const struct TALER_EXCHANGE_ReserveHistory *history,
- int *found)
-{
- if (TALER_TESTING_cmd_is_batch (cmd))
- {
-#define BATCH_INDEX 1
- struct TALER_TESTING_Command *cur;
- struct TALER_TESTING_Command *bcmd;
-
- cur = TALER_TESTING_cmd_batch_get_current (cmd);
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_cmd (cmd,
- BATCH_INDEX,
- &bcmd))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- for (unsigned int i = 0; NULL != bcmd[i].label; i++)
- {
- struct TALER_TESTING_Command *step = &bcmd[i];
-
- if (step == cur)
- break; /* if *we* are in a batch, make sure not to analyze commands past 'now' */
- if (GNUNET_OK !=
- analyze_command (reserve_pub,
- step,
- history_length,
- history,
- found))
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
- }
- else
- {
- const struct TALER_ReservePublicKeyP *rp;
- const struct TALER_EXCHANGE_ReserveHistory *he;
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (cmd,
- 0,
- &rp))
- return GNUNET_OK; /* command does nothing for reserves */
- if (0 !=
- GNUNET_memcmp (rp,
- reserve_pub))
- return GNUNET_OK; /* command affects some _other_ reserve */
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_history (cmd,
- 0,
- &he))
- {
- /* NOTE: only for debugging... */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Command `%s' has the reserve_pub trait, but does not reserve history trait\n",
- cmd->label);
- return GNUNET_OK; /* command does nothing for reserves */
- }
- for (unsigned int i = 0; i<history_length; i++)
- {
- if (found[i])
- continue; /* already found, skip */
- if (0 ==
- history_entry_cmp (he,
- &history[i]))
- {
- found[i] = GNUNET_YES;
- return GNUNET_OK;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Command `%s' reserve history entry not found\n",
- cmd->label);
- return GNUNET_SYSERR;
- }
-}
-
-
-/**
- * Check that the reserve balance and HTTP response code are
- * both acceptable.
- *
- * @param cls closure.
- * @param hr HTTP response details
- * @param balance current balance in the reserve, NULL on error.
- * @param history_length number of entries in the transaction
- * history, 0 on error.
- * @param history detailed transaction history, NULL on error.
- */
-static void
-reserve_status_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_Amount *balance,
- unsigned int history_length,
- const struct TALER_EXCHANGE_ReserveHistory *history)
-{
- struct StatusState *ss = cls;
- struct TALER_TESTING_Interpreter *is = ss->is;
- struct TALER_Amount eb;
-
- ss->rsh = NULL;
- if (ss->expected_response_code != hr->http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected HTTP response code: %d in %s:%u\n",
- hr->http_status,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ss->is);
- return;
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (ss->expected_balance,
- &eb));
-
- if (0 != TALER_amount_cmp (&eb,
- balance))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected amount in reserve: %s\n",
- TALER_amount_to_string (balance));
- TALER_TESTING_interpreter_fail (ss->is);
- return;
- }
- {
- int found[history_length];
-
- memset (found,
- 0,
- sizeof (found));
- for (unsigned int i = 0; i<=is->ip; i++)
- {
- struct TALER_TESTING_Command *cmd = &is->commands[i];
-
- if (GNUNET_OK !=
- analyze_command (ss->reserve_pubp,
- cmd,
- history_length,
- history,
- found))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Entry for command `%s' missing in history\n",
- cmd->label);
- TALER_TESTING_interpreter_fail (ss->is);
- return;
- }
- }
- for (unsigned int i = 0; i<history_length; i++)
- if (! found[i])
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "History entry at index %u of type %d not justified by command history\n",
- i,
- history[i].type);
- TALER_TESTING_interpreter_fail (ss->is);
- return;
- }
- }
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command being executed.
- * @param is the interpreter state.
- */
-static void
-status_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct StatusState *ss = cls;
- const struct TALER_TESTING_Command *create_reserve;
-
- ss->is = is;
- create_reserve
- = TALER_TESTING_interpreter_lookup_command (is,
- ss->reserve_reference);
-
- if (NULL == create_reserve)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (create_reserve,
- 0,
- &ss->reserve_pubp))
- {
- GNUNET_break (0);
- TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n");
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- ss->rsh = TALER_EXCHANGE_reserves_get (is->exchange,
- ss->reserve_pubp,
- GNUNET_TIME_UNIT_ZERO,
- &reserve_status_cb,
- ss);
-}
-
-
-/**
- * Cleanup the state from a "reserve status" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-status_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct StatusState *ss = cls;
-
- if (NULL != ss->rsh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ss->is->ip,
- cmd->label);
- TALER_EXCHANGE_reserves_get_cancel (ss->rsh);
- ss->rsh = NULL;
- }
- GNUNET_free (ss);
-}
-
-
-/**
- * Create a "reserve status" command.
- *
- * @param label the command label.
- * @param reserve_reference reference to the reserve to check.
- * @param expected_balance expected balance for the reserve.
- * @param expected_response_code expected HTTP response code.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_status (const char *label,
- const char *reserve_reference,
- const char *expected_balance,
- unsigned int expected_response_code)
-{
- struct StatusState *ss;
-
- GNUNET_assert (NULL != reserve_reference);
- ss = GNUNET_new (struct StatusState);
- ss->reserve_reference = reserve_reference;
- ss->expected_balance = expected_balance;
- ss->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ss,
- .label = label,
- .run = &status_run,
- .cleanup = &status_cleanup
- };
-
- return cmd;
- }
-}
diff --git a/src/testing/testing_api_cmd_system_start.c b/src/testing/testing_api_cmd_system_start.c
new file mode 100644
index 000000000..541ad75c1
--- /dev/null
+++ b/src/testing/testing_api_cmd_system_start.c
@@ -0,0 +1,395 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not,
+ see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_system_start.c
+ * @brief run taler-benchmark-setup.sh command
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "system" CMD.
+ */
+struct SystemState
+{
+
+ /**
+ * System process.
+ */
+ struct GNUNET_OS_Process *system_proc;
+
+ /**
+ * Input pipe to @e system_proc, used to keep the
+ * process alive until we are done.
+ */
+ struct GNUNET_DISK_PipeHandle *pipe_in;
+
+ /**
+ * Output pipe to @e system_proc, used to find out
+ * when the services are ready.
+ */
+ struct GNUNET_DISK_PipeHandle *pipe_out;
+
+ /**
+ * Task reading from @e pipe_in.
+ */
+ struct GNUNET_SCHEDULER_Task *reader;
+
+ /**
+ * Waiting for child to die.
+ */
+ struct GNUNET_ChildWaitHandle *cwh;
+
+ /**
+ * Our interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * NULL-terminated array of command-line arguments.
+ */
+ char **args;
+
+ /**
+ * Current input buffer, 0-terminated. Contains the last 15 bytes of input
+ * so we can search them again for the "<<READY>>" tag.
+ */
+ char ibuf[16];
+
+ /**
+ * Did we find the ready tag?
+ */
+ bool ready;
+
+ /**
+ * Is the child process still running?
+ */
+ bool active;
+};
+
+
+/**
+ * Defines a GNUNET_ChildCompletedCallback which is sent back
+ * upon death or completion of a child process.
+ *
+ * @param cls our `struct SystemState *`
+ * @param type type of the process
+ * @param exit_code status code of the process
+ */
+static void
+setup_terminated (void *cls,
+ enum GNUNET_OS_ProcessStatusType type,
+ long unsigned int exit_code)
+{
+ struct SystemState *as = cls;
+
+ as->cwh = NULL;
+ as->active = false;
+ if (NULL != as->reader)
+ {
+ GNUNET_SCHEDULER_cancel (as->reader);
+ as->reader = NULL;
+ }
+ if (! as->ready)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Launching Taler system failed: %d/%llu\n",
+ (int) type,
+ (unsigned long long) exit_code);
+ TALER_TESTING_interpreter_fail (as->is);
+ return;
+ }
+}
+
+
+/**
+ * Start helper to read from stdout of child.
+ *
+ * @param as our system state
+ */
+static void
+start_reader (struct SystemState *as);
+
+
+static void
+read_stdout (void *cls)
+{
+ struct SystemState *as = cls;
+ const struct GNUNET_DISK_FileHandle *fh;
+ char buf[1024 * 10];
+ ssize_t ret;
+ size_t off = 0;
+
+ as->reader = NULL;
+ strcpy (buf,
+ as->ibuf);
+ off = strlen (buf);
+ fh = GNUNET_DISK_pipe_handle (as->pipe_out,
+ GNUNET_DISK_PIPE_END_READ);
+ ret = GNUNET_DISK_file_read (fh,
+ &buf[off],
+ sizeof (buf) - off);
+ if (-1 == ret)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "read");
+ TALER_TESTING_interpreter_fail (as->is);
+ return;
+ }
+ if (0 == ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Child closed stdout\n");
+ return;
+ }
+ /* forward log, except single '.' outputs */
+ if ( (1 != ret) ||
+ ('.' != buf[off]) )
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "TUS: %.*s\n",
+ (int) ret,
+ &buf[off]);
+ start_reader (as);
+ off += ret;
+ if (as->ready)
+ {
+ /* already done */
+ return;
+ }
+ if (NULL !=
+ memmem (buf,
+ off,
+ "\n<<READY>>\n",
+ strlen ("\n<<READY>>\n")))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Taler system UP\n");
+ as->ready = true;
+ TALER_TESTING_interpreter_next (as->is);
+ return;
+ }
+
+ {
+ size_t mcpy;
+
+ mcpy = GNUNET_MIN (off,
+ sizeof (as->ibuf) - 1);
+ memcpy (as->ibuf,
+ &buf[off - mcpy],
+ mcpy);
+ as->ibuf[mcpy] = '\0';
+ }
+}
+
+
+static void
+start_reader (struct SystemState *as)
+{
+ const struct GNUNET_DISK_FileHandle *fh;
+
+ GNUNET_assert (NULL == as->reader);
+ fh = GNUNET_DISK_pipe_handle (as->pipe_out,
+ GNUNET_DISK_PIPE_END_READ);
+ as->reader = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ fh,
+ &read_stdout,
+ as);
+}
+
+
+/**
+ * Run the command. Use the `taler-exchange-system' program.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ * @param is interpreter state.
+ */
+static void
+system_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct SystemState *as = cls;
+
+ (void) cmd;
+ as->is = is;
+ as->pipe_in = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_READ);
+ GNUNET_assert (NULL != as->pipe_in);
+ as->pipe_out = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
+ GNUNET_assert (NULL != as->pipe_out);
+ as->system_proc
+ = GNUNET_OS_start_process_vap (
+ GNUNET_OS_INHERIT_STD_ERR,
+ as->pipe_in, as->pipe_out, NULL,
+ "taler-unified-setup.sh",
+ as->args);
+ if (NULL == as->system_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ as->active = true;
+ start_reader (as);
+ as->cwh = GNUNET_wait_child (as->system_proc,
+ &setup_terminated,
+ as);
+}
+
+
+/**
+ * Free the state of a "system" CMD, and possibly kill its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+system_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct SystemState *as = cls;
+
+ (void) cmd;
+ if (NULL != as->cwh)
+ {
+ GNUNET_wait_child_cancel (as->cwh);
+ as->cwh = NULL;
+ }
+ if (NULL != as->reader)
+ {
+ GNUNET_SCHEDULER_cancel (as->reader);
+ as->reader = NULL;
+ }
+ if (NULL != as->system_proc)
+ {
+ if (as->active)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (as->system_proc,
+ SIGTERM));
+ GNUNET_OS_process_wait (as->system_proc);
+ }
+ GNUNET_OS_process_destroy (as->system_proc);
+ as->system_proc = NULL;
+ }
+ if (NULL != as->pipe_in)
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_DISK_pipe_close (as->pipe_in));
+ as->pipe_in = NULL;
+ }
+ if (NULL != as->pipe_out)
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_DISK_pipe_close (as->pipe_out));
+ as->pipe_out = NULL;
+ }
+
+ for (unsigned int i = 0; NULL != as->args[i]; i++)
+ GNUNET_free (as->args[i]);
+ GNUNET_free (as->args);
+ GNUNET_free (as);
+}
+
+
+/**
+ * Offer "system" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+system_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct SystemState *as = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (&as->system_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_system_start (
+ const char *label,
+ const char *config_file,
+ ...)
+{
+ struct SystemState *as;
+ va_list ap;
+ const char *arg;
+ unsigned int cnt;
+
+ as = GNUNET_new (struct SystemState);
+ cnt = 4; /* 0-2 reserved, +1 for NULL termination */
+ va_start (ap,
+ config_file);
+ while (NULL != (arg = va_arg (ap,
+ const char *)))
+ {
+ cnt++;
+ }
+ va_end (ap);
+ as->args = GNUNET_new_array (cnt,
+ char *);
+ as->args[0] = GNUNET_strdup ("taler-unified-setup");
+ as->args[1] = GNUNET_strdup ("-c");
+ as->args[2] = GNUNET_strdup (config_file);
+ cnt = 3;
+ va_start (ap,
+ config_file);
+ while (NULL != (arg = va_arg (ap,
+ const char *)))
+ {
+ as->args[cnt++] = GNUNET_strdup (arg);
+ }
+ va_end (ap);
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = as,
+ .label = label,
+ .run = &system_run,
+ .cleanup = &system_cleanup,
+ .traits = &system_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_system_start.c */
diff --git a/src/testing/testing_api_cmd_take_aml_decision.c b/src/testing/testing_api_cmd_take_aml_decision.c
new file mode 100644
index 000000000..c0e23de22
--- /dev/null
+++ b/src/testing/testing_api_cmd_take_aml_decision.c
@@ -0,0 +1,321 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_cmd_take_aml_decision.c
+ * @brief command for testing /aml/$OFFICER_PUB/decision
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "take_aml_decision" CMD.
+ */
+struct AmlDecisionState
+{
+
+ /**
+ * Auditor enable handle while operation is running.
+ */
+ struct TALER_EXCHANGE_AddAmlDecision *dh;
+
+ /**
+ * Our interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Reference to command to previous set officer command that gives
+ * us an officer_priv trait.
+ */
+ const char *officer_ref_cmd;
+
+ /**
+ * Reference to command to previous AML-triggering event that gives
+ * us a payto-hash trait.
+ */
+ const char *account_ref_cmd;
+
+ /**
+ * Payto hash of the account we are manipulating the AML settings for.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * New AML state to use.
+ */
+ enum TALER_AmlDecisionState new_state;
+
+ /**
+ * Justification given.
+ */
+ const char *justification;
+
+ /**
+ * KYC requirement to add.
+ */
+ const char *kyc_requirement;
+
+ /**
+ * Threshold transaction amount.
+ */
+ struct TALER_Amount new_threshold;
+
+ /**
+ * Expected response code.
+ */
+ unsigned int expected_response;
+};
+
+
+/**
+ * Callback to analyze the /aml-decision/$OFFICER_PUB response, just used to check
+ * if the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param adr response details
+ */
+static void
+take_aml_decision_cb (
+ void *cls,
+ const struct TALER_EXCHANGE_AddAmlDecisionResponse *adr)
+{
+ struct AmlDecisionState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &adr->hr;
+
+ ds->dh = NULL;
+ if (ds->expected_response != hr->http_status)
+ {
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ ds->expected_response);
+ return;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+take_aml_decision_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AmlDecisionState *ds = cls;
+ struct GNUNET_TIME_Timestamp now;
+ const struct TALER_PaytoHashP *h_payto;
+ const struct TALER_AmlOfficerPrivateKeyP *officer_priv;
+ const struct TALER_TESTING_Command *ref;
+ json_t *kyc_requirements = NULL;
+ const char *exchange_url;
+
+ (void) cmd;
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
+ now = GNUNET_TIME_timestamp_get ();
+ ds->is = is;
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ ds->account_ref_cmd);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_h_payto (ref,
+ &h_payto))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ ds->officer_ref_cmd);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_officer_priv (ref,
+ &officer_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ds->h_payto = *h_payto;
+ if (NULL != ds->kyc_requirement)
+ {
+ kyc_requirements = json_array ();
+ GNUNET_assert (NULL != kyc_requirements);
+ GNUNET_assert (0 ==
+ json_array_append (kyc_requirements,
+ json_string (ds->kyc_requirement)));
+ }
+
+ ds->dh = TALER_EXCHANGE_add_aml_decision (
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
+ ds->justification,
+ now,
+ &ds->new_threshold,
+ h_payto,
+ ds->new_state,
+ kyc_requirements,
+ officer_priv,
+ &take_aml_decision_cb,
+ ds);
+ json_decref (kyc_requirements);
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "take_aml_decision" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct AmlDecisionState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+take_aml_decision_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AmlDecisionState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
+ TALER_EXCHANGE_add_aml_decision_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data of a "AML decision" CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+take_aml_decision_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AmlDecisionState *ws = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_h_payto (&ws->h_payto),
+ TALER_TESTING_make_trait_aml_justification (ws->justification),
+ TALER_TESTING_make_trait_aml_decision (&ws->new_state),
+ TALER_TESTING_make_trait_amount (&ws->new_threshold),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_take_aml_decision (
+ const char *label,
+ const char *ref_officer,
+ const char *ref_operation,
+ const char *new_threshold,
+ const char *justification,
+ enum TALER_AmlDecisionState new_state,
+ const char *kyc_requirement,
+ unsigned int expected_response)
+{
+ struct AmlDecisionState *ds;
+
+ ds = GNUNET_new (struct AmlDecisionState);
+ ds->officer_ref_cmd = ref_officer;
+ ds->account_ref_cmd = ref_operation;
+ ds->kyc_requirement = kyc_requirement;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (new_threshold,
+ &ds->new_threshold))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %s\n",
+ new_threshold,
+ label);
+ GNUNET_assert (0);
+ }
+ ds->new_state = new_state;
+ ds->justification = justification;
+ ds->expected_response = expected_response;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &take_aml_decision_run,
+ .cleanup = &take_aml_decision_cleanup,
+ .traits = &take_aml_decision_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_take_aml_decision.c */
diff --git a/src/testing/testing_api_cmd_transfer_get.c b/src/testing/testing_api_cmd_transfer_get.c
index 3ca319cb5..405c8b7f9 100644
--- a/src/testing/testing_api_cmd_transfer_get.c
+++ b/src/testing/testing_api_cmd_transfer_get.c
@@ -44,6 +44,11 @@ struct TrackTransferState
const char *expected_wire_fee;
/**
+ * Our command.
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
* Reference to any operation that can provide a WTID.
* Will be the WTID to track.
*/
@@ -79,11 +84,6 @@ struct TrackTransferState
*/
unsigned int expected_response_code;
- /**
- * Index to the WTID to pick, in case @a wtid_reference has
- * many on offer.
- */
- unsigned int index;
};
@@ -103,10 +103,8 @@ track_transfer_cleanup (void *cls,
if (NULL != tts->tth)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- tts->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (tts->is,
+ cmd->label);
TALER_EXCHANGE_transfers_get_cancel (tts->tth);
tts->tth = NULL;
}
@@ -120,182 +118,178 @@ track_transfer_cleanup (void *cls,
* wire fees and hashed wire details as well.
*
* @param cls closure.
- * @param hr HTTP response details
- * @param ta transfer data returned by the exchange
+ * @param tgr response details
*/
static void
track_transfer_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_EXCHANGE_TransferData *ta)
+ const struct TALER_EXCHANGE_TransfersGetResponse *tgr)
{
struct TrackTransferState *tts = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &tgr->hr;
struct TALER_TESTING_Interpreter *is = tts->is;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
struct TALER_Amount expected_amount;
tts->tth = NULL;
if (tts->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (is);
+ TALER_TESTING_unexpected_status (is,
+ hr->http_status,
+ tts->expected_response_code);
return;
}
switch (hr->http_status)
{
case MHD_HTTP_OK:
- if (NULL == tts->expected_total_amount)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (NULL == tts->expected_wire_fee)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_string_to_amount (tts->expected_total_amount,
- &expected_amount))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (0 != TALER_amount_cmp (&ta->total_amount,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Total amount mismatch to command %s - "
- "%s vs %s\n",
- cmd->label,
- TALER_amount_to_string (&ta->total_amount),
- TALER_amount_to_string (&expected_amount));
- json_dumpf (hr->reply,
- 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 (&ta->wire_fee,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee mismatch to command %s\n",
- cmd->label);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
+ const struct TALER_EXCHANGE_TransferData *ta
+ = &tgr->details.ok.td;
- /**
- * Optionally checking: (1) wire-details for this transfer
- * match the ones from a referenced "deposit" operation -
- * or any operation that could provide wire-details. (2)
- * Total amount for this transfer matches the one from any
- * referenced command that could provide one.
- */if (NULL != tts->wire_details_reference)
- {
- const struct TALER_TESTING_Command *wire_details_cmd;
- const json_t *wire_details;
- struct GNUNET_HashCode h_wire_details;
-
- wire_details_cmd
- = TALER_TESTING_interpreter_lookup_command (is,
- tts->wire_details_reference);
- if (NULL == wire_details_cmd)
+ if (NULL == tts->expected_total_amount)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
+ if (NULL == tts->expected_wire_fee)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
if (GNUNET_OK !=
- TALER_TESTING_get_trait_wire_details (wire_details_cmd,
- 0,
- &wire_details))
+ TALER_string_to_amount (tts->expected_total_amount,
+ &expected_amount))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_merchant_wire_signature_hash (wire_details,
- &h_wire_details));
- if (0 != GNUNET_memcmp (&h_wire_details,
- &ta->h_wire))
+ if (0 != TALER_amount_cmp (&ta->total_amount,
+ &expected_amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire hash missmath to command %s\n",
- cmd->label);
+ "Total amount mismatch to command %s - "
+ "%s vs %s\n",
+ tts->cmd->label,
+ TALER_amount_to_string (&ta->total_amount),
+ TALER_amount_to_string (&expected_amount));
json_dumpf (hr->reply,
stderr,
0);
+ fprintf (stderr, "\n");
TALER_TESTING_interpreter_fail (is);
return;
}
- }
- if (NULL != tts->total_amount_reference)
- {
- const struct TALER_TESTING_Command *total_amount_cmd;
- const struct TALER_Amount *total_amount_from_reference;
- total_amount_cmd
- = TALER_TESTING_interpreter_lookup_command (is,
- tts->total_amount_reference);
- if (NULL == total_amount_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
if (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (total_amount_cmd,
- 0,
- &total_amount_from_reference))
+ TALER_string_to_amount (tts->expected_wire_fee,
+ &expected_amount))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
- if (0 != TALER_amount_cmp (&ta->total_amount,
- total_amount_from_reference))
+
+ if (0 != TALER_amount_cmp (&ta->wire_fee,
+ &expected_amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Amount missmath to command %s\n",
- cmd->label);
+ "Wire fee mismatch to command %s\n",
+ tts->cmd->label);
json_dumpf (hr->reply,
stderr,
0);
TALER_TESTING_interpreter_fail (is);
return;
}
- }
- }
+
+ /**
+ * Optionally checking: (1) wire-details for this transfer
+ * match the ones from a referenced "deposit" operation -
+ * or any operation that could provide wire-details. (2)
+ * Total amount for this transfer matches the one from any
+ * referenced command that could provide one.
+ */
+ if (NULL != tts->wire_details_reference)
+ {
+ const struct TALER_TESTING_Command *wire_details_cmd;
+ const char *payto_uri;
+ struct TALER_PaytoHashP h_payto;
+
+ wire_details_cmd
+ = TALER_TESTING_interpreter_lookup_command (is,
+ tts->
+ wire_details_reference);
+ if (NULL == wire_details_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_payto_uri (wire_details_cmd,
+ &payto_uri))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_payto_hash (payto_uri,
+ &h_payto);
+ if (0 != GNUNET_memcmp (&h_payto,
+ &ta->h_payto))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire hash missmath to command %s\n",
+ tts->cmd->label);
+ json_dumpf (hr->reply,
+ stderr,
+ 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ if (NULL != tts->total_amount_reference)
+ {
+ const struct TALER_TESTING_Command *total_amount_cmd;
+ const struct TALER_Amount *total_amount_from_reference;
+
+ total_amount_cmd
+ = TALER_TESTING_interpreter_lookup_command (is,
+ tts->
+ total_amount_reference);
+ if (NULL == total_amount_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount (total_amount_cmd,
+ &total_amount_from_reference))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (0 != TALER_amount_cmp (&ta->total_amount,
+ total_amount_from_reference))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Amount mismatch in command %s\n",
+ tts->cmd->label);
+ json_dumpf (hr->reply,
+ stderr,
+ 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ break;
+ } /* case OK */
+ } /* switch on status */
TALER_TESTING_interpreter_next (is);
}
@@ -317,19 +311,20 @@ track_transfer_run (void *cls,
struct TALER_WireTransferIdentifierRawP wtid;
const struct TALER_WireTransferIdentifierRawP *wtid_ptr;
+ tts->cmd = cmd;
/* If no reference is given, we'll use a all-zeros
* WTID */
- memset (&wtid, 0, sizeof (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);
-
+ wtid_cmd = TALER_TESTING_interpreter_lookup_command (tts->is,
+ tts->wtid_reference);
if (NULL == wtid_cmd)
{
GNUNET_break (0);
@@ -337,8 +332,9 @@ track_transfer_run (void *cls,
return;
}
- if (GNUNET_OK != TALER_TESTING_get_trait_wtid
- (wtid_cmd, tts->index, &wtid_ptr))
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_wtid (wtid_cmd,
+ &wtid_ptr))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (tts->is);
@@ -346,41 +342,26 @@ track_transfer_run (void *cls,
}
GNUNET_assert (NULL != wtid_ptr);
}
- tts->tth = TALER_EXCHANGE_transfers_get (is->exchange,
- wtid_ptr,
- &track_transfer_cb,
- tts);
+ tts->tth = TALER_EXCHANGE_transfers_get (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ wtid_ptr,
+ &track_transfer_cb,
+ tts);
GNUNET_assert (NULL != tts->tth);
}
-/**
- * Make a "track transfer" CMD where no "expected"-arguments,
- * except the HTTP response code, are given. The best use case
- * is when what matters to check is the HTTP response code, e.g.
- * when a bogus WTID was passed.
- *
- * @param label the command label
- * @param wtid_reference reference to any command which can provide
- * a wtid. If NULL is given, then a all zeroed WTID is
- * used that will at 99.9999% probability NOT match any
- * existing WTID known to the exchange.
- * @param index index number of the WTID to track, in case there
- * are multiple on offer.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_track_transfer_empty (const char *label,
const char *wtid_reference,
- unsigned int index,
unsigned int expected_response_code)
{
struct TrackTransferState *tts;
tts = GNUNET_new (struct TrackTransferState);
tts->wtid_reference = wtid_reference;
- tts->index = index;
tts->expected_response_code = expected_response_code;
{
struct TALER_TESTING_Command cmd = {
@@ -395,25 +376,9 @@ TALER_TESTING_cmd_track_transfer_empty (const char *label,
}
-/**
- * Make a "track transfer" command, specifying which amount and
- * wire fee are expected.
- *
- * @param label the command label.
- * @param wtid_reference reference to any command which can provide
- * a wtid. Will be the one tracked.
- * @param index in case there are multiple WTID offered, this
- * parameter selects a particular one.
- * @param expected_response_code expected HTTP response code.
- * @param expected_total_amount how much money we expect being moved
- * with this wire-transfer.
- * @param expected_wire_fee expected wire fee.
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_track_transfer (const char *label,
const char *wtid_reference,
- unsigned int index,
unsigned int expected_response_code,
const char *expected_total_amount,
const char *expected_wire_fee)
@@ -422,7 +387,6 @@ TALER_TESTING_cmd_track_transfer (const char *label,
tts = GNUNET_new (struct TrackTransferState);
tts->wtid_reference = wtid_reference;
- tts->index = index;
tts->expected_response_code = expected_response_code;
tts->expected_total_amount = expected_total_amount;
tts->expected_wire_fee = expected_wire_fee;
diff --git a/src/testing/testing_api_cmd_twister_exec_client.c b/src/testing/testing_api_cmd_twister_exec_client.c
index b3903f29a..bf83c1f80 100644
--- a/src/testing/testing_api_cmd_twister_exec_client.c
+++ b/src/testing/testing_api_cmd_twister_exec_client.c
@@ -194,7 +194,7 @@ hack_response_code_cleanup
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
hack_response_code_traits (void *cls,
const void **ret,
const char *trait,
@@ -203,7 +203,7 @@ hack_response_code_traits (void *cls,
struct HackResponseCodeState *hrcs = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &hrcs->proc),
+ TALER_TESTING_make_trait_process (&hrcs->proc),
TALER_TESTING_trait_end ()
};
@@ -251,16 +251,6 @@ hack_response_code_run (void *cls,
}
-/**
- * Define a "hack response code" CMD. This causes the next
- * response code (from the service proxied by the twister) to
- * be substituted with @a http_status.
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @param http_status new response code to use
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_hack_response_code (const char *label,
const char *config_filename,
@@ -271,16 +261,17 @@ TALER_TESTING_cmd_hack_response_code (const char *label,
hrcs = GNUNET_new (struct HackResponseCodeState);
hrcs->http_status = http_status;
hrcs->config_filename = config_filename;
-
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &hack_response_code_run,
- .cleanup = &hack_response_code_cleanup,
- .traits = &hack_response_code_traits,
- .cls = hrcs
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &hack_response_code_run,
+ .cleanup = &hack_response_code_cleanup,
+ .traits = &hack_response_code_traits,
+ .cls = hrcs
+ };
+
+ return cmd;
+ }
}
@@ -320,7 +311,7 @@ delete_object_cleanup
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
delete_object_traits (void *cls,
const void **ret,
const char *trait,
@@ -329,7 +320,7 @@ delete_object_traits (void *cls,
struct DeleteObjectState *dos = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &dos->proc),
+ TALER_TESTING_make_trait_process (&dos->proc),
TALER_TESTING_trait_end ()
};
@@ -379,9 +370,8 @@ delete_object_run (void *cls,
* @param cmd the command being cleaned up.
*/
static void
-modify_object_cleanup
- (void *cls,
- const struct TALER_TESTING_Command *cmd)
+modify_object_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
{
struct ModifyObjectState *mos = cls;
@@ -407,7 +397,7 @@ modify_object_cleanup
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
modify_object_traits (void *cls,
const void **ret,
const char *trait,
@@ -416,7 +406,7 @@ modify_object_traits (void *cls,
struct ModifyObjectState *mos = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &mos->proc),
+ TALER_TESTING_make_trait_process (&mos->proc),
TALER_TESTING_trait_end ()
};
@@ -523,16 +513,6 @@ modify_header_dl_run (void *cls,
}
-/**
- * Create a "delete object" CMD. This command deletes
- * the JSON object pointed by @a path.
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @param path object-like path notation to point the object
- * to delete.
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_delete_object (const char *label,
const char *config_filename,
@@ -592,16 +572,15 @@ flip_object_cleanup
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
flip_object_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
-
struct FlipObjectState *fos = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &fos->proc),
+ TALER_TESTING_make_trait_process (&fos->proc),
TALER_TESTING_trait_end ()
};
@@ -674,15 +653,6 @@ flip_download_run (void *cls,
}
-/**
- * Define a "flip object" command, for objects to upload.
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @param path object-like path notation to point the object
- * to flip.
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_flip_upload (const char *label,
const char *config_filename,
@@ -693,28 +663,20 @@ TALER_TESTING_cmd_flip_upload (const char *label,
dos = GNUNET_new (struct FlipObjectState);
dos->path = path;
dos->config_filename = config_filename;
-
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &flip_upload_run,
- .cleanup = &flip_object_cleanup,
- .traits = &flip_object_traits,
- .cls = dos
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &flip_upload_run,
+ .cleanup = &flip_object_cleanup,
+ .traits = &flip_object_traits,
+ .cls = dos
+ };
+
+ return cmd;
+ }
}
-/**
- * Define a "flip object" command, for objects to download.
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @param path object-like path notation to point the object
- * to flip.
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_flip_download (const char *label,
const char *config_filename,
@@ -725,16 +687,17 @@ TALER_TESTING_cmd_flip_download (const char *label,
dos = GNUNET_new (struct FlipObjectState);
dos->path = path;
dos->config_filename = config_filename;
-
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &flip_download_run,
- .cleanup = &flip_object_cleanup,
- .traits = &flip_object_traits,
- .cls = dos
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &flip_download_run,
+ .cleanup = &flip_object_cleanup,
+ .traits = &flip_object_traits,
+ .cls = dos
+ };
+
+ return cmd;
+ }
}
@@ -773,7 +736,7 @@ malform_request_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
malform_request_traits (void *cls,
const void **ret,
const char *trait,
@@ -781,7 +744,7 @@ malform_request_traits (void *cls,
{
struct MalformRequestState *mrs = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &mrs->proc),
+ TALER_TESTING_make_trait_process (&mrs->proc),
TALER_TESTING_trait_end ()
};
@@ -831,9 +794,8 @@ malform_request_run (void *cls,
* @param cmd the command being cleaned up.
*/
static void
-malform_response_cleanup
- (void *cls,
- const struct TALER_TESTING_Command *cmd)
+malform_response_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
{
struct MalformResponseState *mrs = cls;
@@ -859,7 +821,7 @@ malform_response_cleanup
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
malform_response_traits (void *cls,
const void **ret,
const char *trait,
@@ -867,7 +829,7 @@ malform_response_traits (void *cls,
{
struct MalformResponseState *mrs = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &mrs->proc),
+ TALER_TESTING_make_trait_process (&mrs->proc),
TALER_TESTING_trait_end ()
};
@@ -909,14 +871,6 @@ malform_response_run (void *cls,
}
-/**
- * Create a "malform request" CMD. This command makes the
- * next request randomly malformed (by truncating it).
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_malform_request (const char *label,
const char *config_filename)
@@ -925,28 +879,20 @@ TALER_TESTING_cmd_malform_request (const char *label,
mrs = GNUNET_new (struct MalformRequestState);
mrs->config_filename = config_filename;
-
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &malform_request_run,
- .cleanup = &malform_request_cleanup,
- .traits = &malform_request_traits,
- .cls = mrs
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &malform_request_run,
+ .cleanup = &malform_request_cleanup,
+ .traits = &malform_request_traits,
+ .cls = mrs
+ };
+
+ return cmd;
+ }
}
-/**
- * Create a "malform response" CMD. This command makes
- * the next response randomly malformed (by truncating it).
- *
- * @param label command label
- * @param config_filename configuration filename.
- *
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_malform_response (const char *label,
const char *config_filename)
@@ -969,19 +915,6 @@ TALER_TESTING_cmd_malform_response (const char *label,
}
-/**
- * Create a "modify object" CMD. This command instructs
- * the twister to modify the next object that is downloaded
- * from the proxied service.
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @param path object-like path notation to point the object
- * to modify.
- * @param value value to put as the object's.
- *
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_modify_object_dl (const char *label,
const char *config_filename,
@@ -994,31 +927,20 @@ TALER_TESTING_cmd_modify_object_dl (const char *label,
mos->path = path;
mos->value = value;
mos->config_filename = config_filename;
-
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &modify_object_dl_run,
- .cleanup = &modify_object_cleanup,
- .traits = &modify_object_traits,
- .cls = mos
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &modify_object_dl_run,
+ .cleanup = &modify_object_cleanup,
+ .traits = &modify_object_traits,
+ .cls = mos
+ };
+
+ return cmd;
+ }
}
-/**
- * Create a "modify object" CMD. This command instructs
- * the twister to modify the next object that will be uploaded
- * to the proxied service.
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @param path object-like path notation pointing the object
- * to modify.
- * @param value value to put as the object's.
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_modify_object_ul (const char *label,
const char *config_filename,
@@ -1031,29 +953,20 @@ TALER_TESTING_cmd_modify_object_ul (const char *label,
mos->path = path;
mos->value = value;
mos->config_filename = config_filename;
-
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &modify_object_ul_run,
- .cleanup = &modify_object_cleanup,
- .traits = &modify_object_traits,
- .cls = mos
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &modify_object_ul_run,
+ .cleanup = &modify_object_cleanup,
+ .traits = &modify_object_traits,
+ .cls = mos
+ };
+
+ return cmd;
+ }
}
-/**
- * Create a "modify header" CMD. This command instructs
- * the twister to modify a header in the next HTTP response.
- *
- * @param label command label
- * @param config_filename configuration filename.
- * @param path identifies the location to modify
- * @param value value to set the header to.
- * @return the command
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_modify_header_dl (const char *label,
const char *config_filename,
@@ -1066,16 +979,17 @@ TALER_TESTING_cmd_modify_header_dl (const char *label,
mos->path = path;
mos->value = value;
mos->config_filename = config_filename;
-
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &modify_header_dl_run,
- .cleanup = &modify_object_cleanup,
- .traits = &modify_object_traits,
- .cls = mos
- };
-
- return cmd;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &modify_header_dl_run,
+ .cleanup = &modify_object_cleanup,
+ .traits = &modify_object_traits,
+ .cls = mos
+ };
+
+ return cmd;
+ }
}
diff --git a/src/testing/testing_api_cmd_wire.c b/src/testing/testing_api_cmd_wire.c
index 66d018c79..41ff7a978 100644
--- a/src/testing/testing_api_cmd_wire.c
+++ b/src/testing/testing_api_cmd_wire.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
+ Copyright (C) 2018, 2023 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
@@ -39,6 +39,11 @@ struct WireState
struct TALER_EXCHANGE_WireHandle *wh;
/**
+ * Our command.
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
* Which wire-method we expect is offered by the exchange.
*/
const char *expected_method;
@@ -72,19 +77,14 @@ struct WireState
* that the wire fee is acceptable too.
*
* @param cls closure.
- * @param hr HTTP response details
- * @param accounts_len length of the @a accounts array.
- * @param accounts list of wire accounts of the exchange,
- * NULL on error.
+ * @param wr response details
*/
static void
wire_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- unsigned int accounts_len,
- const struct TALER_EXCHANGE_WireAccount *accounts)
+ const struct TALER_EXCHANGE_WireResponse *wr)
{
struct WireState *ws = cls;
- struct TALER_TESTING_Command *cmd = &ws->is->commands[ws->is->ip];
+ const struct TALER_EXCHANGE_HttpResponse *hr = &wr->hr;
struct TALER_Amount expected_fee;
TALER_LOG_DEBUG ("Checking parsed /wire response\n");
@@ -100,41 +100,70 @@ wire_cb (void *cls,
if (MHD_HTTP_OK == hr->http_status)
{
+ unsigned int accounts_len
+ = wr->details.ok.accounts_len;
+ unsigned int fees_len
+ = wr->details.ok.fees_len;
+ const struct TALER_EXCHANGE_WireAccount *accounts
+ = wr->details.ok.accounts;
+ const struct TALER_EXCHANGE_WireFeesByMethod *fees
+ = wr->details.ok.fees;
+
for (unsigned int i = 0; i<accounts_len; i++)
{
char *method;
method = TALER_payto_get_method (accounts[i].payto_uri);
+ if (NULL == method)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return;
+ }
if (0 == strcmp (ws->expected_method,
method))
{
ws->method_found = GNUNET_OK;
- if (NULL != ws->expected_fee)
+ }
+ GNUNET_free (method);
+ }
+ if (NULL != ws->expected_fee)
+ {
+ bool fee_found = false;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (ws->expected_fee,
+ &expected_fee));
+ for (unsigned int i = 0; i<fees_len; i++)
+ {
+ if (0 != strcmp (fees[i].method,
+ ws->expected_method))
+ continue;
+ for (const struct TALER_EXCHANGE_WireAggregateFees *waf
+ = fees[i].fees_head;
+ NULL != waf;
+ waf = waf->next)
{
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (ws->expected_fee,
- &expected_fee));
- for (const struct TALER_EXCHANGE_WireAggregateFees *waf
- = accounts[i].fees;
- NULL != waf;
- waf = waf->next)
+ if (0 != TALER_amount_cmp (&waf->fees.wire,
+ &expected_fee))
{
- if (0 != TALER_amount_cmp (&waf->wire_fee,
- &expected_fee))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee mismatch to command %s\n",
- cmd->label);
- TALER_TESTING_interpreter_fail (ws->is);
- GNUNET_free (method);
- return;
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire fee mismatch to command %s\n",
+ ws->cmd->label);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return;
}
+ fee_found = true;
}
}
- TALER_LOG_DEBUG ("Freeing method '%s'\n",
- method);
- GNUNET_free (method);
+ if (! fee_found)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "/wire does not contain expected fee '%s'\n",
+ ws->expected_fee);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return;
+ }
}
if (GNUNET_OK != ws->method_found)
{
@@ -163,11 +192,14 @@ wire_run (void *cls,
{
struct WireState *ws = cls;
- (void) cmd;
+ ws->cmd = cmd;
ws->is = is;
- ws->wh = TALER_EXCHANGE_wire (is->exchange,
- &wire_cb,
- ws);
+ ws->wh = TALER_EXCHANGE_wire (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ &wire_cb,
+ ws);
}
@@ -186,10 +218,8 @@ wire_cleanup (void *cls,
if (NULL != ws->wh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ws->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (ws->is,
+ cmd->label);
TALER_EXCHANGE_wire_cancel (ws->wh);
ws->wh = NULL;
}
@@ -197,17 +227,6 @@ wire_cleanup (void *cls,
}
-/**
- * Create a "wire" command.
- *
- * @param label the command label.
- * @param expected_method which wire-transfer method is expected
- * to be offered by the exchange.
- * @param expected_fee the fee the exchange should charge.
- * @param expected_response_code the HTTP response the exchange
- * should return.
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_wire (const char *label,
const char *expected_method,
diff --git a/src/testing/testing_api_cmd_wire_add.c b/src/testing/testing_api_cmd_wire_add.c
index 8d8a3a4f6..d2a15894a 100644
--- a/src/testing/testing_api_cmd_wire_add.c
+++ b/src/testing/testing_api_cmd_wire_add.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020 Taler Systems SA
+ Copyright (C) 2020-2023 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
@@ -67,27 +67,21 @@ struct WireAddState
* if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
+ * @param wer response details
*/
static void
wire_add_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+ const struct TALER_EXCHANGE_ManagementWireEnableResponse *wer)
{
struct WireAddState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &wer->hr;
ds->dh = NULL;
if (ds->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ds->is);
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ ds->expected_response_code);
return;
}
TALER_TESTING_interpreter_next (ds->is);
@@ -109,12 +103,31 @@ wire_add_run (void *cls,
struct WireAddState *ds = cls;
struct TALER_MasterSignatureP master_sig1;
struct TALER_MasterSignatureP master_sig2;
- struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp now;
+ json_t *credit_rest;
+ json_t *debit_rest;
+ const char *exchange_url;
(void) cmd;
- now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
+ now = GNUNET_TIME_timestamp_get ();
ds->is = is;
+ debit_rest = json_array ();
+ credit_rest = json_array ();
if (ds->bad_sig)
{
memset (&master_sig1,
@@ -126,23 +139,50 @@ wire_add_run (void *cls,
}
else
{
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
TALER_exchange_offline_wire_add_sign (ds->payto_uri,
+ NULL,
+ debit_rest,
+ credit_rest,
now,
- &is->master_priv,
+ master_priv,
&master_sig1);
TALER_exchange_wire_signature_make (ds->payto_uri,
- &is->master_priv,
+ NULL,
+ debit_rest,
+ credit_rest,
+ master_priv,
&master_sig2);
}
ds->dh = TALER_EXCHANGE_management_enable_wire (
- is->ctx,
- is->exchange_url,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
ds->payto_uri,
+ NULL,
+ debit_rest,
+ credit_rest,
now,
&master_sig1,
&master_sig2,
+ NULL,
+ 0LL,
&wire_add_cb,
ds);
+ json_decref (debit_rest);
+ json_decref (credit_rest);
if (NULL == ds->dh)
{
GNUNET_break (0);
@@ -167,10 +207,8 @@ wire_add_cleanup (void *cls,
if (NULL != ds->dh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ds->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
TALER_EXCHANGE_management_enable_wire_cancel (ds->dh);
ds->dh = NULL;
}
@@ -178,26 +216,6 @@ wire_add_cleanup (void *cls,
}
-/**
- * Offer internal data from a "wire_add" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-wire_add_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- return GNUNET_NO;
-}
-
-
struct TALER_TESTING_Command
TALER_TESTING_cmd_wire_add (const char *label,
const char *payto_uri,
@@ -215,8 +233,7 @@ TALER_TESTING_cmd_wire_add (const char *label,
.cls = ds,
.label = label,
.run = &wire_add_run,
- .cleanup = &wire_add_cleanup,
- .traits = &wire_add_traits
+ .cleanup = &wire_add_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_wire_del.c b/src/testing/testing_api_cmd_wire_del.c
index 2a1c9e455..50ebfc7cb 100644
--- a/src/testing/testing_api_cmd_wire_del.c
+++ b/src/testing/testing_api_cmd_wire_del.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2020 Taler Systems SA
+ Copyright (C) 2020, 2023 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
@@ -67,27 +67,22 @@ struct WireDelState
* if the response code is acceptable.
*
* @param cls closure.
- * @param hr HTTP response details
+ * @param wdr response details
*/
static void
wire_del_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr)
+ const struct TALER_EXCHANGE_ManagementWireDisableResponse *wdr)
{
struct WireDelState *ds = cls;
+ const struct TALER_EXCHANGE_HttpResponse *hr = &wdr->hr;
ds->dh = NULL;
if (ds->expected_response_code != hr->http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- TALER_TESTING_interpreter_fail (ds->is);
+ TALER_TESTING_unexpected_status (ds->is,
+ hr->http_status,
+ ds->expected_response_code);
+
return;
}
TALER_TESTING_interpreter_next (ds->is);
@@ -108,11 +103,26 @@ wire_del_run (void *cls,
{
struct WireDelState *ds = cls;
struct TALER_MasterSignatureP master_sig;
- struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp now;
+ const char *exchange_url;
(void) cmd;
- now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
+ {
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url));
+ }
+ now = GNUNET_TIME_timestamp_get ();
ds->is = is;
if (ds->bad_sig)
{
@@ -122,14 +132,28 @@ wire_del_run (void *cls,
}
else
{
+ const struct TALER_TESTING_Command *exchange_cmd;
+ const struct TALER_MasterPrivateKeyP *master_priv;
+
+ exchange_cmd = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_master_priv (exchange_cmd,
+ &master_priv));
TALER_exchange_offline_wire_del_sign (ds->payto_uri,
now,
- &is->master_priv,
+ master_priv,
&master_sig);
}
ds->dh = TALER_EXCHANGE_management_disable_wire (
- is->ctx,
- is->exchange_url,
+ TALER_TESTING_interpreter_get_context (is),
+ exchange_url,
ds->payto_uri,
now,
&master_sig,
@@ -159,10 +183,8 @@ wire_del_cleanup (void *cls,
if (NULL != ds->dh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ds->is->ip,
- cmd->label);
+ TALER_TESTING_command_incomplete (ds->is,
+ cmd->label);
TALER_EXCHANGE_management_disable_wire_cancel (ds->dh);
ds->dh = NULL;
}
@@ -170,26 +192,6 @@ wire_del_cleanup (void *cls,
}
-/**
- * Offer internal data from a "wire_del" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-wire_del_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- return GNUNET_NO;
-}
-
-
struct TALER_TESTING_Command
TALER_TESTING_cmd_wire_del (const char *label,
const char *payto_uri,
@@ -207,8 +209,7 @@ TALER_TESTING_cmd_wire_del (const char *label,
.cls = ds,
.label = label,
.run = &wire_del_run,
- .cleanup = &wire_del_cleanup,
- .traits = &wire_del_traits
+ .cleanup = &wire_del_cleanup
};
return cmd;
diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c
index cfbdc177d..f8ff0205b 100644
--- a/src/testing/testing_api_cmd_withdraw.c
+++ b/src/testing/testing_api_cmd_withdraw.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2022 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
@@ -27,6 +27,7 @@
#include <microhttpd.h>
#include <gnunet/gnunet_curl_lib.h>
#include "taler_signatures.h"
+#include "taler_extensions.h"
#include "taler_testing_lib.h"
#include "backoff.h"
@@ -61,11 +62,16 @@ struct WithdrawState
/**
* Reference to a withdraw or reveal operation from which we should
- * re-use the private coin key, or NULL for regular withdrawal.
+ * reuse the private coin key, or NULL for regular withdrawal.
*/
const char *reuse_coin_key_ref;
/**
+ * Our command.
+ */
+ const struct TALER_TESTING_Command *cmd;
+
+ /**
* String describing the denomination value we should withdraw.
* A corresponding denomination key must exist in the exchange's
* offerings. Can be NULL if @e pk is set instead.
@@ -85,6 +91,37 @@ struct WithdrawState
char *exchange_url;
/**
+ * URI if the reserve we are withdrawing from.
+ */
+ char *reserve_payto_uri;
+
+ /**
+ * Private key of the reserve we are withdrawing from.
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Public key of the reserve we are withdrawing from.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Private key of the coin.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * Blinding key used during the operation.
+ */
+ union GNUNET_CRYPTO_BlindingSecretP bks;
+
+ /**
+ * Values contributed from the exchange during the
+ * withdraw protocol.
+ */
+ struct TALER_ExchangeWithdrawValues exchange_vals;
+
+ /**
* Interpreter state (during command).
*/
struct TALER_TESTING_Interpreter *is;
@@ -98,18 +135,30 @@ struct WithdrawState
/**
* Private key material of the coin, set by the interpreter.
*/
- struct TALER_PlanchetSecretsP ps;
+ struct TALER_PlanchetMasterSecretP ps;
+
+ /**
+ * An age > 0 signifies age restriction is required
+ */
+ uint8_t age;
+
+ /**
+ * If age > 0, put here the corresponding age commitment with its proof and
+ * its hash, respectively.
+ */
+ struct TALER_AgeCommitmentProof age_commitment_proof;
+ struct TALER_AgeCommitmentHash h_age_commitment;
/**
* Reserve history entry that corresponds to this operation.
* Will be of type #TALER_EXCHANGE_RTT_WITHDRAWAL.
*/
- struct TALER_EXCHANGE_ReserveHistory reserve_history;
+ struct TALER_EXCHANGE_ReserveHistoryEntry reserve_history;
/**
* Withdraw handle (while operation is running).
*/
- struct TALER_EXCHANGE_WithdrawHandle *wsh;
+ struct TALER_EXCHANGE_BatchWithdrawHandle *wsh;
/**
* Task scheduled to try later.
@@ -127,6 +176,18 @@ struct WithdrawState
struct GNUNET_TIME_Relative total_backoff;
/**
+ * Set to the KYC requirement payto hash *if* the exchange replied with a
+ * request for KYC.
+ */
+ struct TALER_PaytoHashP h_payto;
+
+ /**
+ * Set to the KYC requirement row *if* the exchange replied with
+ * a request for KYC.
+ */
+ uint64_t requirement_row;
+
+ /**
* Expected HTTP response code to the request.
*/
unsigned int expected_response_code;
@@ -164,8 +225,7 @@ do_retry (void *cls)
struct WithdrawState *ws = cls;
ws->retry_task = NULL;
- ws->is->commands[ws->is->ip].last_req_time
- = GNUNET_TIME_absolute_get ();
+ TALER_TESTING_touch_cmd (ws->is);
withdraw_run (ws,
NULL,
ws->is);
@@ -178,38 +238,36 @@ do_retry (void *cls)
* in the state.
*
* @param cls closure.
- * @param hr HTTP response details
- * @param sig signature over the coin, NULL on error.
+ * @param wr withdraw response details
*/
static void
reserve_withdraw_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_DenominationSignature *sig)
+ const struct TALER_EXCHANGE_BatchWithdrawResponse *wr)
{
struct WithdrawState *ws = cls;
struct TALER_TESTING_Interpreter *is = ws->is;
ws->wsh = NULL;
- if (ws->expected_response_code != hr->http_status)
+ if (ws->expected_response_code != wr->hr.http_status)
{
if (0 != ws->do_retry)
{
- if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != hr->ec)
+ if (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN != wr->hr.ec)
ws->do_retry--; /* we don't count reserve unknown as failures here */
- if ( (0 == hr->http_status) ||
- (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
- (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == hr->ec) ||
- (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN == hr->ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
+ if ( (0 == wr->hr.http_status) ||
+ (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec) ||
+ (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == wr->hr.ec) ||
+ (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN == wr->hr.ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == wr->hr.http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Retrying withdraw failed with %u/%d\n",
- hr->http_status,
- (int) hr->ec);
+ wr->hr.http_status,
+ (int) wr->hr.ec);
/* on DB conflicts, do not use backoff */
- if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
+ if (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec)
ws->backoff = GNUNET_TIME_UNIT_ZERO;
- else if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != hr->ec)
+ else if (TALER_EC_EXCHANGE_GENERIC_RESERVE_UNKNOWN != wr->hr.ec)
ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff);
else
ws->backoff = GNUNET_TIME_relative_max (UNKNOWN_MIN_BACKOFF,
@@ -218,64 +276,62 @@ reserve_withdraw_cb (void *cls,
UNKNOWN_MAX_BACKOFF);
ws->total_backoff = GNUNET_TIME_relative_add (ws->total_backoff,
ws->backoff);
- ws->is->commands[ws->is->ip].num_tries++;
+ TALER_TESTING_inc_tries (ws->is);
ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff,
&do_retry,
ws);
return;
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
- TALER_TESTING_interpreter_get_current_label (is),
- __FILE__,
- __LINE__);
- json_dumpf (hr->reply,
- stderr,
- 0);
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
+ TALER_TESTING_unexpected_status_with_body (is,
+ wr->hr.http_status,
+ ws->expected_response_code,
+ wr->hr.reply);
return;
}
- switch (hr->http_status)
+ switch (wr->hr.http_status)
{
case MHD_HTTP_OK:
- if (NULL == sig)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- ws->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (
- sig->rsa_signature);
+ GNUNET_assert (1 == wr->details.ok.num_coins);
+ TALER_denom_sig_copy (&ws->sig,
+ &wr->details.ok.coins[0].sig);
+ ws->coin_priv = wr->details.ok.coins[0].coin_priv;
+ ws->bks = wr->details.ok.coins[0].bks;
+ TALER_denom_ewv_copy (&ws->exchange_vals,
+ &wr->details.ok.coins[0].exchange_vals);
if (0 != ws->total_backoff.rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Total withdraw backoff for %s was %s\n",
- is->commands[is->ip].label,
+ ws->cmd->label,
GNUNET_STRINGS_relative_time_to_string (ws->total_backoff,
- GNUNET_YES));
+ true));
}
break;
case MHD_HTTP_FORBIDDEN:
/* nothing to check */
break;
+ case MHD_HTTP_NOT_FOUND:
+ /* nothing to check */
+ break;
case MHD_HTTP_CONFLICT:
/* nothing to check */
break;
case MHD_HTTP_GONE:
/* theoretically could check that the key was actually */
break;
- case MHD_HTTP_NOT_FOUND:
- /* nothing to check */
+ case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
+ /* KYC required */
+ ws->requirement_row =
+ wr->details.unavailable_for_legal_reasons.requirement_row;
+ ws->h_payto
+ = wr->details.unavailable_for_legal_reasons.h_payto;
break;
default:
/* Unsupported status code (by test harness) */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Withdraw test command does not support status code %u\n",
- hr->http_status);
+ wr->hr.http_status);
GNUNET_break (0);
break;
}
@@ -284,50 +340,6 @@ reserve_withdraw_cb (void *cls,
/**
- * Parser reference to a coin.
- *
- * @param coin_reference of format $LABEL['#' $INDEX]?
- * @param[out] cref where we return a copy of $LABEL
- * @param[out] idx where we set $INDEX
- * @return #GNUNET_SYSERR if $INDEX is present but not numeric
- */
-static int
-parse_coin_reference (const char *coin_reference,
- char **cref,
- unsigned int *idx)
-{
- const char *index;
-
- /* We allow command references of the form "$LABEL#$INDEX" or
- just "$LABEL", which implies the index is 0. Figure out
- which one it is. */
- index = strchr (coin_reference, '#');
- if (NULL == index)
- {
- *idx = 0;
- *cref = GNUNET_strdup (coin_reference);
- return GNUNET_OK;
- }
- *cref = GNUNET_strndup (coin_reference,
- index - coin_reference);
- if (1 != sscanf (index + 1,
- "%u",
- idx))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Numeric index (not `%s') required after `#' in command reference of command in %s:%u\n",
- index,
- __FILE__,
- __LINE__);
- GNUNET_free (*cref);
- *cref = NULL;
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
* Run the command.
*/
static void
@@ -340,7 +352,9 @@ withdraw_run (void *cls,
const struct TALER_TESTING_Command *create_reserve;
const struct TALER_EXCHANGE_DenomPublicKey *dpk;
- (void) cmd;
+ if (NULL != cmd)
+ ws->cmd = cmd;
+ ws->is = is;
create_reserve
= TALER_TESTING_interpreter_lookup_command (
is,
@@ -353,44 +367,53 @@ withdraw_run (void *cls,
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_priv (create_reserve,
- 0,
&rp))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
+ if (NULL == ws->exchange_url)
+ ws->exchange_url
+ = GNUNET_strdup (TALER_TESTING_get_exchange_url (is));
+ ws->reserve_priv = *rp;
+ GNUNET_CRYPTO_eddsa_key_get_public (&ws->reserve_priv.eddsa_priv,
+ &ws->reserve_pub.eddsa_pub);
+ ws->reserve_payto_uri
+ = TALER_reserve_make_payto (ws->exchange_url,
+ &ws->reserve_pub);
+
if (NULL == ws->reuse_coin_key_ref)
{
- TALER_planchet_setup_random (&ws->ps);
+ TALER_planchet_master_setup_random (&ws->ps);
}
else
{
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_PlanchetMasterSecretP *ps;
const struct TALER_TESTING_Command *cref;
char *cstr;
unsigned int index;
GNUNET_assert (GNUNET_OK ==
- parse_coin_reference (ws->reuse_coin_key_ref,
- &cstr,
- &index));
+ TALER_TESTING_parse_coin_reference (
+ ws->reuse_coin_key_ref,
+ &cstr,
+ &index));
cref = TALER_TESTING_interpreter_lookup_command (is,
cstr);
GNUNET_assert (NULL != cref);
GNUNET_free (cstr);
GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_coin_priv (cref,
- index,
- &coin_priv));
- TALER_planchet_setup_random (&ws->ps);
- ws->ps.coin_priv = *coin_priv;
+ TALER_TESTING_get_trait_planchet_secret (cref,
+ &ps));
+ ws->ps = *ps;
}
- ws->is = is;
+
if (NULL == ws->pk)
{
- dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange),
- &ws->amount);
+ dpk = TALER_TESTING_find_pk (TALER_TESTING_get_keys (is),
+ &ws->amount,
+ ws->age > 0);
if (NULL == dpk)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -408,18 +431,30 @@ withdraw_run (void *cls,
{
ws->amount = ws->pk->value;
}
+
ws->reserve_history.type = TALER_EXCHANGE_RTT_WITHDRAWAL;
GNUNET_assert (0 <=
TALER_amount_add (&ws->reserve_history.amount,
&ws->amount,
- &ws->pk->fee_withdraw));
- ws->reserve_history.details.withdraw.fee = ws->pk->fee_withdraw;
- ws->wsh = TALER_EXCHANGE_withdraw (is->exchange,
- ws->pk,
- rp,
- &ws->ps,
- &reserve_withdraw_cb,
- ws);
+ &ws->pk->fees.withdraw));
+ ws->reserve_history.details.withdraw.fee = ws->pk->fees.withdraw;
+ {
+ struct TALER_EXCHANGE_WithdrawCoinInput wci = {
+ .pk = ws->pk,
+ .ps = &ws->ps,
+ .ach = 0 < ws->age ? &ws->h_age_commitment : NULL
+ };
+
+ ws->wsh = TALER_EXCHANGE_batch_withdraw (
+ TALER_TESTING_interpreter_get_context (is),
+ TALER_TESTING_get_exchange_url (is),
+ TALER_TESTING_get_keys (is),
+ rp,
+ 1,
+ &wci,
+ &reserve_withdraw_cb,
+ ws);
+ }
if (NULL == ws->wsh)
{
GNUNET_break (0);
@@ -444,10 +479,9 @@ withdraw_cleanup (void *cls,
if (NULL != ws->wsh)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %s did not complete\n",
- cmd->label);
- TALER_EXCHANGE_withdraw_cancel (ws->wsh);
+ TALER_TESTING_command_incomplete (ws->is,
+ cmd->label);
+ TALER_EXCHANGE_batch_withdraw_cancel (ws->wsh);
ws->wsh = NULL;
}
if (NULL != ws->retry_task)
@@ -455,17 +489,17 @@ withdraw_cleanup (void *cls,
GNUNET_SCHEDULER_cancel (ws->retry_task);
ws->retry_task = NULL;
}
- if (NULL != ws->sig.rsa_signature)
- {
- GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature);
- ws->sig.rsa_signature = NULL;
- }
+ TALER_denom_sig_free (&ws->sig);
+ TALER_denom_ewv_free (&ws->exchange_vals);
if (NULL != ws->pk)
{
TALER_EXCHANGE_destroy_denomination_key (ws->pk);
ws->pk = NULL;
}
+ if (ws->age > 0)
+ TALER_age_commitment_proof_free (&ws->age_commitment_proof);
GNUNET_free (ws->exchange_url);
+ GNUNET_free (ws->reserve_payto_uri);
GNUNET_free (ws);
}
@@ -480,104 +514,83 @@ withdraw_cleanup (void *cls,
* @param index index number of the object to offer.
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
withdraw_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct WithdrawState *ws = cls;
- const struct TALER_TESTING_Command *reserve_cmd;
- const struct TALER_ReservePrivateKeyP *reserve_priv;
- const struct TALER_ReservePublicKeyP *reserve_pub;
-
- /* We offer the reserve key where these coins were withdrawn
- * from. */
- reserve_cmd = TALER_TESTING_interpreter_lookup_command (ws->is,
- ws->reserve_reference);
-
- if (NULL == reserve_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ws->is);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_priv (reserve_cmd,
- 0,
- &reserve_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ws->is);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (reserve_cmd,
- 0,
- &reserve_pub))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ws->is);
- return GNUNET_SYSERR;
- }
- if (NULL == ws->exchange_url)
- ws->exchange_url
- = GNUNET_strdup (TALER_EXCHANGE_get_base_url (ws->is->exchange));
- {
- struct TALER_TESTING_Trait traits[] = {
- /* history entry MUST be first due to response code logic below! */
- TALER_TESTING_make_trait_reserve_history (0,
- &ws->reserve_history),
- TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
- &ws->ps.coin_priv),
- TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
- &ws->ps.blinding_key),
- TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
- ws->pk),
- TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,
- &ws->sig),
- TALER_TESTING_make_trait_reserve_priv (0,
- reserve_priv),
- TALER_TESTING_make_trait_reserve_pub (0,
- reserve_pub),
- TALER_TESTING_make_trait_amount_obj (0,
- &ws->amount),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- ws->exchange_url),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait ((ws->expected_response_code == MHD_HTTP_OK)
- ? &traits[0] /* we have reserve history */
- : &traits[1],/* skip reserve history */
- ret,
- trait,
- index);
- }
+ struct TALER_TESTING_Trait traits[] = {
+ /* history entry MUST be first due to response code logic below! */
+ TALER_TESTING_make_trait_reserve_history (0,
+ &ws->reserve_history),
+ TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
+ &ws->coin_priv),
+ TALER_TESTING_make_trait_planchet_secret (&ws->ps),
+ TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
+ &ws->bks),
+ TALER_TESTING_make_trait_exchange_wd_value (0 /* only one coin */,
+ &ws->exchange_vals),
+ TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
+ ws->pk),
+ TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,
+ &ws->sig),
+ TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub),
+ TALER_TESTING_make_trait_amount (&ws->amount),
+ TALER_TESTING_make_trait_legi_requirement_row (&ws->requirement_row),
+ TALER_TESTING_make_trait_h_payto (&ws->h_payto),
+ TALER_TESTING_make_trait_payto_uri (ws->reserve_payto_uri),
+ TALER_TESTING_make_trait_exchange_url (ws->exchange_url),
+ TALER_TESTING_make_trait_age_commitment_proof (0,
+ 0 < ws->age
+ ? &ws->age_commitment_proof
+ : NULL),
+ TALER_TESTING_make_trait_h_age_commitment (0,
+ 0 < ws->age
+ ? &ws->h_age_commitment
+ : NULL),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait ((ws->expected_response_code == MHD_HTTP_OK)
+ ? &traits[0] /* we have reserve history */
+ : &traits[1], /* skip reserve history */
+ ret,
+ trait,
+ index);
}
-/**
- * Create a withdraw command, letting the caller specify
- * the desired amount as string.
- *
- * @param label command label.
- * @param reserve_reference command providing us with a reserve to withdraw from
- * @param amount how much we withdraw.
- * @param expected_response_code which HTTP response code
- * we expect from the exchange.
- * @return the withdraw command to be executed by the interpreter.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_amount (const char *label,
const char *reserve_reference,
const char *amount,
+ uint8_t age,
unsigned int expected_response_code)
{
struct WithdrawState *ws;
ws = GNUNET_new (struct WithdrawState);
+ ws->age = age;
+ if (0 < age)
+ {
+ struct GNUNET_HashCode seed;
+ struct TALER_AgeMask mask;
+
+ mask = TALER_extensions_get_age_restriction_mask ();
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &seed,
+ sizeof(seed));
+ TALER_age_restriction_commit (&mask,
+ age,
+ &seed,
+ &ws->age_commitment_proof);
+ TALER_age_commitment_hash (&ws->age_commitment_proof.commitment,
+ &ws->h_age_commitment);
+ }
+
ws->reserve_reference = reserve_reference;
if (GNUNET_OK !=
TALER_string_to_amount (amount,
@@ -604,26 +617,12 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
}
-/**
- * Create a withdraw command, letting the caller specify
- * the desired amount as string and also re-using an existing
- * coin private key in the process (violating the specification,
- * which will result in an error when spending the coin!).
- *
- * @param label command label.
- * @param reserve_reference command providing us with a reserve to withdraw from
- * @param amount how much we withdraw.
- * @param coin_ref reference to (withdraw/reveal) command of a coin
- * from which we should re-use the private key
- * @param expected_response_code which HTTP response code
- * we expect from the exchange.
- * @return the withdraw command to be executed by the interpreter.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_amount_reuse_key (
const char *label,
const char *reserve_reference,
const char *amount,
+ uint8_t age,
const char *coin_ref,
unsigned int expected_response_code)
{
@@ -632,6 +631,7 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
cmd = TALER_TESTING_cmd_withdraw_amount (label,
reserve_reference,
amount,
+ age,
expected_response_code);
{
struct WithdrawState *ws = cmd.cls;
@@ -642,18 +642,6 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
}
-/**
- * Create withdraw command, letting the caller specify the
- * amount by a denomination key.
- *
- * @param label command label.
- * @param reserve_reference reference to the reserve to withdraw
- * from; will provide reserve priv to sign the request.
- * @param dk denomination public key.
- * @param expected_response_code expected HTTP response code.
- *
- * @return the command.
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_denomination (
const char *label,
@@ -688,14 +676,6 @@ TALER_TESTING_cmd_withdraw_denomination (
}
-/**
- * Modify a withdraw command to enable retries when the
- * reserve is not yet full or we get other transient
- * errors from the exchange.
- *
- * @param cmd a withdraw command
- * @return the command with retries enabled
- */
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd)
{
diff --git a/src/testing/testing_api_helpers_auditor.c b/src/testing/testing_api_helpers_auditor.c
deleted file mode 100644
index b74258004..000000000
--- a/src/testing/testing_api_helpers_auditor.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_helpers_auditor.c
- * @brief helper functions
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-#include "taler_auditor_service.h"
-
-
-/**
- * Closure for #cleanup_auditor.
- */
-struct CleanupContext
-{
- /**
- * Where we find the state to clean up.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Next cleanup routine to call, NULL for none.
- */
- GNUNET_SCHEDULER_TaskCallback fcb;
-
- /**
- * Closure for @e fcb
- */
- void *fcb_cls;
-};
-
-
-/**
- * Function to clean up the auditor connection.
- *
- * @param cls a `struct CleanupContext`
- */
-static void
-cleanup_auditor (void *cls)
-{
- struct CleanupContext *cc = cls;
- struct TALER_TESTING_Interpreter *is = cc->is;
-
- TALER_AUDITOR_disconnect (is->auditor);
- is->auditor = NULL;
- if (NULL != cc->fcb)
- cc->fcb (cc->fcb_cls);
- GNUNET_free (cc);
-}
-
-
-/**
- * Closure for #auditor_main_wrapper()
- */
-struct MainWrapperContext
-{
- /**
- * Main function to launch.
- */
- TALER_TESTING_Main main_cb;
-
- /**
- * Closure for @e main_cb.
- */
- void *main_cb_cls;
-
- /**
- * Configuration we use.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Name of the configuration file.
- */
- const char *config_filename;
-
-};
-
-
-/**
- * Function called with information about the auditor.
- *
- * @param cls closure
- * @param hr http response details
- * @param vi basic information about the auditor
- * @param compat protocol compatibility information
- */
-static void
-auditor_version_cb (void *cls,
- const struct TALER_AUDITOR_HttpResponse *hr,
- const struct TALER_AUDITOR_VersionInformation *vi,
- enum TALER_AUDITOR_VersionCompatibility compat)
-{
- struct TALER_TESTING_Interpreter *is = cls;
-
- (void) hr;
- if (TALER_AUDITOR_VC_MATCH != compat)
- {
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- is->auditor_working = GNUNET_YES;
-}
-
-
-/**
- * Setup the @a is 'auditor' member before running the main test loop.
- *
- * @param cls must be a `struct MainWrapperContext *`
- * @param[in,out] is interpreter state to setup
- */
-static void
-auditor_main_wrapper (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct MainWrapperContext *mwc = cls;
- struct CleanupContext *cc;
- char *auditor_base_url;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (mwc->cfg,
- "auditor",
- "BASE_URL",
- &auditor_base_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "BASE_URL");
- return;
- }
-
- is->auditor = TALER_AUDITOR_connect (is->ctx,
- auditor_base_url,
- &auditor_version_cb,
- is);
- GNUNET_free (auditor_base_url);
-
- if (NULL == is->auditor)
- {
- GNUNET_break (0);
- return;
- }
-
- cc = GNUNET_new (struct CleanupContext);
- cc->is = is;
- cc->fcb = is->final_cleanup_cb;
- cc->fcb_cls = is->final_cleanup_cb_cls;
- is->final_cleanup_cb = cleanup_auditor;
- is->final_cleanup_cb_cls = cc;
- mwc->main_cb (mwc->main_cb_cls,
- is);
-}
-
-
-/**
- * Install signal handlers plus schedules the main wrapper
- * around the "run" method.
- *
- * @param cls our `struct MainWrapperContext`
- * @param cfg configuration we use
- * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
- * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
- * times.
- */
-static int
-setup_with_cfg (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct MainWrapperContext *mwc = cls;
- struct TALER_TESTING_SetupContext setup_ctx = {
- .config_filename = mwc->config_filename,
- .main_cb = &auditor_main_wrapper,
- .main_cb_cls = mwc
- };
-
- mwc->cfg = cfg;
- return TALER_TESTING_setup_with_auditor_and_exchange_cfg (&setup_ctx,
- cfg);
-}
-
-
-/**
- * Install signal handlers plus schedules the main wrapper
- * around the "run" method.
- *
- * @param main_cb the "run" method which contains all the
- * commands.
- * @param main_cb_cls a closure for "run", typically NULL.
- * @param config_filename configuration filename.
- * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
- * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
- * times.
- */
-int
-TALER_TESTING_auditor_setup (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const char *config_filename)
-{
- struct MainWrapperContext mwc = {
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls,
- .config_filename = config_filename
- };
-
- return GNUNET_CONFIGURATION_parse_and_run (config_filename,
- &setup_with_cfg,
- &mwc);
-}
-
-
-/* end of testing_auditor_api_helpers.c */
diff --git a/src/testing/testing_api_helpers_bank.c b/src/testing/testing_api_helpers_bank.c
deleted file mode 100644
index d7cce01bb..000000000
--- a/src/testing/testing_api_helpers_bank.c
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2021 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_helpers_bank.c
- * @brief convenience functions for bank tests.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_testing_lib.h"
-#include "taler_fakebank_lib.h"
-
-#define BANK_FAIL() \
- do {GNUNET_break (0); return NULL; } while (0)
-
-
-struct TALER_FAKEBANK_Handle *
-TALER_TESTING_run_fakebank (const char *bank_url,
- const char *currency)
-{
- const char *port;
- long pnum;
- struct TALER_FAKEBANK_Handle *fakebankd;
-
- port = strrchr (bank_url,
- (unsigned char) ':');
- if (NULL == port)
- pnum = 80;
- else
- pnum = strtol (port + 1, NULL, 10);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Starting Fakebank on port %u (%s)\n",
- (unsigned int) pnum,
- bank_url);
- fakebankd = TALER_FAKEBANK_start ((uint16_t) pnum,
- currency);
- if (NULL == fakebankd)
- {
- GNUNET_break (0);
- return NULL;
- }
- return fakebankd;
-}
-
-
-int
-TALER_TESTING_has_in_name (const char *prog,
- const char *marker)
-{
- size_t name_pos;
- size_t pos;
-
- if (! prog || ! marker)
- return GNUNET_NO;
-
- pos = 0;
- name_pos = 0;
- while (prog[pos])
- {
- if ('/' == prog[pos])
- name_pos = pos + 1;
- pos++;
- }
- if (name_pos == pos)
- return GNUNET_YES;
- return (NULL != strstr (prog + name_pos, marker));
-}
-
-
-struct TALER_TESTING_LibeufinServices
-TALER_TESTING_run_libeufin (const struct TALER_TESTING_BankConfiguration *bc)
-{
- struct GNUNET_OS_Process *nexus_proc;
- struct GNUNET_OS_Process *sandbox_proc;
- struct TALER_TESTING_LibeufinServices ret = { 0 };
- unsigned int iter;
- char *curl_check_cmd;
-
- nexus_proc = GNUNET_OS_start_process (
- GNUNET_OS_INHERIT_STD_ERR,
- NULL, NULL, NULL,
- "libeufin-nexus",
- "libeufin-nexus",
- "serve",
- "--db-name", "/tmp/nexus-exchange-test.sqlite3",
- NULL);
- if (NULL == nexus_proc)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "exec",
- "libeufin-nexus");
- return ret;
- }
- GNUNET_asprintf (&curl_check_cmd,
- "curl -s %s",
- bc->exchange_auth.wire_gateway_url);
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `nexus' to be ready (via %s)\n", curl_check_cmd);
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (
- stderr,
- "Failed to launch `nexus'\n");
- GNUNET_OS_process_kill (nexus_proc,
- SIGTERM);
- GNUNET_OS_process_wait (nexus_proc);
- GNUNET_OS_process_destroy (nexus_proc);
- GNUNET_free (curl_check_cmd);
- GNUNET_break (0);
- return ret;
- }
- fprintf (stderr, ".");
- sleep (1);
- iter++;
- }
- while (0 != system (curl_check_cmd));
-
- // start sandbox.
- GNUNET_free (curl_check_cmd);
- fprintf (stderr, "\n");
-
- sandbox_proc = GNUNET_OS_start_process (
- GNUNET_OS_INHERIT_STD_ERR,
- NULL, NULL, NULL,
- "libeufin-sandbox",
- "libeufin-sandbox",
- "serve",
- "--db-name", "/tmp/sandbox-exchange-test.sqlite3",
- NULL);
- if (NULL == sandbox_proc)
- {
- GNUNET_break (0);
- return ret;
- }
-
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `sandbox' to be ready.\n");
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (
- stderr,
- "Failed to launch `sandbox'\n");
- GNUNET_OS_process_kill (sandbox_proc,
- SIGTERM);
- GNUNET_OS_process_wait (sandbox_proc);
- GNUNET_OS_process_destroy (sandbox_proc);
- GNUNET_break (0);
- return ret;
- }
- fprintf (stderr, ".");
- sleep (1);
- iter++;
- }
- while (0 != system ("curl -s http://localhost:5000/"));
- fprintf (stderr, "\n");
-
- // Creates nexus user + bank loopback connection + Taler facade.
- if (0 != system ("taler-nexus-prepare"))
- {
- GNUNET_OS_process_kill (nexus_proc, SIGTERM);
- GNUNET_OS_process_wait (nexus_proc);
- GNUNET_OS_process_destroy (nexus_proc);
- GNUNET_OS_process_kill (sandbox_proc, SIGTERM);
- GNUNET_OS_process_wait (sandbox_proc);
- GNUNET_OS_process_destroy (sandbox_proc);
- TALER_LOG_ERROR ("Could not prepare nexus\n");
- GNUNET_break (0);
- return ret;
- }
- ret.nexus = nexus_proc;
- ret.sandbox = sandbox_proc;
- return ret;
-}
-
-
-struct GNUNET_OS_Process *
-TALER_TESTING_run_bank (const char *config_filename,
- const char *bank_url)
-{
- struct GNUNET_OS_Process *bank_proc;
- unsigned int iter;
- char *wget_cmd;
- char *database;
- struct GNUNET_CONFIGURATION_Handle *cfg;
-
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- config_filename))
- {
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- exit (77);
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "bank",
- "database",
- &database))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "bank",
- "database");
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- exit (77);
- }
- GNUNET_CONFIGURATION_destroy (cfg);
- bank_proc = GNUNET_OS_start_process (
- GNUNET_OS_INHERIT_STD_ERR,
- NULL, NULL, NULL,
- "taler-bank-manage-testing",
- "taler-bank-manage-testing",
- config_filename,
- database,
- "serve", NULL);
- GNUNET_free (database);
- if (NULL == bank_proc)
- {
- BANK_FAIL ();
- }
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 2 -T 1 %s -o /dev/null -O /dev/null",
- bank_url);
-
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `taler-bank-manage' to be ready (via %s)\n", wget_cmd);
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (
- stderr,
- "Failed to launch `taler-bank-manage' (or `wget')\n");
- GNUNET_OS_process_kill (bank_proc,
- SIGTERM);
- GNUNET_OS_process_wait (bank_proc);
- GNUNET_OS_process_destroy (bank_proc);
- GNUNET_free (wget_cmd);
- BANK_FAIL ();
- }
- fprintf (stderr, ".");
- sleep (1);
- iter++;
- }
- while (0 != system (wget_cmd));
- GNUNET_free (wget_cmd);
- fprintf (stderr, "\n");
-
- return bank_proc;
-
-}
-
-
-int
-TALER_TESTING_prepare_nexus (const char *config_filename,
- int reset_db,
- const char *config_section,
- struct TALER_TESTING_BankConfiguration *bc)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- unsigned long long port;
- char *database = NULL; // silence compiler
- char *exchange_payto_uri;
-
- GNUNET_assert (0 ==
- strncasecmp (config_section,
- "exchange-account-",
- strlen ("exchange-account-")));
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- config_filename))
- {
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- config_section,
- "PAYTO_URI",
- &exchange_payto_uri))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- config_section,
- "PAYTO_URI");
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "bank",
- "HTTP_PORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "bank",
- "HTTP_PORT");
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free (database);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- (uint16_t) port))
- {
- fprintf (stderr,
- "Required port %llu not available, skipping.\n",
- port);
- GNUNET_break (0);
- GNUNET_free (database);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
-
- /* DB preparation */
- if (GNUNET_YES == reset_db)
- {
- if (0 != system (
- "rm -f /tmp/nexus-exchange-test.sqlite3 && rm -f /tmp/sandbox-exchange-test.sqlite3"))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to invoke db-removal command.\n");
- GNUNET_free (database);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- }
-
- {
- char *csn;
-
- GNUNET_asprintf (&csn,
- "exchange-accountcredentials-%s",
- &config_section[strlen ("exchange-account-")]);
-
-
- if (GNUNET_OK !=
- TALER_BANK_auth_parse_cfg (cfg,
- csn,
- &bc->exchange_auth))
- {
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free (csn);
- return GNUNET_SYSERR;
- }
- GNUNET_free (csn);
- }
- GNUNET_CONFIGURATION_destroy (cfg);
- bc->exchange_payto = exchange_payto_uri;
- bc->user42_payto =
- "payto://iban/BIC/FR7630006000011234567890189?receiver-name=User42";
- bc->user43_payto =
- "payto://iban/BIC/GB33BUKB20201555555555?receiver-name=User43";
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Relying on nexus %s on port %u\n",
- bc->exchange_auth.wire_gateway_url,
- (unsigned int) port);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n",
- bc->exchange_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
- bc->user42_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
- bc->user43_payto);
- return GNUNET_OK;
-}
-
-
-int
-TALER_TESTING_prepare_bank (const char *config_filename,
- int reset_db,
- const char *config_section,
- struct TALER_TESTING_BankConfiguration *bc)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- unsigned long long port;
- struct GNUNET_OS_Process *dbreset_proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
- char *database;
- char *exchange_payto_uri;
-
- GNUNET_assert (0 ==
- strncasecmp (config_section,
- "exchange-account-",
- strlen ("exchange-account-")));
- cfg = GNUNET_CONFIGURATION_create ();
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- config_filename))
- {
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "bank",
- "DATABASE",
- &database))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "bank",
- "DATABASE");
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- config_section,
- "PAYTO_URI",
- &exchange_payto_uri))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- config_section,
- "PAYTO_URI");
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "bank",
- "HTTP_PORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "bank",
- "HTTP_PORT");
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free (database);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- (uint16_t) port))
- {
- fprintf (stderr,
- "Required port %llu not available, skipping.\n",
- port);
- GNUNET_break (0);
- GNUNET_free (database);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
-
- /* DB preparation */
- if (GNUNET_YES == reset_db)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Flushing bank database\n");
- if (NULL ==
- (dbreset_proc = GNUNET_OS_start_process (
- GNUNET_OS_INHERIT_STD_ERR,
- NULL, NULL, NULL,
- "taler-bank-manage",
- "taler-bank-manage",
- "-c", config_filename,
- "--with-db", database,
- "django",
- "flush",
- "--no-input", NULL)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to flush the bank db.\n");
- GNUNET_free (database);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (dbreset_proc,
- &type,
- &code))
- {
- GNUNET_OS_process_destroy (dbreset_proc);
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free (database);
- return GNUNET_SYSERR;
- }
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- fprintf (stderr,
- "Failed to setup database `%s'\n",
- database);
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free (database);
- return GNUNET_SYSERR;
- }
- GNUNET_free (database);
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected error running `taler-bank-manage django flush'!\n");
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_destroy (dbreset_proc);
- }
- {
- char *csn;
-
- GNUNET_asprintf (&csn,
- "exchange-accountcredentials-%s",
- &config_section[strlen ("exchange-account-")]);
-
- if (GNUNET_OK !=
- TALER_BANK_auth_parse_cfg (cfg,
- csn,
- &bc->exchange_auth))
- {
- GNUNET_break (0);
- GNUNET_free (csn);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- GNUNET_free (csn);
- }
- GNUNET_CONFIGURATION_destroy (cfg);
- bc->exchange_payto = exchange_payto_uri;
- bc->user42_payto = "payto://x-taler-bank/localhost/42";
- bc->user43_payto = "payto://x-taler-bank/localhost/43";
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Using pybank %s on port %u\n",
- bc->exchange_auth.wire_gateway_url,
- (unsigned int) port);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "exchange payto: %s\n",
- bc->exchange_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "user42_payto: %s\n",
- bc->user42_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "user43_payto: %s\n",
- bc->user43_payto);
- return GNUNET_OK;
-}
-
-
-int
-TALER_TESTING_prepare_fakebank (const char *config_filename,
- const char *config_section,
- struct TALER_TESTING_BankConfiguration *bc)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- unsigned long long fakebank_port;
- char *exchange_payto_uri;
-
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg,
- config_filename))
- return GNUNET_SYSERR;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "BANK",
- "HTTP_PORT",
- &fakebank_port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "BANK",
- "HTTP_PORT");
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- config_section,
- "PAYTO_URI",
- &exchange_payto_uri))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- config_section,
- "PAYTO_URI");
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- {
- char *exchange_xtalerbank_account;
-
- exchange_xtalerbank_account
- = TALER_xtalerbank_account_from_payto (exchange_payto_uri);
- if (NULL == exchange_xtalerbank_account)
- {
- GNUNET_break (0);
- GNUNET_free (exchange_payto_uri);
- return GNUNET_SYSERR;
- }
- GNUNET_asprintf (&bc->exchange_auth.wire_gateway_url,
- "http://localhost:%u/%s/",
- (unsigned int) fakebank_port,
- exchange_xtalerbank_account);
- GNUNET_free (exchange_xtalerbank_account);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Using fakebank %s on port %u\n",
- bc->exchange_auth.wire_gateway_url,
- (unsigned int) fakebank_port);
-
- GNUNET_CONFIGURATION_destroy (cfg);
- if (GNUNET_OK !=
- TALER_TESTING_url_port_free (bc->exchange_auth.wire_gateway_url))
- {
- GNUNET_free (bc->exchange_auth.wire_gateway_url);
- bc->exchange_auth.wire_gateway_url = NULL;
- GNUNET_free (exchange_payto_uri);
- return GNUNET_SYSERR;
- }
- /* Now we know it's the fake bank, for purpose of authentication, we
- * don't have any auth. */
- bc->exchange_auth.method = TALER_BANK_AUTH_NONE;
- bc->exchange_payto = exchange_payto_uri;
- bc->user42_payto = "payto://x-taler-bank/localhost/42";
- bc->user43_payto = "payto://x-taler-bank/localhost/43";
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n",
- bc->exchange_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
- bc->user42_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user43_payto: %s\n",
- bc->user43_payto);
- return GNUNET_OK;
-}
-
-
-json_t *
-TALER_TESTING_make_wire_details (const char *payto)
-{
- return GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("payto_uri",
- payto),
- GNUNET_JSON_pack_string ("salt",
- "test-salt (must be constant for aggregation tests)"));
-}
-
-
-/* end of testing_api_helpers_bank.c */
diff --git a/src/testing/testing_api_helpers_exchange.c b/src/testing/testing_api_helpers_exchange.c
deleted file mode 100644
index a6307ca4c..000000000
--- a/src/testing/testing_api_helpers_exchange.c
+++ /dev/null
@@ -1,948 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_helpers_exchange.c
- * @brief helper functions
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-void
-TALER_TESTING_cleanup_files (const char *config_name)
-{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_parse_and_run (config_name,
- &TALER_TESTING_cleanup_files_cfg,
- NULL))
- exit (77);
-}
-
-
-/**
- * Remove @a option directory from @a section in @a cfg.
- *
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-remove_dir (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *section,
- const char *option)
-{
- char *dir;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- section,
- option,
- &dir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- section,
- option);
- return GNUNET_SYSERR;
- }
- if (GNUNET_YES ==
- GNUNET_DISK_directory_test (dir,
- GNUNET_NO))
- GNUNET_break (GNUNET_OK ==
- GNUNET_DISK_directory_remove (dir));
- GNUNET_free (dir);
- return GNUNET_OK;
-}
-
-
-int
-TALER_TESTING_cleanup_files_cfg (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- char *dir;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "exchange-offline",
- "SECM_TOFU_FILE",
- &dir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-offline",
- "SECM_TOFU_FILE");
- return GNUNET_SYSERR;
- }
- if ( (0 != unlink (dir)) &&
- (ENOENT != errno) )
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "unlink",
- dir);
- GNUNET_free (dir);
- return GNUNET_SYSERR;
- }
- GNUNET_free (dir);
- if (GNUNET_OK !=
- remove_dir (cfg,
- "taler-exchange-secmod-eddsa",
- "KEY_DIR"))
- return GNUNET_SYSERR;
- if (GNUNET_OK !=
- remove_dir (cfg,
- "taler-exchange-secmod-rsa",
- "KEY_DIR"))
- return GNUNET_SYSERR;
- return GNUNET_OK;
-}
-
-
-int
-TALER_TESTING_run_auditor_exchange (const char *config_filename,
- const char *exchange_master_pub,
- const char *exchange_base_url,
- int do_remove)
-{
- struct GNUNET_OS_Process *proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
-
- TALER_LOG_DEBUG ("Add exchange (%s,%s) to the auditor\n",
- exchange_base_url,
- exchange_master_pub);
-
- proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-exchange",
- "taler-auditor-exchange",
- "-c", config_filename,
- "-u", exchange_base_url,
- "-m", exchange_master_pub,
- (GNUNET_YES == do_remove)
- ? "-r"
- : NULL,
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-auditor-exchange`, is your PATH correct?\n");
- return GNUNET_SYSERR;
- }
- GNUNET_assert (GNUNET_OK ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code));
- GNUNET_OS_process_destroy (proc);
- if ( (0 != code) ||
- (GNUNET_OS_PROCESS_EXITED != type) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "taler-auditor-exchange terminated with error (%d/%d)\n",
- (int) type,
- (int) code);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-int
-TALER_TESTING_exchange_db_reset (const char *config_filename)
-{
- struct GNUNET_OS_Process *proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
-
- proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-dbinit",
- "taler-exchange-dbinit",
- "-c", config_filename,
- "-r",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n");
- return GNUNET_NO;
- }
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code))
- {
- GNUNET_break (0);
- GNUNET_OS_process_destroy (proc);
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_destroy (proc);
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to setup (exchange) database, exit code %d\n",
- (int) code);
- return GNUNET_NO;
- }
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected error (%d/%d) running `taler-exchange-dbinit'!\n",
- (int) type,
- (int) code);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-int
-TALER_TESTING_auditor_db_reset (const char *config_filename)
-{
- struct GNUNET_OS_Process *proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
-
- proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-dbinit",
- "taler-auditor-dbinit",
- "-c", config_filename,
- "-R",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-auditor-dbinit`, is your PATH correct?\n");
- return GNUNET_NO;
- }
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code))
- {
- GNUNET_break (0);
- GNUNET_OS_process_destroy (proc);
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_destroy (proc);
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to setup (auditor) database, exit code %d\n",
- (int) code);
- return GNUNET_NO;
- }
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected error (%d/%d) running `taler-auditor-dbinit'!\n",
- (int) type,
- (int) code);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Type of closure for
- * #sign_keys_for_exchange.
- */
-struct SignInfo
-{
- /**
- * Members will be set to the exchange configuration.
- */
- struct TALER_TESTING_ExchangeConfiguration *ec;
-
- /**
- * Name of the configuration file to use.
- */
- const char *config_filename;
-
- /**
- * Did we reset the database?
- */
- int db_reset;
-};
-
-
-/**
- * Sign the keys for an exchange given configuration @a cfg.
- * The information to be signed must be in a file "auditor.in".
- *
- * @param[in,out] cls a `struct SignInfo` with further parameters
- * @param cfg configuration to use
- * @return #GNUNET_OK on success
- */
-static int
-sign_keys_for_exchange (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct SignInfo *si = cls;
- char *exchange_master_pub;
- int ret;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "BASE_URL",
- &si->ec->exchange_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "exchange",
- "BASE_URL");
- si->ec->exchange_url = NULL;
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- TALER_TESTING_url_port_free (si->ec->exchange_url))
- {
- GNUNET_free (si->ec->exchange_url);
- si->ec->exchange_url = NULL;
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "auditor",
- "BASE_URL",
- &si->ec->auditor_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "auditor",
- "BASE_URL");
- GNUNET_free (si->ec->exchange_url);
- si->ec->exchange_url = NULL;
- si->ec->auditor_url = NULL;
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_TESTING_url_port_free (si->ec->auditor_url))
- {
- ret = GNUNET_NO;
- goto fail;
- }
- 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");
- ret = GNUNET_SYSERR;
- goto fail;
- }
- if ( (GNUNET_OK !=
- TALER_TESTING_run_auditor_exchange (si->config_filename,
- exchange_master_pub,
- si->ec->exchange_url,
- GNUNET_NO)) &&
- (GNUNET_YES == si->db_reset) )
- {
- ret = GNUNET_NO;
- goto fail;
- }
- GNUNET_free (exchange_master_pub);
- return GNUNET_OK;
-fail:
- GNUNET_free (si->ec->exchange_url);
- GNUNET_free (si->ec->auditor_url);
- si->ec->exchange_url = NULL;
- si->ec->auditor_url = NULL;
- return ret;
-}
-
-
-/**
- * Prepare launching an exchange. Checks that the configured
- * port is available, runs taler-exchange-dbinit. Does NOT
- * launch the exchange process itself.
- *
- * @param config_filename configuration file to use
- * @param reset_db should we reset the database?
- * @param[out] ec will be set to the exchange configuration data
- * @return #GNUNET_OK on success, #GNUNET_NO if test should be
- * skipped, #GNUNET_SYSERR on test failure
- */
-int
-TALER_TESTING_prepare_exchange (const char *config_filename,
- int reset_db,
- struct TALER_TESTING_ExchangeConfiguration *ec)
-{
- struct SignInfo si = {
- .config_filename = config_filename,
- .ec = ec,
- .db_reset = reset_db
- };
-
- if (GNUNET_YES == reset_db)
- {
- if (GNUNET_OK !=
- TALER_TESTING_exchange_db_reset (config_filename))
- return GNUNET_NO;
- if (GNUNET_OK !=
- TALER_TESTING_auditor_db_reset (config_filename))
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_parse_and_run (config_filename,
- &sign_keys_for_exchange,
- &si))
- return GNUNET_NO;
- return GNUNET_OK;
-}
-
-
-/**
- * Find denomination key matching the given amount.
- *
- * @param keys array of keys to search
- * @param amount coin value to look for
- * @return NULL if no matching key was found
- */
-const struct TALER_EXCHANGE_DenomPublicKey *
-TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
- const struct TALER_Amount *amount)
-{
- struct GNUNET_TIME_Absolute now;
- struct TALER_EXCHANGE_DenomPublicKey *pk;
- char *str;
-
- now = GNUNET_TIME_absolute_get ();
- for (unsigned int i = 0; i<keys->num_denom_keys; i++)
- {
- pk = &keys->denom_keys[i];
- if ( (0 == TALER_amount_cmp (amount,
- &pk->value)) &&
- (now.abs_value_us >= pk->valid_from.abs_value_us) &&
- (now.abs_value_us <
- pk->withdraw_valid_until.abs_value_us) )
- return pk;
- }
- /* do 2nd pass to check if expiration times are to blame for
- * failure */
- str = TALER_amount_to_string (amount);
- for (unsigned int i = 0; i<keys->num_denom_keys; i++)
- {
- pk = &keys->denom_keys[i];
- if ( (0 == TALER_amount_cmp (amount,
- &pk->value)) &&
- ( (now.abs_value_us < pk->valid_from.abs_value_us) ||
- (now.abs_value_us >
- pk->withdraw_valid_until.abs_value_us) ) )
- {
- GNUNET_log
- (GNUNET_ERROR_TYPE_WARNING,
- "Have denomination key for `%s', but with wrong"
- " expiration range %llu vs [%llu,%llu)\n",
- str,
- (unsigned long long) now.abs_value_us,
- (unsigned long long) pk->valid_from.abs_value_us,
- (unsigned long long)
- pk->withdraw_valid_until.abs_value_us);
- GNUNET_free (str);
- return NULL;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "No denomination key for amount %s found\n",
- str);
- GNUNET_free (str);
- return NULL;
-}
-
-
-int
-TALER_TESTING_wait_exchange_ready (const char *base_url)
-{
- char *wget_cmd;
- unsigned int iter;
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 1 -T 1 %sseed -o /dev/null -O /dev/null",
- base_url); // make sure ends with '/'
- /* give child time to start and bind against the socket */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Waiting for `taler-exchange-httpd` service to be ready (check with: %s)\n",
- wget_cmd);
- iter = 0;
- do
- {
- if (10 == iter)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to launch `taler-exchange-httpd` service (or `wget')\n");
- GNUNET_free (wget_cmd);
- return 77;
- }
- sleep (1);
- iter++;
- }
- while (0 != system (wget_cmd));
- GNUNET_free (wget_cmd);
- return 0;
-}
-
-
-int
-TALER_TESTING_wait_httpd_ready (const char *base_url)
-{
- char *wget_cmd;
- unsigned int iter;
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null",
- base_url); // make sure ends with '/'
- /* give child time to start and bind against the socket */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Waiting for HTTP service to be ready (check with: %s)\n",
- wget_cmd);
- iter = 0;
- do
- {
- if (10 == iter)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to launch HTTP service (or `wget')\n");
- GNUNET_free (wget_cmd);
- return 77;
- }
- sleep (1);
- iter++;
- }
- while (0 != system (wget_cmd));
- GNUNET_free (wget_cmd);
- return 0;
-}
-
-
-/**
- * Wait for the auditor to have started. Waits for at
- * most 10s, after that returns 77 to indicate an error.
- *
- * @param base_url what URL should we expect the auditor
- * to be running at
- * @return 0 on success
- */
-int
-TALER_TESTING_wait_auditor_ready (const char *base_url)
-{
- char *wget_cmd;
- unsigned int iter;
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 1 -T 1 %sversion -o /dev/null -O /dev/null",
- base_url); // make sure ends with '/'
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `taler-auditor-httpd' to be ready at %s\n",
- base_url);
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (stderr,
- "Failed to launch `taler-auditor-httpd' (or `wget')\n");
- GNUNET_free (wget_cmd);
- return 77;
- }
- fprintf (stderr, ".\n");
- sleep (1);
- iter++;
- }
- while (0 != system (wget_cmd));
- GNUNET_free (wget_cmd);
- return 0;
-}
-
-
-int
-TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const char *config_file)
-{
- struct TALER_TESTING_SetupContext setup_ctx = {
- .config_filename = config_file,
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls
- };
- int result;
-
- result =
- GNUNET_CONFIGURATION_parse_and_run (config_file,
- &TALER_TESTING_setup_with_exchange_cfg,
- &setup_ctx);
- if (GNUNET_OK != result)
- return result;
- return GNUNET_OK;
-}
-
-
-/**
- * Stop taler-exchange-crypto helpers.
- *
- * @param[in] helpers the process handles.
- */
-static void
-stop_helpers (struct GNUNET_OS_Process *helpers[2])
-{
- for (unsigned int i = 0; i<2; i++)
- {
- if (NULL == helpers[i])
- continue;
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (helpers[i],
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (helpers[i]));
- GNUNET_OS_process_destroy (helpers[i]);
- }
-}
-
-
-/**
- * Start taler-exchange-crypto helpers.
- *
- * @param config_filename configuration file to use
- * @param[out] helpers where to store the process handles.
- */
-static int
-start_helpers (const char *config_filename,
- struct GNUNET_OS_Process *helpers[2])
-{
- char *dir;
- const struct GNUNET_OS_ProjectData *pd;
-
- pd = GNUNET_OS_project_data_get ();
- GNUNET_OS_init (TALER_project_data_default ());
- dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
- GNUNET_OS_init (pd);
- if (NULL == dir)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- {
- char *fn;
-
- GNUNET_asprintf (&fn,
- "%s/%s",
- dir,
- "taler-exchange-secmod-eddsa");
- helpers[0] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- fn,
- "taler-exchange-secmod-eddsa",
- "-c", config_filename,
- "-L", "INFO",
- NULL);
- GNUNET_free (fn);
- }
- {
- char *fn;
-
- GNUNET_asprintf (&fn,
- "%s/%s",
- dir,
- "taler-exchange-secmod-rsa");
- helpers[1] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- fn,
- "taler-exchange-secmod-rsa",
- "-c", config_filename,
- "-L", "INFO",
- NULL);
- GNUNET_free (fn);
- }
- GNUNET_free (dir);
- if ( (NULL == helpers[0]) ||
- (NULL == helpers[1]) )
- {
- stop_helpers (helpers);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-int
-TALER_TESTING_setup_with_exchange_cfg (
- void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- const struct TALER_TESTING_SetupContext *setup_ctx = cls;
- struct GNUNET_OS_Process *exchanged;
- struct GNUNET_OS_Process *helpers[2];
- unsigned long long port;
- char *serve;
- char *base_url;
- int result;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "SERVE",
- &serve))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "SERVE");
- return GNUNET_NO;
- }
-
- if (0 == strcmp ("tcp", serve))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "exchange",
- "PORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "PORT");
- GNUNET_free (serve);
- return GNUNET_NO;
- }
-
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- (uint16_t) port))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Required port %llu not available, skipping.\n",
- port);
- GNUNET_free (serve);
- return GNUNET_NO;
- }
- }
- GNUNET_free (serve);
- if (GNUNET_OK !=
- start_helpers (setup_ctx->config_filename,
- helpers))
- {
- GNUNET_break (0);
- return 77;
- }
- exchanged = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-httpd",
- "taler-exchange-httpd",
- "-a", /* some tests may need timetravel */
- "-c", setup_ctx->config_filename,
- NULL);
- if (NULL == exchanged)
- {
- GNUNET_break (0);
- stop_helpers (helpers);
- return 77;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "BASE_URL",
- &base_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "BASE_URL");
- stop_helpers (helpers);
- return GNUNET_NO;
- }
-
- if (0 != TALER_TESTING_wait_exchange_ready (base_url))
- {
- GNUNET_free (base_url);
- stop_helpers (helpers);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (exchanged,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (exchanged));
- GNUNET_OS_process_destroy (exchanged);
- return 77;
- }
- GNUNET_free (base_url);
-
- /* NOTE: this call blocks. */
- result = TALER_TESTING_setup (setup_ctx->main_cb,
- setup_ctx->main_cb_cls,
- cfg,
- exchanged,
- GNUNET_YES);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (exchanged,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (exchanged));
- GNUNET_OS_process_destroy (exchanged);
- stop_helpers (helpers);
- return result;
-}
-
-
-int
-TALER_TESTING_setup_with_auditor_and_exchange_cfg (
- void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- const struct TALER_TESTING_SetupContext *setup_ctx = cls;
- struct GNUNET_OS_Process *auditord;
- unsigned long long port;
- char *serve;
- char *base_url;
- int result;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "auditor",
- "SERVE",
- &serve))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "SERVE");
- return GNUNET_NO;
- }
-
- if (0 == strcmp ("tcp", serve))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "auditor",
- "PORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "PORT");
- GNUNET_free (serve);
- return GNUNET_NO;
- }
-
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- (uint16_t) port))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Required port %llu not available, skipping.\n",
- port);
- GNUNET_free (serve);
- return GNUNET_NO;
- }
- }
- GNUNET_free (serve);
- auditord = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-httpd",
- "taler-auditor-httpd",
- "-c", setup_ctx->config_filename,
- NULL);
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "auditor",
- "BASE_URL",
- &base_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "BASE_URL");
- return GNUNET_NO;
- }
-
- if (0 != TALER_TESTING_wait_auditor_ready (base_url))
- {
- GNUNET_free (base_url);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (auditord,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (auditord));
- GNUNET_OS_process_destroy (auditord);
- return 77;
- }
- GNUNET_free (base_url);
-
- /* NOTE: this call blocks. */
- result = TALER_TESTING_setup_with_exchange_cfg ((void *) setup_ctx,
- cfg);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (auditord,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (auditord));
- GNUNET_OS_process_destroy (auditord);
- return result;
-}
-
-
-int
-TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const char *config_file)
-{
- struct TALER_TESTING_SetupContext setup_ctx = {
- .config_filename = config_file,
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls
- };
-
- return GNUNET_CONFIGURATION_parse_and_run (
- config_file,
- &TALER_TESTING_setup_with_auditor_and_exchange_cfg,
- &setup_ctx);
-}
-
-
-int
-TALER_TESTING_url_port_free (const char *url)
-{
- const char *port;
- long pnum;
-
- port = strrchr (url,
- (unsigned char) ':');
- if (NULL == port)
- pnum = 80;
- else
- pnum = strtol (port + 1, NULL, 10);
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- pnum))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Port %u not available.\n",
- (unsigned int) pnum);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/* end of testing_api_helpers_exchange.c */
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c
index 9e989ca36..0f242f7f1 100644
--- a/src/testing/testing_api_loop.c
+++ b/src/testing/testing_api_loop.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
+ Copyright (C) 2018-2023 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
@@ -26,23 +26,67 @@
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
+#include "taler_extensions.h"
#include "taler_signatures.h"
#include "taler_testing_lib.h"
-#include "taler_fakebank_lib.h"
-/**
- * Pipe used to communicate child death via signal.
- * Must be global, as used in signal handler!
- */
-static struct GNUNET_DISK_PipeHandle *sigpipe;
/**
- * Lookup command by label.
- *
- * @param is interpreter state to search
- * @param label label to look for
- * @return NULL if command was not found
+ * The interpreter and its state
*/
+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;
+
+ /**
+ * Handle for the child management.
+ */
+ struct GNUNET_ChildWaitHandle *cwh;
+
+ /**
+ * Main execution context for the main loop.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+ /**
+ * Context for running the CURL event loop.
+ */
+ struct GNUNET_CURL_RescheduleContext *rc;
+
+ /**
+ * Hash map mapping variable names to commands.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *vars;
+
+ /**
+ * Task run on timeout.
+ */
+ struct GNUNET_SCHEDULER_Task *timeout_task;
+
+ /**
+ * Instruction pointer. Tells #interpreter_run() which instruction to run
+ * next. Need (signed) int because it gets -1 when rewinding the
+ * interpreter to the first CMD.
+ */
+ int ip;
+
+ /**
+ * Result of the testcases, #GNUNET_OK on success
+ */
+ enum GNUNET_GenericReturnValue result;
+
+};
+
+
const struct TALER_TESTING_Command *
TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
const char *label)
@@ -66,7 +110,6 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
if (TALER_TESTING_cmd_is_batch (cmd))
{
-#define BATCH_INDEX 1
struct TALER_TESTING_Command *batch;
struct TALER_TESTING_Command *current;
struct TALER_TESTING_Command *icmd;
@@ -74,9 +117,8 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
current = TALER_TESTING_cmd_batch_get_current (cmd);
GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_cmd (cmd,
- BATCH_INDEX,
- &batch));
+ TALER_TESTING_get_trait_batch_cmds (cmd,
+ &batch));
/* We must do the loop forward, but we can find the last match */
match = NULL;
for (unsigned int j = 0;
@@ -98,62 +140,48 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
"Command not found: %s\n",
label);
return NULL;
+}
+
+const struct TALER_TESTING_Command *
+TALER_TESTING_interpreter_get_command (struct TALER_TESTING_Interpreter *is,
+ const char *name)
+{
+ const struct TALER_TESTING_Command *cmd;
+ struct GNUNET_HashCode h_name;
+
+ GNUNET_CRYPTO_hash (name,
+ strlen (name),
+ &h_name);
+ cmd = GNUNET_CONTAINER_multihashmap_get (is->vars,
+ &h_name);
+ if (NULL == cmd)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Command not found by name: %s\n",
+ name);
+ return cmd;
}
-/**
- * Obtain main execution context for the main loop.
- */
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;
}
-struct TALER_FAKEBANK_Handle *
-TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is)
+void
+TALER_TESTING_touch_cmd (struct TALER_TESTING_Interpreter *is)
{
- return is->fakebank;
+ is->commands[is->ip].last_req_time
+ = GNUNET_TIME_absolute_get ();
}
-/**
- * Run tests starting the "fakebank" first. The "fakebank"
- * is a C minimalist version of the human-oriented Python bank,
- * which is also part of the Taler project.
- *
- * @param is pointer to the interpreter state
- * @param commands the list of commands to execute
- * @param bank_url the url the fakebank is supposed to run on
- */
void
-TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is,
- struct TALER_TESTING_Command *commands,
- const char *bank_url)
+TALER_TESTING_inc_tries (struct TALER_TESTING_Interpreter *is)
{
- char *currency;
-
- if (GNUNET_OK !=
- TALER_config_get_currency (is->cfg,
- &currency))
- {
- is->result = GNUNET_SYSERR;
- return;
- }
- is->fakebank = TALER_TESTING_run_fakebank (bank_url,
- currency);
- GNUNET_free (currency);
- if (NULL == is->fakebank)
- {
- GNUNET_break (0);
- is->result = GNUNET_SYSERR;
- return;
- }
- TALER_TESTING_run (is,
- commands);
+ is->commands[is->ip].num_tries++;
}
@@ -166,9 +194,6 @@ static void
interpreter_run (void *cls);
-/**
- * Current command is done, run the next one.
- */
void
TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
{
@@ -180,7 +205,13 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
return; /* ignore, we already failed! */
if (TALER_TESTING_cmd_is_batch (cmd))
{
- TALER_TESTING_cmd_batch_next (is);
+ if (TALER_TESTING_cmd_batch_next (is,
+ cmd->cls))
+ {
+ /* batch is done */
+ cmd->finish_time = GNUNET_TIME_absolute_get ();
+ is->ip++;
+ }
}
else
{
@@ -194,7 +225,7 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
"Interpreter executed 1000 instructions in %s\n",
GNUNET_STRINGS_relative_time_to_string (
GNUNET_TIME_absolute_get_duration (last_report),
- GNUNET_YES));
+ true));
last_report = GNUNET_TIME_absolute_get ();
}
ipc++;
@@ -203,11 +234,6 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
}
-/**
- * Current command failed, clean up and fail the test case.
- *
- * @param is interpreter of the test
- */
void
TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
{
@@ -228,27 +254,9 @@ TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
}
-/**
- * Create command array terminator.
- *
- * @return a end-command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_end (void)
-{
- static struct TALER_TESTING_Command cmd;
- cmd.label = NULL;
-
- return cmd;
-}
-
-
-/**
- * Obtain current label.
- */
const char *
-TALER_TESTING_interpreter_get_current_label (struct
- TALER_TESTING_Interpreter *is)
+TALER_TESTING_interpreter_get_current_label (
+ struct TALER_TESTING_Interpreter *is)
{
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
@@ -256,11 +264,6 @@ TALER_TESTING_interpreter_get_current_label (struct
}
-/**
- * Run the main interpreter loop that performs exchange operations.
- *
- * @param cls contains the `struct TALER_TESTING_Interpreter`
- */
static void
interpreter_run (void *cls)
{
@@ -268,7 +271,6 @@ interpreter_run (void *cls)
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
is->task = NULL;
-
if (NULL == cmd->label)
{
@@ -286,6 +288,19 @@ interpreter_run (void *cls)
= cmd->last_req_time
= GNUNET_TIME_absolute_get ();
cmd->num_tries = 1;
+ if (NULL != cmd->name)
+ {
+ struct GNUNET_HashCode h_name;
+
+ GNUNET_CRYPTO_hash (cmd->name,
+ strlen (cmd->name),
+ &h_name);
+ (void) GNUNET_CONTAINER_multihashmap_put (
+ is->vars,
+ &h_name,
+ cmd,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+ }
cmd->run (cmd->cls,
cmd,
is);
@@ -308,23 +323,15 @@ do_shutdown (void *cls)
label = is->commands[is->ip].label;
if (NULL == label)
label = "END";
-
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Executing shutdown at `%s'\n",
label);
-
for (unsigned int j = 0;
NULL != (cmd = &is->commands[j])->label;
j++)
- cmd->cleanup (cmd->cls,
- cmd);
-
- if (NULL != is->exchange)
- {
- TALER_LOG_DEBUG ("Disconnecting the exchange\n");
- TALER_EXCHANGE_disconnect (is->exchange);
- is->exchange = NULL;
- }
+ if (NULL != cmd->cleanup)
+ cmd->cleanup (cmd->cls,
+ cmd);
if (NULL != is->task)
{
GNUNET_SCHEDULER_cancel (is->task);
@@ -340,20 +347,20 @@ do_shutdown (void *cls)
GNUNET_CURL_gnunet_rc_destroy (is->rc);
is->rc = NULL;
}
+ if (NULL != is->vars)
+ {
+ GNUNET_CONTAINER_multihashmap_destroy (is->vars);
+ is->vars = NULL;
+ }
if (NULL != is->timeout_task)
{
GNUNET_SCHEDULER_cancel (is->timeout_task);
is->timeout_task = NULL;
}
- if (NULL != is->child_death_task)
+ if (NULL != is->cwh)
{
- GNUNET_SCHEDULER_cancel (is->child_death_task);
- is->child_death_task = NULL;
- }
- if (NULL != is->fakebank)
- {
- TALER_FAKEBANK_stop (is->fakebank);
- is->fakebank = NULL;
+ GNUNET_wait_child_cancel (is->cwh);
+ is->cwh = NULL;
}
GNUNET_free (is->commands);
}
@@ -362,7 +369,7 @@ do_shutdown (void *cls)
/**
* Function run when the test terminates (good or bad) with timeout.
*
- * @param cls NULL
+ * @param cls the `struct TALER_TESTING_Interpreter *`
*/
static void
do_timeout (void *cls)
@@ -380,55 +387,35 @@ do_timeout (void *cls)
* Task triggered whenever we receive a SIGCHLD (child
* process died).
*
- * @param cls closure
+ * @param cls the `struct TALER_TESTING_Interpreter *`
+ * @param type type of the process
+ * @param code status code of the process
*/
static void
-maint_child_death (void *cls)
+maint_child_death (void *cls,
+ enum GNUNET_OS_ProcessStatusType type,
+ long unsigned int code)
{
struct TALER_TESTING_Interpreter *is = cls;
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
- const struct GNUNET_DISK_FileHandle *pr;
struct GNUNET_OS_Process **processp;
- char c[16];
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
-
- if (TALER_TESTING_cmd_is_batch (cmd))
- {
- struct TALER_TESTING_Command *batch_cmd;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_cmd (cmd,
- 0,
- &batch_cmd));
- cmd = batch_cmd;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ is->cwh = NULL;
+ while (TALER_TESTING_cmd_is_batch (cmd))
+ cmd = TALER_TESTING_cmd_batch_get_current (cmd);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got SIGCHLD for `%s'.\n",
cmd->label);
- is->child_death_task = NULL;
- pr = GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ);
- GNUNET_break (0 <
- GNUNET_DISK_file_read (pr,
- &c,
- sizeof (c)));
if (GNUNET_OK !=
TALER_TESTING_get_trait_process (cmd,
- 0,
&processp))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
-
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got the dead child process handle, waiting for termination ...\n");
- GNUNET_OS_process_wait_status (*processp,
- &type,
- &code);
GNUNET_OS_process_destroy (*processp);
*processp = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -462,45 +449,36 @@ maint_child_death (void *cls)
TALER_TESTING_interpreter_fail (is);
return;
}
-
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Dead child, go on with next command.\n");
TALER_TESTING_interpreter_next (is);
}
-/**
- * Wait until we receive SIGCHLD signal.
- * Then obtain the process trait of the current
- * command, wait on the the zombie and continue
- * with the next command.
- */
void
TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
{
- const struct GNUNET_DISK_FileHandle *pr;
+ struct GNUNET_OS_Process **processp;
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
- GNUNET_assert (NULL == is->child_death_task);
- pr = GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ);
- is->child_death_task
- = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr,
- &maint_child_death,
- is);
+ while (TALER_TESTING_cmd_is_batch (cmd))
+ cmd = TALER_TESTING_cmd_batch_get_current (cmd);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_process (cmd,
+ &processp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (NULL == is->cwh);
+ is->cwh
+ = GNUNET_wait_child (*processp,
+ &maint_child_death,
+ is);
}
-/**
- * Run the testsuite. Note, CMDs are copied into
- * the interpreter state because they are _usually_
- * defined into the "run" method that returns after
- * having scheduled the test interpreter.
- *
- * @param is the interpreter state
- * @param commands the list of command to execute
- * @param timeout how long to wait
- */
void
TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands,
@@ -516,37 +494,36 @@ TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
/* get the number of commands */
for (i = 0; NULL != commands[i].label; i++)
;
- is->commands = GNUNET_new_array (i + 1,
- struct TALER_TESTING_Command);
- memcpy (is->commands,
- commands,
- sizeof (struct TALER_TESTING_Command) * i);
- is->timeout_task = GNUNET_SCHEDULER_add_delayed
- (timeout,
- &do_timeout,
- is);
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is);
+ is->commands = GNUNET_malloc_large ( (i + 1)
+ * sizeof (struct TALER_TESTING_Command));
+ GNUNET_assert (NULL != is->commands);
+ GNUNET_memcpy (is->commands,
+ commands,
+ sizeof (struct TALER_TESTING_Command) * i);
+ is->timeout_task = GNUNET_SCHEDULER_add_delayed (
+ timeout,
+ &do_timeout,
+ is);
+ GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
+ is);
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
}
-/**
- * Run the testsuite. Note, CMDs are copied into
- * the interpreter state because they are _usually_
- * defined into the "run" method that returns after
- * having scheduled the test interpreter.
- *
- * @param is the interpreter state
- * @param commands the list of command to execute
- */
+#include "valgrind.h"
+
void
TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands)
{
TALER_TESTING_run2 (is,
commands,
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
- 5));
+ 0 == RUNNING_ON_VALGRIND
+ ? GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
+ 5)
+ : GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
+ 50));
}
@@ -580,376 +557,446 @@ struct MainContext
/**
- * Signal handler called for SIGCHLD. Triggers the
- * respective handler by writing to the trigger pipe.
+ * 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
-sighandler_child_death (void)
+main_wrapper (void *cls)
{
- static char c;
- int old_errno = errno; /* back-up errno */
+ struct MainContext *main_ctx = cls;
- GNUNET_break (1 == GNUNET_DISK_file_write
- (GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_WRITE),
- &c, sizeof (c)));
- errno = old_errno; /* restore errno */
+ main_ctx->main_cb (main_ctx->main_cb_cls,
+ main_ctx->is);
}
-/**
- * "Canonical" cert_cb used when we are connecting to the
- * Exchange.
- *
- * @param cls closure, typically, the "run" method containing
- * all the commands to be run, and a closure for it.
- * @param hr HTTP response details
- * @param keys the exchange's keys.
- * @param compat protocol compatibility information.
- */
+enum GNUNET_GenericReturnValue
+TALER_TESTING_loop (TALER_TESTING_Main main_cb,
+ void *main_cb_cls)
+{
+ struct TALER_TESTING_Interpreter is;
+ struct MainContext main_ctx = {
+ .main_cb = main_cb,
+ .main_cb_cls = main_cb_cls,
+ /* needed to init the curl ctx */
+ .is = &is,
+ };
+
+ memset (&is,
+ 0,
+ sizeof (is));
+ is.ctx = GNUNET_CURL_init (
+ &GNUNET_CURL_gnunet_scheduler_reschedule,
+ &is.rc);
+ GNUNET_CURL_enable_async_scope_header (is.ctx,
+ "Taler-Correlation-Id");
+ GNUNET_assert (NULL != is.ctx);
+ is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
+ is.vars = GNUNET_CONTAINER_multihashmap_create (1024,
+ false);
+ /* Blocking */
+ GNUNET_SCHEDULER_run (&main_wrapper,
+ &main_ctx);
+ return is.result;
+}
+
+
+int
+TALER_TESTING_main (char *const *argv,
+ const char *loglevel,
+ const char *cfg_file,
+ const char *exchange_account_section,
+ enum TALER_TESTING_BankSystem bs,
+ struct TALER_TESTING_Credentials *cred,
+ TALER_TESTING_Main main_cb,
+ void *main_cb_cls)
+{
+ enum GNUNET_GenericReturnValue ret;
+
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup (argv[0],
+ loglevel,
+ NULL);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_credentials (cfg_file,
+ exchange_account_section,
+ bs,
+ cred))
+ {
+ GNUNET_break (0);
+ return 77;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_cleanup_files_cfg (NULL,
+ cred->cfg))
+ {
+ GNUNET_break (0);
+ return 77;
+ }
+ if (GNUNET_OK !=
+ TALER_extensions_init (cred->cfg))
+ {
+ GNUNET_break (0);
+ return 77;
+ }
+ ret = TALER_TESTING_loop (main_cb,
+ main_cb_cls);
+ /* TODO: should we free 'cred' resources here? */
+ return (GNUNET_OK == ret) ? 0 : 1;
+}
+
+
+/* ************** iterate over commands ********* */
+
+
void
-TALER_TESTING_cert_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_EXCHANGE_Keys *keys,
- enum TALER_EXCHANGE_VersionCompatibility compat)
+TALER_TESTING_iterate (struct TALER_TESTING_Interpreter *is,
+ bool asc,
+ TALER_TESTING_CommandIterator cb,
+ void *cb_cls)
{
- struct MainContext *main_ctx = cls;
- struct TALER_TESTING_Interpreter *is = main_ctx->is;
+ unsigned int start;
+ unsigned int end;
+ int inc;
- (void) compat;
- if (NULL == keys)
+ if (asc)
{
- if (GNUNET_NO == is->working)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Got NULL response for /keys during startup (%u/%d), retrying!\n",
- hr->http_status,
- (int) hr->ec);
- TALER_EXCHANGE_disconnect (is->exchange);
- GNUNET_assert (NULL != (is->exchange
- = TALER_EXCHANGE_connect (is->ctx,
- main_ctx->exchange_url,
- &TALER_TESTING_cert_cb,
- main_ctx,
- TALER_EXCHANGE_OPTION_END)));
- return;
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Got NULL response for /keys during execution (%u/%d)!\n",
- hr->http_status,
- (int) hr->ec);
- }
+ inc = 1;
+ start = 0;
+ end = is->ip;
}
else
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got %d DK from /keys in generation %u\n",
- keys->num_denom_keys,
- is->key_generation + 1);
+ inc = -1;
+ start = is->ip;
+ end = 0;
}
- is->key_generation++;
- is->keys = keys;
+ for (unsigned int off = start; off != end + inc; off += inc)
+ {
+ const struct TALER_TESTING_Command *cmd = &is->commands[off];
- /* /keys has been called for some reason and
- * the interpreter is already running. */
- if (GNUNET_YES == is->working)
- return;
- is->working = GNUNET_YES;
- /* Trigger the next command. */
- TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n",
- is->ip);
- GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
+ cb (cb_cls,
+ cmd);
+ }
+}
+
+
+/* ************** special commands ********* */
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_end (void)
+{
+ static struct TALER_TESTING_Command cmd;
+ cmd.label = NULL;
+
+ return cmd;
+}
+
+
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_set_var (const char *name,
+ struct TALER_TESTING_Command cmd)
+{
+ cmd.name = name;
+ return cmd;
}
/**
- * 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".
+ * State for a "rewind" CMD.
*/
-static void
-main_wrapper_exchange_agnostic (void *cls)
+struct RewindIpState
{
- struct MainContext *main_ctx = cls;
+ /**
+ * Instruction pointer to set into the interpreter.
+ */
+ const char *target_label;
- main_ctx->main_cb (main_ctx->main_cb_cls,
- main_ctx->is);
+ /**
+ * How many times this set should take place. However, this value lives at
+ * the calling process, and this CMD is only in charge of checking and
+ * decremeting it.
+ */
+ unsigned int counter;
+};
+
+
+/**
+ * Seek for the @a target command in @a batch (and rewind to it
+ * if successful).
+ *
+ * @param is the interpreter state (for failures)
+ * @param cmd batch to search for @a target
+ * @param target command to search for
+ * @return #GNUNET_OK on success, #GNUNET_NO if target was not found,
+ * #GNUNET_SYSERR if target is in the future and we failed
+ */
+static enum GNUNET_GenericReturnValue
+seek_batch (struct TALER_TESTING_Interpreter *is,
+ const struct TALER_TESTING_Command *cmd,
+ const struct TALER_TESTING_Command *target)
+{
+ unsigned int new_ip;
+ struct TALER_TESTING_Command *batch;
+ struct TALER_TESTING_Command *current;
+ struct TALER_TESTING_Command *icmd;
+ struct TALER_TESTING_Command *match;
+
+ current = TALER_TESTING_cmd_batch_get_current (cmd);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_batch_cmds (cmd,
+ &batch));
+ match = NULL;
+ for (new_ip = 0;
+ NULL != (icmd = &batch[new_ip]);
+ new_ip++)
+ {
+ if (current == target)
+ current = NULL;
+ if (icmd == target)
+ {
+ match = icmd;
+ break;
+ }
+ if (TALER_TESTING_cmd_is_batch (icmd))
+ {
+ int ret = seek_batch (is,
+ icmd,
+ target);
+ if (GNUNET_SYSERR == ret)
+ return GNUNET_SYSERR; /* failure! */
+ if (GNUNET_OK == ret)
+ {
+ match = icmd;
+ break;
+ }
+ }
+ }
+ if (NULL == current)
+ {
+ /* refuse to jump forward */
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return GNUNET_SYSERR;
+ }
+ if (NULL == match)
+ return GNUNET_NO; /* not found */
+ TALER_TESTING_cmd_batch_set_current (cmd,
+ new_ip);
+ return GNUNET_OK;
}
/**
- * Function run when the test is aborted before we launch the actual
- * interpreter. Cleans up our state.
+ * Run the "rewind" CMD.
*
- * @param cls the main context
+ * @param cls closure.
+ * @param cmd command being executed now.
+ * @param is the interpreter state.
*/
static void
-do_abort (void *cls)
+rewind_ip_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
{
- struct MainContext *main_ctx = cls;
- struct TALER_TESTING_Interpreter *is = main_ctx->is;
+ struct RewindIpState *ris = cls;
+ const struct TALER_TESTING_Command *target;
+ unsigned int new_ip;
- is->timeout_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Executing abort prior to interpreter launch\n");
- if (NULL != is->exchange)
+ (void) cmd;
+ if (0 == ris->counter)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ target
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ris->target_label);
+ if (NULL == target)
{
- TALER_EXCHANGE_disconnect (is->exchange);
- is->exchange = NULL;
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
}
- if (NULL != is->ctx)
+ ris->counter--;
+ for (new_ip = 0;
+ NULL != is->commands[new_ip].label;
+ new_ip++)
{
- GNUNET_CURL_fini (is->ctx);
- is->ctx = NULL;
+ const struct TALER_TESTING_Command *cmd = &is->commands[new_ip];
+
+ if (cmd == target)
+ break;
+ if (TALER_TESTING_cmd_is_batch (cmd))
+ {
+ int ret = seek_batch (is,
+ cmd,
+ target);
+ if (GNUNET_SYSERR == ret)
+ return; /* failure! */
+ if (GNUNET_OK == ret)
+ break;
+ }
}
- if (NULL != is->rc)
+ if (new_ip > (unsigned int) is->ip)
{
- GNUNET_CURL_gnunet_rc_destroy (is->rc);
- is->rc = NULL;
+ /* refuse to jump forward */
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
}
+ is->ip = new_ip - 1; /* -1 because the next function will advance by one */
+ TALER_TESTING_interpreter_next (is);
}
-/**
- * Initialize scheduler loop and curl context for the testcase,
- * and responsible to run the "run" method.
- *
- * @param cls a `struct MainContext *`
- */
-static void
-main_wrapper_exchange_connect (void *cls)
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_rewind_ip (const char *label,
+ const char *target_label,
+ unsigned int counter)
{
- struct MainContext *main_ctx = cls;
- struct TALER_TESTING_Interpreter *is = main_ctx->is;
- char *exchange_url;
+ struct RewindIpState *ris;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (is->cfg,
- "exchange",
- "BASE_URL",
- &exchange_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "BASE_URL");
- return;
+ ris = GNUNET_new (struct RewindIpState);
+ ris->target_label = target_label;
+ ris->counter = counter;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ris,
+ .label = label,
+ .run = &rewind_ip_run
+ };
+
+ return cmd;
}
- main_ctx->exchange_url = exchange_url;
- is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
- main_ctx);
- is->working = GNUNET_YES;
- GNUNET_break
- (NULL != (is->exchange =
- TALER_EXCHANGE_connect (is->ctx,
- exchange_url,
- &TALER_TESTING_cert_cb,
- main_ctx,
- TALER_EXCHANGE_OPTION_END)));
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Starting main test loop\n");
- main_ctx->main_cb (main_ctx->main_cb_cls,
- is);
}
/**
- * Load the exchange and auditor key material into @a is.
+ * State for a "authchange" CMD.
+ */
+struct AuthchangeState
+{
+
+ /**
+ * What is the new authorization token to send?
+ */
+ const char *auth_token;
+
+ /**
+ * Old context, clean up on termination.
+ */
+ struct GNUNET_CURL_Context *old_ctx;
+};
+
+
+/**
+ * Run the command.
*
- * @param[in,out] is state to initialize
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
*/
-static int
-load_keys (struct TALER_TESTING_Interpreter *is)
+static void
+authchange_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
{
- char *fn;
+ struct AuthchangeState *ss = cls;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (is->cfg,
- "exchange-offline",
- "MASTER_PRIV_FILE",
- &fn))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-offline",
- "MASTER_PRIV_FILE");
- return GNUNET_SYSERR;
- }
- if (GNUNET_SYSERR ==
- GNUNET_DISK_directory_create_for_file (fn))
+ (void) cmd;
+ ss->old_ctx = is->ctx;
+ if (NULL != is->rc)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not setup directory for master private key file `%s'\n",
- fn);
- GNUNET_free (fn);
- return GNUNET_SYSERR;
+ GNUNET_CURL_gnunet_rc_destroy (is->rc);
+ is->rc = NULL;
}
- if (GNUNET_SYSERR ==
- GNUNET_CRYPTO_eddsa_key_from_file (fn,
- GNUNET_YES,
- &is->master_priv.eddsa_priv))
+ is->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+ &is->rc);
+ GNUNET_CURL_enable_async_scope_header (is->ctx,
+ "Taler-Correlation-Id");
+ GNUNET_assert (NULL != is->ctx);
+ is->rc = GNUNET_CURL_gnunet_rc_create (is->ctx);
+ if (NULL != ss->auth_token)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not load master private key from `%s'\n",
- fn);
- GNUNET_free (fn);
- return GNUNET_SYSERR;
- }
- GNUNET_free (fn);
- GNUNET_CRYPTO_eddsa_key_get_public (&is->master_priv.eddsa_priv,
- &is->master_pub.eddsa_pub);
+ char *authorization;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (is->cfg,
- "auditor",
- "AUDITOR_PRIV_FILE",
- &fn))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "AUDITOR_PRIV_FILE");
- return GNUNET_SYSERR;
- }
- if (GNUNET_SYSERR ==
- GNUNET_DISK_directory_create_for_file (fn))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not setup directory for auditor private key file `%s'\n",
- fn);
- GNUNET_free (fn);
- return GNUNET_SYSERR;
- }
- if (GNUNET_SYSERR ==
- GNUNET_CRYPTO_eddsa_key_from_file (fn,
- GNUNET_YES,
- &is->auditor_priv.eddsa_priv))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not load auditor private key from `%s'\n",
- fn);
- GNUNET_free (fn);
- return GNUNET_SYSERR;
+ GNUNET_asprintf (&authorization,
+ "%s: %s",
+ MHD_HTTP_HEADER_AUTHORIZATION,
+ ss->auth_token);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CURL_append_header (is->ctx,
+ authorization));
+ GNUNET_free (authorization);
}
- GNUNET_free (fn);
- GNUNET_CRYPTO_eddsa_key_get_public (&is->auditor_priv.eddsa_priv,
- &is->auditor_pub.eddsa_pub);
- return GNUNET_OK;
+ TALER_TESTING_interpreter_next (is);
}
/**
- * Load the exchange and auditor URLs from the configuration into @a is.
+ * Call GNUNET_CURL_fini(). Done as a separate task to
+ * ensure that all of the command's cleanups have been
+ * executed first. See #7151.
*
- * @param[in,out] is state to initialize
+ * @param cls a `struct GNUNET_CURL_Context *` to clean up.
*/
-static int
-load_urls (struct TALER_TESTING_Interpreter *is)
+static void
+deferred_cleanup_cb (void *cls)
{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (is->cfg,
- "auditor",
- "BASE_URL",
- &is->auditor_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "BASE_URL");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (is->cfg,
- "exchange",
- "BASE_URL",
- &is->exchange_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "BASE_URL");
- GNUNET_free (is->auditor_url);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
+ struct GNUNET_CURL_Context *ctx = cls;
+
+ GNUNET_CURL_fini (ctx);
}
/**
- * Install signal handlers plus schedules the main wrapper
- * around the "run" method.
+ * Cleanup the state from a "authchange" CMD.
*
- * @param main_cb the "run" method which contains all the
- * commands.
- * @param main_cb_cls a closure for "run", typically NULL.
- * @param cfg configuration to use
- * @param exchanged exchange process handle: will be put in the
- * state as some commands - e.g. revoke - need to send
- * signal to it, for example to let it know to reload the
- * key state.. if NULL, the interpreter will run without
- * trying to connect to the exchange first.
- * @param exchange_connect #GNUNET_YES if the test should connect
- * to the exchange, #GNUNET_NO otherwise
- * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
- * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
- * times.
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
*/
-int
-TALER_TESTING_setup (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- struct GNUNET_OS_Process *exchanged,
- int exchange_connect)
+static void
+authchange_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
{
- struct TALER_TESTING_Interpreter is;
- struct MainContext main_ctx = {
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls,
- /* needed to init the curl ctx */
- .is = &is,
- };
- struct GNUNET_SIGNAL_Context *shc_chld;
+ struct AuthchangeState *ss = cls;
- memset (&is,
- 0,
- sizeof (is));
- is.exchanged = exchanged;
- is.cfg = cfg;
- if (GNUNET_OK !=
- load_keys (&is))
- return GNUNET_SYSERR;
- if (GNUNET_OK !=
- load_urls (&is))
- return GNUNET_SYSERR;
- sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
- GNUNET_assert (NULL != sigpipe);
- shc_chld = GNUNET_SIGNAL_handler_install
- (GNUNET_SIGCHLD,
- &sighandler_child_death);
- is.ctx = GNUNET_CURL_init
- (&GNUNET_CURL_gnunet_scheduler_reschedule,
- &is.rc);
- GNUNET_CURL_enable_async_scope_header (is.ctx, "Taler-Correlation-Id");
- GNUNET_assert (NULL != is.ctx);
- is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
+ (void) cmd;
+ if (NULL != ss->old_ctx)
+ {
+ (void) GNUNET_SCHEDULER_add_now (&deferred_cleanup_cb,
+ ss->old_ctx);
+ ss->old_ctx = NULL;
+ }
+ GNUNET_free (ss);
+}
- /* Blocking */
- if (GNUNET_YES == exchange_connect)
- GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect,
- &main_ctx);
- else
- GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic,
- &main_ctx);
- if (NULL != is.final_cleanup_cb)
- is.final_cleanup_cb (is.final_cleanup_cb_cls);
- GNUNET_free (main_ctx.exchange_url);
- GNUNET_SIGNAL_handler_uninstall (shc_chld);
- GNUNET_DISK_pipe_close (sigpipe);
- sigpipe = NULL;
- GNUNET_free (is.auditor_url);
- GNUNET_free (is.exchange_url);
- return is.result;
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_set_authorization (const char *label,
+ const char *auth_token)
+{
+ struct AuthchangeState *ss;
+
+ ss = GNUNET_new (struct AuthchangeState);
+ ss->auth_token = auth_token;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &authchange_run,
+ .cleanup = &authchange_cleanup
+ };
+
+ return cmd;
+ }
}
diff --git a/src/testing/testing_api_misc.c b/src/testing/testing_api_misc.c
new file mode 100644
index 000000000..80ff0b6c8
--- /dev/null
+++ b/src/testing/testing_api_misc.c
@@ -0,0 +1,394 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_misc.c
+ * @brief non-command functions useful for writing tests
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_fakebank_lib.h"
+
+
+bool
+TALER_TESTING_has_in_name (const char *prog,
+ const char *marker)
+{
+ size_t name_pos;
+ size_t pos;
+
+ if (! prog || ! marker)
+ return false;
+
+ pos = 0;
+ name_pos = 0;
+ while (prog[pos])
+ {
+ if ('/' == prog[pos])
+ name_pos = pos + 1;
+ pos++;
+ }
+ if (name_pos == pos)
+ return true;
+ return (NULL != strstr (prog + name_pos,
+ marker));
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_TESTING_get_credentials (
+ const char *cfg_file,
+ const char *exchange_account_section,
+ enum TALER_TESTING_BankSystem bs,
+ struct TALER_TESTING_Credentials *ua)
+{
+ unsigned long long port;
+ char *exchange_payto_uri;
+
+ ua->cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_load (ua->cfg,
+ cfg_file))
+ {
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (ua->cfg);
+ return GNUNET_SYSERR;
+ }
+ if (0 !=
+ strncasecmp (exchange_account_section,
+ "exchange-account-",
+ strlen ("exchange-account-")))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (ua->cfg,
+ exchange_account_section,
+ "PAYTO_URI",
+ &exchange_payto_uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ exchange_account_section,
+ "PAYTO_URI");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (ua->cfg,
+ "bank",
+ "HTTP_PORT",
+ &port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "bank",
+ "HTTP_PORT");
+ return GNUNET_SYSERR;
+ }
+ {
+ char *csn;
+
+ GNUNET_asprintf (&csn,
+ "exchange-accountcredentials-%s",
+ &exchange_account_section[strlen ("exchange-account-")]);
+ if (GNUNET_OK !=
+ TALER_BANK_auth_parse_cfg (ua->cfg,
+ csn,
+ &ua->ba))
+ {
+ GNUNET_break (0);
+ GNUNET_free (csn);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (csn);
+ }
+ {
+ char *csn;
+
+ GNUNET_asprintf (&csn,
+ "admin-accountcredentials-%s",
+ &exchange_account_section[strlen ("exchange-account-")]);
+ if (GNUNET_OK !=
+ TALER_BANK_auth_parse_cfg (ua->cfg,
+ csn,
+ &ua->ba_admin))
+ {
+ GNUNET_break (0);
+ GNUNET_free (csn);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (csn);
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (ua->cfg,
+ "exchange",
+ "BASE_URL",
+ &ua->exchange_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "BASE_URL");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (ua->cfg,
+ "auditor",
+ "BASE_URL",
+ &ua->auditor_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "auditor",
+ "BASE_URL");
+ return GNUNET_SYSERR;
+ }
+
+ switch (bs)
+ {
+ case TALER_TESTING_BS_FAKEBANK:
+ ua->exchange_payto
+ = exchange_payto_uri;
+ ua->user42_payto
+ = GNUNET_strdup ("payto://x-taler-bank/localhost/42?receiver-name=42");
+ ua->user43_payto
+ = GNUNET_strdup ("payto://x-taler-bank/localhost/43?receiver-name=43");
+ break;
+ case TALER_TESTING_BS_IBAN:
+ ua->exchange_payto
+ = exchange_payto_uri;
+ ua->user42_payto
+ = GNUNET_strdup (
+ "payto://iban/SANDBOXX/FR7630006000011234567890189?receiver-name=User42");
+ ua->user43_payto
+ = GNUNET_strdup (
+ "payto://iban/SANDBOXX/GB33BUKB20201555555555?receiver-name=User43");
+ break;
+ }
+ return GNUNET_OK;
+}
+
+
+json_t *
+TALER_TESTING_make_wire_details (const char *payto)
+{
+ struct TALER_WireSaltP salt;
+
+ /* salt must be constant for aggregation tests! */
+ memset (&salt,
+ 47,
+ sizeof (salt));
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("payto_uri",
+ payto),
+ GNUNET_JSON_pack_data_auto ("salt",
+ &salt));
+}
+
+
+/**
+ * Remove @a option directory from @a section in @a cfg.
+ *
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+remove_dir (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ const char *option)
+{
+ char *dir;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ section,
+ option,
+ &dir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ option);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (dir,
+ GNUNET_NO))
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_DISK_directory_remove (dir));
+ GNUNET_free (dir);
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_TESTING_cleanup_files_cfg (
+ void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *dir;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange-offline",
+ "SECM_TOFU_FILE",
+ &dir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange-offline",
+ "SECM_TOFU_FILE");
+ return GNUNET_SYSERR;
+ }
+ if ( (0 != unlink (dir)) &&
+ (ENOENT != errno) )
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "unlink",
+ dir);
+ GNUNET_free (dir);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (dir);
+ if (GNUNET_OK !=
+ remove_dir (cfg,
+ "taler-exchange-secmod-eddsa",
+ "KEY_DIR"))
+ return GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ remove_dir (cfg,
+ "taler-exchange-secmod-rsa",
+ "KEY_DIR"))
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
+
+const struct TALER_EXCHANGE_DenomPublicKey *
+TALER_TESTING_find_pk (
+ const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_Amount *amount,
+ bool age_restricted)
+{
+ struct GNUNET_TIME_Timestamp now;
+ struct TALER_EXCHANGE_DenomPublicKey *pk;
+ char *str;
+
+ now = GNUNET_TIME_timestamp_get ();
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ {
+ pk = &keys->denom_keys[i];
+ if ( (0 == TALER_amount_cmp (amount,
+ &pk->value)) &&
+ (GNUNET_TIME_timestamp_cmp (now,
+ >=,
+ pk->valid_from)) &&
+ (GNUNET_TIME_timestamp_cmp (now,
+ <,
+ pk->withdraw_valid_until)) &&
+ (age_restricted == (0 != pk->key.age_mask.bits)) )
+ return pk;
+ }
+ /* do 2nd pass to check if expiration times are to blame for
+ * failure */
+ str = TALER_amount_to_string (amount);
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ {
+ pk = &keys->denom_keys[i];
+ if ( (0 == TALER_amount_cmp (amount,
+ &pk->value)) &&
+ (GNUNET_TIME_timestamp_cmp (now,
+ <,
+ pk->valid_from) ||
+ GNUNET_TIME_timestamp_cmp (now,
+ >,
+ pk->withdraw_valid_until) ) &&
+ (age_restricted == (0 != pk->key.age_mask.bits)) )
+ {
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_WARNING,
+ "Have denomination key for `%s', but with wrong"
+ " expiration range %llu vs [%llu,%llu)\n",
+ str,
+ (unsigned long long) now.abs_time.abs_value_us,
+ (unsigned long long) pk->valid_from.abs_time.abs_value_us,
+ (unsigned long long) pk->withdraw_valid_until.abs_time.abs_value_us);
+ GNUNET_free (str);
+ return NULL;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No denomination key for amount %s found\n",
+ str);
+ GNUNET_free (str);
+ return NULL;
+}
+
+
+int
+TALER_TESTING_wait_httpd_ready (const char *base_url)
+{
+ char *wget_cmd;
+ unsigned int iter;
+
+ GNUNET_asprintf (&wget_cmd,
+ "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null",
+ base_url); // make sure ends with '/'
+ /* give child time to start and bind against the socket */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Waiting for HTTP service to be ready (check with: %s)\n",
+ wget_cmd);
+ iter = 0;
+ do
+ {
+ if (10 == iter)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to launch HTTP service (or `wget')\n");
+ GNUNET_free (wget_cmd);
+ return 77;
+ }
+ sleep (1);
+ iter++;
+ }
+ while (0 != system (wget_cmd));
+ GNUNET_free (wget_cmd);
+ return 0;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_TESTING_url_port_free (const char *url)
+{
+ const char *port;
+ long pnum;
+
+ port = strrchr (url,
+ (unsigned char) ':');
+ if (NULL == port)
+ pnum = 80;
+ else
+ pnum = strtol (port + 1, NULL, 10);
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
+ pnum))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Port %u not available.\n",
+ (unsigned int) pnum);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
diff --git a/src/testing/testing_api_trait_amount.c b/src/testing/testing_api_trait_amount.c
deleted file mode 100644
index 96698b49e..000000000
--- a/src/testing/testing_api_trait_amount.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3,
- or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_amount.c
- * @brief offer amounts as traits.
- * @author Marcello Stanisci
- */
-
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_AMOUNT "amount"
-
-/**
- * Obtain an amount from a @a cmd.
- *
- * @param cmd command to extract the amount from.
- * @param index which amount to pick if @a cmd has multiple
- * on offer
- * @param[out] amount set to the amount.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_amount_obj (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_Amount **amount)
-{
- return cmd->traits (cmd->cls,
- (const void **) amount,
- TALER_TESTING_TRAIT_AMOUNT,
- index);
-}
-
-
-/**
- * Offer amount.
- *
- * @param index which amount to offer, in case there are
- * multiple available.
- * @param amount the amount to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_amount_obj (unsigned int index,
- const struct TALER_Amount *amount)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_AMOUNT,
- .ptr = (const void *) amount
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_amount.c */
diff --git a/src/testing/testing_api_trait_blinding_key.c b/src/testing/testing_api_trait_blinding_key.c
deleted file mode 100644
index ae1889a1f..000000000
--- a/src/testing/testing_api_trait_blinding_key.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_blinding_key.c
- * @brief offer blinding keys as traits.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_BLINDING_KEY "blinding-key"
-
-
-/**
- * Obtain a blinding key from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index which coin to pick if @a cmd has multiple on offer.
- * @param[out] blinding_key set to the offered blinding key.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_blinding_key
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_DenominationBlindingKeyP **blinding_key)
-{
- return cmd->traits (cmd->cls,
- (const void **) blinding_key,
- TALER_TESTING_TRAIT_BLINDING_KEY,
- index);
-}
-
-
-/**
- * Offer blinding key.
- *
- * @param index index number to associate to the offered key.
- * @param blinding_key blinding key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_blinding_key
- (unsigned int index,
- const struct TALER_DenominationBlindingKeyP *blinding_key)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_BLINDING_KEY,
- .ptr = (const void *) blinding_key
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_blinding_key.c */
diff --git a/src/testing/testing_api_trait_cmd.c b/src/testing/testing_api_trait_cmd.c
deleted file mode 100644
index f24054713..000000000
--- a/src/testing/testing_api_trait_cmd.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_trait_cmd.c
- * @brief offers CMDs as traits.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_CMD "cmd"
-
-
-/**
- * Obtain a command from @a cmd.
- *
- * @param cmd command to extract the command from.
- * @param index always zero. Commands offering this
- * kind of traits do not need this index. For
- * example, a "batch" CMD returns always the
- * CMD currently being executed.
- * @param[out] _cmd where to write the wire details.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_cmd (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- struct TALER_TESTING_Command **_cmd)
-{
- return cmd->traits (cmd->cls,
- (const void **) _cmd,
- TALER_TESTING_TRAIT_CMD,
- index);
-}
-
-
-/**
- * Offer a command in a trait.
- *
- * @param index always zero. Commands offering this
- * kind of traits do not need this index. For
- * example, a "meta" CMD returns always the
- * CMD currently being executed.
- * @param cmd wire details to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_cmd (unsigned int index,
- const struct TALER_TESTING_Command *cmd)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_CMD,
- .ptr = (const struct TALER_TESTING_Command *) cmd
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_cmd.c */
diff --git a/src/testing/testing_api_trait_coin_priv.c b/src/testing/testing_api_trait_coin_priv.c
deleted file mode 100644
index 61a770cf6..000000000
--- a/src/testing/testing_api_trait_coin_priv.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_trait_coin_priv.c
- * @brief coin priv traits.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_COIN_PRIVATE_KEY "coin-private-key"
-
-
-/**
- * Obtain a coin private key from a @a cmd.
- *
- * @param cmd command to extract trait from.
- * @param index index of the coin priv to obtain.
- * @param[out] coin_priv set to the private key of the coin.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_coin_priv
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_CoinSpendPrivateKeyP **coin_priv)
-{
- return cmd->traits (cmd->cls,
- (const void **) coin_priv,
- TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
- index);
-}
-
-
-/**
- * Offer coin private key.
- *
- * @param index index number to associate with offered coin priv.
- * @param coin_priv coin private key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_coin_priv
- (unsigned int index,
- const struct TALER_CoinSpendPrivateKeyP *coin_priv)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
- .ptr = (const void *) coin_priv
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_coin_priv.c */
diff --git a/src/testing/testing_api_trait_contract.c b/src/testing/testing_api_trait_contract.c
deleted file mode 100644
index 1e88cb86f..000000000
--- a/src/testing/testing_api_trait_contract.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_contract.c
- * @brief offers contract term trait.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * Contains a contract terms object as a json_t.
- */
-#define TALER_TESTING_TRAIT_CONTRACT_TERMS "contract-terms"
-
-
-/**
- * Obtain contract terms from @a cmd.
- *
- * @param cmd command to extract the contract terms from.
- * @param index contract terms index number.
- * @param[out] contract_terms where to write the contract terms.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_contract_terms (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const json_t **contract_terms)
-{
- return cmd->traits (cmd->cls,
- (const void **) contract_terms,
- TALER_TESTING_TRAIT_CONTRACT_TERMS,
- index);
-}
-
-
-/**
- * Offer contract terms.
- *
- * @param index contract terms index number.
- * @param contract_terms contract terms to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_contract_terms (unsigned int index,
- const json_t *contract_terms)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_CONTRACT_TERMS,
- .ptr = (const void *) contract_terms
- };
- return ret;
-}
diff --git a/src/testing/testing_api_trait_denom_pub.c b/src/testing/testing_api_trait_denom_pub.c
deleted file mode 100644
index f866588db..000000000
--- a/src/testing/testing_api_trait_denom_pub.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_denom_pub.c
- * @brief denom pub traits.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_DENOM_PUB "denomination-public-key"
-
-
-/**
- * Obtain a denomination public key from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index index number of the denom to obtain.
- * @param[out] denom_pub set to the offered denom pub.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_denom_pub (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct
- TALER_EXCHANGE_DenomPublicKey **denom_pub)
-{
- return cmd->traits (cmd->cls,
- (const void **) denom_pub,
- TALER_TESTING_TRAIT_DENOM_PUB,
- index);
-}
-
-
-/**
- * Make a trait for a denomination public key.
- *
- * @param index index number to associate to the offered denom pub.
- * @param denom_pub denom pub to offer with this trait.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_denom_pub (unsigned int index,
- const struct
- TALER_EXCHANGE_DenomPublicKey *denom_pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_DENOM_PUB,
- .ptr = (const void *) denom_pub
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_denom_pub.c */
diff --git a/src/testing/testing_api_trait_denom_sig.c b/src/testing/testing_api_trait_denom_sig.c
deleted file mode 100644
index 07e89440e..000000000
--- a/src/testing/testing_api_trait_denom_sig.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3,
- or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_trait_denom_sig.c
- * @brief offer denomination signatures as traits
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_DENOM_SIG "denomination-signature"
-
-
-/**
- * Obtain a denomination signature from a @a cmd.
- *
- * @param cmd command to extract the denom sig from.
- * @param index index number associated with the denom sig.
- * @param[out] denom_sig set to the offered signature.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_denom_sig
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_DenominationSignature **denom_sig)
-{
- return cmd->traits (cmd->cls,
- (const void **) denom_sig,
- TALER_TESTING_TRAIT_DENOM_SIG,
- index);
-}
-
-
-/**
- * Offer denom sig.
- *
- * @param index index number to associate to the signature on
- * offer.
- * @param denom_sig the denom sig on offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_denom_sig
- (unsigned int index,
- const struct TALER_DenominationSignature *denom_sig)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_DENOM_SIG,
- .ptr = (const void *) denom_sig
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_denom_sig.c */
diff --git a/src/testing/testing_api_trait_exchange_pub.c b/src/testing/testing_api_trait_exchange_pub.c
deleted file mode 100644
index 8c7027260..000000000
--- a/src/testing/testing_api_trait_exchange_pub.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_exchange_pub.c
- * @brief exchange pub traits.
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_EXCHANGE_PUB "exchange-public-key"
-
-
-/**
- * Obtain a exchange public key from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index index number of the exchange to obtain.
- * @param[out] exchange_pub set to the offered exchange pub.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_exchange_pub
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ExchangePublicKeyP **exchange_pub)
-{
- return cmd->traits (cmd->cls,
- (const void **) exchange_pub,
- TALER_TESTING_TRAIT_EXCHANGE_PUB,
- index);
-}
-
-
-/**
- * Make a trait for a exchange public key.
- *
- * @param index index number to associate to the offered exchange pub.
- * @param exchange_pub exchange pub to offer with this trait.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_exchange_pub
- (unsigned int index,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_EXCHANGE_PUB,
- .ptr = (const void *) exchange_pub
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_exchange_pub.c */
diff --git a/src/testing/testing_api_trait_exchange_sig.c b/src/testing/testing_api_trait_exchange_sig.c
deleted file mode 100644
index 349454ae7..000000000
--- a/src/testing/testing_api_trait_exchange_sig.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_exchange_sig.c
- * @brief exchange pub traits.
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_EXCHANGE_SIG "exchange-online-signature"
-
-
-/**
- * Obtain a exchange signature (online sig) from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index index number of the exchange to obtain.
- * @param[out] exchange_sig set to the offered exchange signature.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_exchange_sig
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ExchangeSignatureP **exchange_sig)
-{
- return cmd->traits (cmd->cls,
- (const void **) exchange_sig,
- TALER_TESTING_TRAIT_EXCHANGE_SIG,
- index);
-}
-
-
-/**
- * Make a trait for a exchange signature.
- *
- * @param index index number to associate to the offered exchange pub.
- * @param exchange_sig exchange signature to offer with this trait.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_exchange_sig
- (unsigned int index,
- const struct TALER_ExchangeSignatureP *exchange_sig)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_EXCHANGE_SIG,
- .ptr = (const void *) exchange_sig
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_exchange_sig.c */
diff --git a/src/testing/testing_api_trait_fresh_coin.c b/src/testing/testing_api_trait_fresh_coin.c
deleted file mode 100644
index e5f1c6827..000000000
--- a/src/testing/testing_api_trait_fresh_coin.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_fresh_coin.c
- * @brief traits to offer fresh conins (after "melt" operations)
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_FRESH_COINS "fresh-coins"
-
-/**
- * Get a array of fresh coins.
- *
- * @param cmd command to extract the fresh coin from.
- * @param index which array to pick if @a cmd has multiple
- * on offer.
- * @param[out] fresh_coins will point to the offered array.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_fresh_coins
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_TESTING_FreshCoinData **fresh_coins)
-{
- return cmd->traits (cmd->cls,
- (const void **) fresh_coins,
- TALER_TESTING_TRAIT_FRESH_COINS,
- index);
-}
-
-
-/**
- * Offer a _array_ of fresh coins.
- *
- * @param index which array of fresh coins to offer,
- * if there are multiple on offer. Typically passed as
- * zero.
- * @param fresh_coins the array of fresh coins to offer
- * @return the trait,
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_fresh_coins
- (unsigned int index,
- const struct TALER_TESTING_FreshCoinData *fresh_coins)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_FRESH_COINS,
- .ptr = (const void *) fresh_coins
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_fresh_coin.c */
diff --git a/src/testing/testing_api_trait_json.c b/src/testing/testing_api_trait_json.c
deleted file mode 100644
index e12f1e9a1..000000000
--- a/src/testing/testing_api_trait_json.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_trait_json.c
- * @brief offers JSON traits.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_WIRE_DETAILS "wire-details"
-#define TALER_TESTING_TRAIT_EXCHANGE_KEYS "exchange-keys"
-#define TALER_TESTING_TRAIT_JSON "json"
-
-/**
- * Obtain serialized exchange keys from @a cmd.
- *
- * @param cmd command to extract the keys from.
- * @param index index number associate with the keys on offer.
- * @param[out] keys where to write the serialized keys.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_exchange_keys
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const json_t **keys)
-{
- return cmd->traits (cmd->cls,
- (const void **) keys,
- TALER_TESTING_TRAIT_EXCHANGE_KEYS,
- index);
-}
-
-
-/**
- * Offer serialized keys in a trait.
- *
- * @param index index number associate with the serial keys
- * on offer.
- * @param keys serialized keys to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_exchange_keys
- (unsigned int index,
- const json_t *keys)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_EXCHANGE_KEYS,
- .ptr = (const json_t *) keys
- };
- return ret;
-}
-
-
-/**
- * Obtain wire details from @a cmd.
- *
- * @param cmd command to extract the wire details from.
- * @param index index number associate with the wire details
- * on offer; usually zero, as one command sticks to
- * one bank account.
- * @param[out] wire_details where to write the wire details.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_wire_details
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const json_t **wire_details)
-{
- return cmd->traits (cmd->cls,
- (const void **) wire_details,
- TALER_TESTING_TRAIT_WIRE_DETAILS,
- index);
-}
-
-
-/**
- * Offer wire details in a trait.
- *
- * @param index index number associate with the wire details
- * on offer; usually zero, as one command sticks to
- * one bank account.
- * @param wire_details wire details to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_wire_details
- (unsigned int index,
- const json_t *wire_details)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS,
- .ptr = (const json_t *) wire_details
- };
- return ret;
-}
-
-
-/**
- * Obtain json from @a cmd.
- *
- * @param cmd command to extract the json from.
- * @param index index number associate with the json on offer.
- * @param[out] json where to write the json.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_json (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const json_t **json)
-{
- return cmd->traits (cmd->cls,
- (const void **) json,
- TALER_TESTING_TRAIT_JSON,
- index);
-}
-
-
-/**
- * Offer json in a trait.
- *
- * @param index index number associate with the json
- * on offer.
- * @param json json to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_json (unsigned int index,
- const json_t *json)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_JSON,
- .ptr = (const json_t *) json
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_json.c */
diff --git a/src/testing/testing_api_trait_merchant_key.c b/src/testing/testing_api_trait_merchant_key.c
deleted file mode 100644
index 41b6b8883..000000000
--- a/src/testing/testing_api_trait_merchant_key.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_merchant_key.c
- * @brief traits to offer peer's (private) keys
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_MERCHANT_PRIV "merchant-priv"
-#define TALER_TESTING_TRAIT_MERCHANT_PUB "merchant-pub-pub"
-
-/**
- * Obtain a private key from a "peer". Used e.g. to obtain
- * a merchant's priv to sign a /track request.
- *
- * @param cmd command that is offering the key.
- * @param index (typically zero) which key to return if there
- * are multiple on offer.
- * @param[out] priv set to the key coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_merchant_priv
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_MerchantPrivateKeyP **priv)
-{
- return cmd->traits (cmd->cls,
- (const void **) priv,
- TALER_TESTING_TRAIT_MERCHANT_PRIV,
- index);
-}
-
-
-/**
- * Offer private key, typically done when CMD_1 needs it to
- * sign a request.
- *
- * @param index (typically zero) which key to return if there are
- * multiple on offer.
- * @param priv which object should be offered.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_merchant_priv (unsigned int index,
- const struct
- TALER_MerchantPrivateKeyP *priv)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_MERCHANT_PRIV,
- .ptr = (const void *) priv
- };
-
- return ret;
-}
-
-
-/**
- * Obtain a public key from a "peer". Used e.g. to obtain
- * a merchant's public key to use backend's API.
- *
- * @param cmd command offering the key.
- * @param index (typically zero) which key to return if there
- * are multiple on offer.
- * @param[out] pub set to the key coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_merchant_pub
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_MerchantPublicKeyP **pub)
-{
- return cmd->traits (cmd->cls,
- (const void **) pub,
- TALER_TESTING_TRAIT_MERCHANT_PUB,
- index);
-}
-
-
-/**
- * Offer public key.
- *
- * @param index (typically zero) which key to return if there
- * are multiple on offer. NOTE: if one key is offered, it
- * is mandatory to set this as zero.
- * @param pub which object should be returned.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_merchant_pub (unsigned int index,
- const struct
- TALER_MerchantPublicKeyP *pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_MERCHANT_PUB,
- .ptr = (const void *) pub
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_merchant_key.c */
diff --git a/src/testing/testing_api_trait_number.c b/src/testing/testing_api_trait_number.c
deleted file mode 100644
index ed25593ef..000000000
--- a/src/testing/testing_api_trait_number.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_number.c
- * @brief traits to offer numbers
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_UINT "uint"
-#define TALER_TESTING_TRAIT_UINT32 "uint-32"
-#define TALER_TESTING_TRAIT_UINT64 "uint-64"
-#define TALER_TESTING_TRAIT_INT64 "int-64"
-#define TALER_TESTING_TRAIT_BANK_ROW "bank-transaction-row"
-
-
-/**
- * Obtain a number from @a cmd.
- *
- * @param cmd command to extract the number from.
- * @param index the number's index number.
- * @param[out] n set to the number coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_uint (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const unsigned int **n)
-{
- return cmd->traits (cmd->cls,
- (const void **) n,
- TALER_TESTING_TRAIT_UINT,
- index);
-}
-
-
-/**
- * Offer a number.
- *
- * @param index the number's index number.
- * @param n the number to offer.
- * @return #GNUNET_OK on success.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_uint (unsigned int index,
- const unsigned int *n)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_UINT,
- .ptr = (const void *) n
- };
- return ret;
-}
-
-
-/**
- * Obtain a "number" value from @a cmd, 32-bit version.
- *
- * @param cmd command to extract the number from.
- * @param index the number's index number.
- * @param[out] n set to the number coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_uint32 (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const uint32_t **n)
-{
- return cmd->traits (cmd->cls,
- (const void **) n,
- TALER_TESTING_TRAIT_UINT32,
- index);
-}
-
-
-/**
- * Offer number trait, 32-bit version.
- *
- * @param index the number's index number.
- * @param n number to offer.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_uint32 (unsigned int index,
- const uint32_t *n)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_UINT32,
- .ptr = (const void *) n
- };
- return ret;
-}
-
-
-/**
- * Obtain a "number" value from @a cmd, 64-bit version.
- *
- * @param cmd command to extract the number from.
- * @param index the number's index number.
- * @param[out] n set to the number coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_uint64 (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const uint64_t **n)
-{
- return cmd->traits (cmd->cls,
- (const void **) n,
- TALER_TESTING_TRAIT_UINT64,
- index);
-}
-
-
-/**
- * Offer number trait, 64-bit version.
- *
- * @param index the number's index number.
- * @param n number to offer.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_uint64 (unsigned int index,
- const uint64_t *n)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_UINT64,
- .ptr = (const void *) n
- };
- return ret;
-}
-
-
-/**
- * Obtain a "number" value from @a cmd, 64-bit signed version.
- *
- * @param cmd command to extract the number from.
- * @param index the number's index number.
- * @param[out] n set to the number coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_int64 (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const int64_t **n)
-{
- return cmd->traits (cmd->cls,
- (const void **) n,
- TALER_TESTING_TRAIT_INT64,
- index);
-}
-
-
-/**
- * Offer number trait, 64-bit signed version.
- *
- * @param index the number's index number.
- * @param n number to offer.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_int64 (unsigned int index,
- const int64_t *n)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_INT64,
- .ptr = (const void *) n
- };
- return ret;
-}
-
-
-/**
- * Obtain a bank transaction row value from @a cmd.
- *
- * @param cmd command to extract the number from.
- * @param[out] row set to the number coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_bank_row (const struct TALER_TESTING_Command *cmd,
- const uint64_t **row)
-{
- return cmd->traits (cmd->cls,
- (const void **) row,
- TALER_TESTING_TRAIT_BANK_ROW,
- 0);
-}
-
-
-/**
- * Offer bank transaction row trait.
- *
- * @param row number to offer.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_bank_row (const uint64_t *row)
-{
- struct TALER_TESTING_Trait ret = {
- .index = 0,
- .trait_name = TALER_TESTING_TRAIT_BANK_ROW,
- .ptr = (const void *) row
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_number.c */
diff --git a/src/testing/testing_api_trait_process.c b/src/testing/testing_api_trait_process.c
deleted file mode 100644
index 3d2af31fd..000000000
--- a/src/testing/testing_api_trait_process.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3,
- or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty
- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_trait_process.c
- * @brief trait offering process handles.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_PROCESS "process"
-
-
-/**
- * Obtain location where a command stores a pointer to a process.
- *
- * @param cmd command to extract trait from.
- * @param index which process to pick if @a cmd
- * has multiple on offer.
- * @param[out] processp set to the address of the pointer to the
- * process.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_process
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- struct GNUNET_OS_Process ***processp)
-{
- return cmd->traits (cmd->cls,
- (const void **) processp,
- TALER_TESTING_TRAIT_PROCESS,
- index);
-}
-
-
-/**
- * Offer location where a command stores a pointer to a process.
- *
- * @param index offered location index number, in case there are
- * multiple on offer.
- * @param processp process location to offer.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_process
- (unsigned int index,
- struct GNUNET_OS_Process **processp)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_PROCESS,
- .ptr = (const void *) processp
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_process.c */
diff --git a/src/testing/testing_api_trait_reserve_history.c b/src/testing/testing_api_trait_reserve_history.c
deleted file mode 100644
index b458dbd66..000000000
--- a/src/testing/testing_api_trait_reserve_history.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_reserve_history.c
- * @brief implements reserve hostry trait
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_RESERVE_HISTORY \
- "reserve-history-entry"
-
-
-/**
- * Obtain a reserve history entry from a @a cmd.
- *
- * @param cmd command to extract the reserve history from.
- * @param index reserve history's index number.
- * @param[out] rhp set to the reserve history.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_reserve_history (
- const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_EXCHANGE_ReserveHistory **rhp)
-{
- return cmd->traits (cmd->cls,
- (const void **) rhp,
- TALER_TESTING_TRAIT_RESERVE_HISTORY,
- index);
-}
-
-
-/**
- * Offer a reserve history entry.
- *
- * @param index reserve pubs's index number.
- * @param rh reserve history entry to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_reserve_history (
- unsigned int index,
- const struct TALER_EXCHANGE_ReserveHistory *rh)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_RESERVE_HISTORY,
- .ptr = (const void *) rh
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_reserve_history.c */
diff --git a/src/testing/testing_api_trait_reserve_priv.c b/src/testing/testing_api_trait_reserve_priv.c
deleted file mode 100644
index f4a4ef500..000000000
--- a/src/testing/testing_api_trait_reserve_priv.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_reserve_priv.c
- * @brief implements reserve private key trait
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY \
- "reserve-private-key"
-
-/**
- * Obtain a reserve private key from a @a cmd.
- *
- * @param cmd command to extract the reserve priv from.
- * @param index reserve priv's index number.
- * @param[out] reserve_priv set to the reserve priv.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_reserve_priv
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ReservePrivateKeyP **reserve_priv)
-{
- return cmd->traits (cmd->cls,
- (const void **) reserve_priv,
- TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
- index);
-}
-
-
-/**
- * Offer a reserve private key.
- *
- * @param index reserve priv's index number.
- * @param reserve_priv reserve private key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_reserve_priv
- (unsigned int index,
- const struct TALER_ReservePrivateKeyP *reserve_priv)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
- .ptr = (const void *) reserve_priv
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_reserve_priv.c */
diff --git a/src/testing/testing_api_trait_reserve_pub.c b/src/testing/testing_api_trait_reserve_pub.c
deleted file mode 100644
index 743a10e96..000000000
--- a/src/testing/testing_api_trait_reserve_pub.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_reserve_pub.c
- * @brief implements reserve public key trait
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY \
- "reserve-public-key"
-
-/**
- * Obtain a reserve public key from a @a cmd.
- *
- * @param cmd command to extract the reserve pub from.
- * @param index reserve pub's index number.
- * @param[out] reserve_pub set to the reserve pub.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_reserve_pub
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ReservePublicKeyP **reserve_pub)
-{
- if (NULL == cmd->traits)
- return GNUNET_SYSERR;
- return cmd->traits (cmd->cls,
- (const void **) reserve_pub,
- TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
- index);
-}
-
-
-/**
- * Offer a reserve public key.
- *
- * @param index reserve pub's index number.
- * @param reserve_pub reserve public key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_reserve_pub
- (unsigned int index,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
- .ptr = (const void *) reserve_pub
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_reserve_pub.c */
diff --git a/src/testing/testing_api_trait_string.c b/src/testing/testing_api_trait_string.c
deleted file mode 100644
index b102265e8..000000000
--- a/src/testing/testing_api_trait_string.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_string.c
- * @brief offers strings traits.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-/**
- * Some string. Avoid, use something more precise!
- */
-#define TALER_TESTING_TRAIT_STRING "string"
-
-/**
- * An HTTP-URL.
- */
-#define TALER_TESTING_TRAIT_URL "url"
-
-/**
- * A PAYTO-URL.
- */
-#define TALER_TESTING_TRAIT_PAYTO "payto"
-
-/**
- * String identifying an order.
- */
-#define TALER_TESTING_TRAIT_ORDER_ID "order-id"
-
-
-/**
- * Obtain a string from @a cmd.
- *
- * @param cmd command to extract the subject from.
- * @param index index number associated with the transfer
- * subject to offer.
- * @param[out] s where to write the offered
- * string
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_string (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const char **s)
-{
- return cmd->traits (cmd->cls,
- (const void **) s,
- TALER_TESTING_TRAIT_STRING,
- index);
-}
-
-
-/**
- * Offer string.
- *
- * @param index index number associated with the transfer
- * subject being offered.
- * @param s transfer subject to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_string (unsigned int index,
- const char *s)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_STRING,
- .ptr = (const void *) s
- };
- return ret;
-}
-
-
-/**
- * Obtain a HTTP url from @a cmd.
- *
- * @param cmd command to extract the url from.
- * @param index which url is to be picked, in case
- * multiple are offered.
- * @param[out] url where to write the url.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_url (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const char **url)
-{
- return cmd->traits (cmd->cls,
- (const void **) url,
- TALER_TESTING_TRAIT_URL,
- index);
-}
-
-
-/**
- * Offer HTTP url in a trait.
- *
- * @param index which url is to be picked,
- * in case multiple are offered.
- * @param url the url to offer.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_url (unsigned int index,
- const char *url)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_URL,
- .ptr = (const void *) url
- };
-
- GNUNET_assert ( (NULL == url) ||
- (0 != strncasecmp (url,
- "payto://",
- strlen ("payto://"))) );
- return ret;
-}
-
-
-/**
- * Obtain a order id from @a cmd.
- *
- * @param cmd command to extract the order id from.
- * @param index which order id is to be picked, in case
- * multiple are offered.
- * @param[out] order_id where to write the order id.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_order_id (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const char **order_id)
-{
- return cmd->traits (cmd->cls,
- (const void **) order_id,
- TALER_TESTING_TRAIT_ORDER_ID,
- index);
-}
-
-
-/**
- * Offer order id in a trait.
- *
- * @param index which order id is to be offered,
- * in case multiple are offered.
- * @param order_id the order id to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_order_id (unsigned int index,
- const char *order_id)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_ORDER_ID,
- .ptr = (const void *) order_id
- };
- return ret;
-}
-
-
-/**
- * Obtain a PAYTO-url from @a cmd.
- *
- * @param cmd command to extract the url from.
- * @param pt which url is to be picked, in case
- * multiple are offered.
- * @param[out] url where to write the url.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_payto (const struct TALER_TESTING_Command *cmd,
- enum TALER_TESTING_PaytoType pt,
- const char **url)
-{
- return cmd->traits (cmd->cls,
- (const void **) url,
- TALER_TESTING_TRAIT_PAYTO,
- (unsigned int) pt);
-}
-
-
-/**
- * Offer a "payto" URL reference.
- *
- * @param pt which reference is to be offered,
- * in case multiple are offered.
- * @param payto_uri the payto URI
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_payto (enum TALER_TESTING_PaytoType pt,
- const char *payto_uri)
-{
- struct TALER_TESTING_Trait ret = {
- .index = (unsigned int) pt,
- .trait_name = TALER_TESTING_TRAIT_PAYTO,
- .ptr = (const void *) payto_uri,
- };
-
- GNUNET_assert (0 == strncasecmp (payto_uri,
- "payto://",
- strlen ("payto://")));
- return ret;
-}
-
-
-/* end of testing_api_trait_string.c */
diff --git a/src/testing/testing_api_trait_time.c b/src/testing/testing_api_trait_time.c
deleted file mode 100644
index 207246bed..000000000
--- a/src/testing/testing_api_trait_time.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_trait_time.c
- * @brief traits to offer time stamps.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_TIME_ABS "time-abs"
-#define TALER_TESTING_TRAIT_TIME_REL "time-rel"
-
-/**
- * Obtain a absolute time from @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index which time stamp to pick if
- * @a cmd has multiple on offer.
- * @param[out] time set to the wanted WTID.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_absolute_time
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct GNUNET_TIME_Absolute **time)
-{
- return cmd->traits (cmd->cls,
- (const void **) time,
- TALER_TESTING_TRAIT_TIME_ABS,
- index);
-}
-
-
-/**
- * Offer a absolute time.
- *
- * @param index associate the object with this index
- * @param time which object should be returned
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_absolute_time
- (unsigned int index,
- const struct GNUNET_TIME_Absolute *time)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_TIME_ABS,
- .ptr = (const void *) time
- };
- return ret;
-}
-
-
-/**
- * Obtain a relative time from @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index which time to pick if
- * @a cmd has multiple on offer.
- * @param[out] time set to the wanted WTID.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_relative_time (
- const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct GNUNET_TIME_Relative **time)
-{
- return cmd->traits (cmd->cls,
- (const void **) time,
- TALER_TESTING_TRAIT_TIME_REL,
- index);
-}
-
-
-/**
- * Offer a relative time.
- *
- * @param index associate the object with this index
- * @param time which object should be returned
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_relative_time (
- unsigned int index,
- const struct GNUNET_TIME_Relative *time)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_TIME_REL,
- .ptr = (const void *) time
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_time.c */
diff --git a/src/testing/testing_api_trait_uuid.c b/src/testing/testing_api_trait_uuid.c
deleted file mode 100644
index 4d5003ecd..000000000
--- a/src/testing/testing_api_trait_uuid.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2020 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 3, or
- (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-/**
- * @file testing/testing_api_trait_uuid.c
- * @brief offer any trait that is passed over as a uuid.
- * @author Jonathan Buchanan
- */
-#include "platform.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_testing_lib.h"
-
-
-#define TALER_TESTING_TRAIT_UUID "uuid"
-#define TALER_TESTING_TRAIT_CLAIM_TOKEN "claim_token"
-
-
-/**
- * Obtain a uuid from @a cmd.
- *
- * @param cmd command to extract the uuid from.
- * @param index which amount to pick if @a cmd has multiple
- * on offer
- * @param[out] uuid where to write the uuid.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_uuid (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- struct GNUNET_Uuid **uuid)
-{
- return cmd->traits (cmd->cls,
- (const void **) uuid,
- TALER_TESTING_TRAIT_UUID,
- index);
-}
-
-
-/**
- * Offer a uuid in a trait.
- *
- * @param index which uuid to offer, in case there are
- * multiple available.
- * @param uuid the uuid to offer.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_uuid (unsigned int index,
- const struct GNUNET_Uuid *uuid)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_UUID,
- .ptr = (const void *) uuid
- };
- return ret;
-}
-
-
-/**
- * Obtain a claim token from @a cmd.
- *
- * @param cmd command to extract the token from.
- * @param index which amount to pick if @a cmd has multiple
- * on offer
- * @param[out] ct where to write the token.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_claim_token (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ClaimTokenP **ct)
-{
- return cmd->traits (cmd->cls,
- (const void **) ct,
- TALER_TESTING_TRAIT_CLAIM_TOKEN,
- index);
-}
-
-
-/**
- * Offer a claim token in a trait.
- *
- * @param index which token to offer, in case there are
- * multiple available.
- * @param ct the token to offer.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_claim_token (unsigned int index,
- const struct TALER_ClaimTokenP *ct)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_CLAIM_TOKEN,
- .ptr = (const void *) ct
- };
- return ret;
-}
diff --git a/src/testing/testing_api_trait_wtid.c b/src/testing/testing_api_trait_wtid.c
deleted file mode 100644
index 5c7e7060e..000000000
--- a/src/testing/testing_api_trait_wtid.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
-
- TALER is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with TALER; see the file COPYING. If not, see
- <http://www.gnu.org/licenses/>
-*/
-
-/**
- * @file testing/testing_api_trait_number.c
- * @brief traits to offer numbers
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_WTID "wtid"
-
-/**
- * Obtain a WTID value from @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index which WTID to pick if @a cmd has multiple on
- * offer
- * @param[out] wtid set to the wanted WTID.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_wtid
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_WireTransferIdentifierRawP **wtid)
-{
- return cmd->traits (cmd->cls,
- (const void **) wtid,
- TALER_TESTING_TRAIT_WTID,
- index);
-}
-
-
-/**
- * Offer a WTID.
- *
- * @param index associate the object with this index
- * @param wtid which object should be returned
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_wtid
- (unsigned int index,
- const struct TALER_WireTransferIdentifierRawP *wtid)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_WTID,
- .ptr = (const void *) wtid
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_number.c */
diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c
index 6d623af7a..799ae6718 100644
--- a/src/testing/testing_api_traits.c
+++ b/src/testing/testing_api_traits.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
+ Copyright (C) 2018, 2021 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
@@ -29,6 +29,11 @@
#include "taler_testing_lib.h"
+TALER_TESTING_SIMPLE_TRAITS (TALER_TESTING_MAKE_IMPL_SIMPLE_TRAIT)
+
+TALER_TESTING_INDEXED_TRAITS (TALER_TESTING_MAKE_IMPL_INDEXED_TRAIT)
+
+
/**
* End a trait array. Usually, commands offer several traits,
* and put them in arrays.
@@ -46,16 +51,7 @@ TALER_TESTING_trait_end ()
}
-/**
- * Pick the chosen trait from the traits array.
- *
- * @param traits the traits array.
- * @param ret where to store the result.
- * @param trait type of the trait to extract.
- * @param index index number of the object to extract.
- * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
- */
-int
+enum GNUNET_GenericReturnValue
TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
const void **ret,
const char *trait,
@@ -63,19 +59,75 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
{
for (unsigned int i = 0; NULL != traits[i].trait_name; i++)
{
- if ( (0 == strcmp (trait, traits[i].trait_name)) &&
+ if ( (0 == strcmp (trait,
+ traits[i].trait_name)) &&
(index == traits[i].index) )
{
*ret = (void *) traits[i].ptr;
return GNUNET_OK;
}
}
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Trait %s/%u not found.\n",
- trait, index);
-
+ trait,
+ index);
return GNUNET_SYSERR;
}
+const char *
+TALER_TESTING_get_exchange_url (struct TALER_TESTING_Interpreter *is)
+{
+ const char *exchange_url;
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd
+ = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_exchange_url (exchange_cmd,
+ &exchange_url))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return NULL;
+ }
+ return exchange_url;
+}
+
+
+struct TALER_EXCHANGE_Keys *
+TALER_TESTING_get_keys (
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_EXCHANGE_Keys *keys;
+ const struct TALER_TESTING_Command *exchange_cmd;
+
+ exchange_cmd
+ = TALER_TESTING_interpreter_get_command (is,
+ "exchange");
+ if (NULL == exchange_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return NULL;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_keys (exchange_cmd,
+ &keys))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return NULL;
+ }
+ return keys;
+}
+
+
/* end of testing_api_traits.c */
diff --git a/src/testing/testing_api_twister_helpers.c b/src/testing/testing_api_twister_helpers.c
index 935d8bcc1..68fbf0082 100644
--- a/src/testing/testing_api_twister_helpers.c
+++ b/src/testing/testing_api_twister_helpers.c
@@ -116,7 +116,9 @@ TALER_TWISTER_run_twister (const char *config_filename)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not start the taler-twister client\n");
- GNUNET_OS_process_kill (proc, SIGTERM);
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (proc,
+ SIGTERM));
GNUNET_OS_process_wait (proc);
GNUNET_OS_process_destroy (proc);
TWISTER_FAIL ();
@@ -129,7 +131,9 @@ TALER_TWISTER_run_twister (const char *config_filename)
&code))
{
GNUNET_OS_process_destroy (client_proc);
- GNUNET_OS_process_kill (proc, SIGTERM);
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (proc,
+ SIGTERM));
GNUNET_OS_process_wait (proc);
GNUNET_OS_process_destroy (proc);
TWISTER_FAIL ();
@@ -140,7 +144,9 @@ TALER_TWISTER_run_twister (const char *config_filename)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to check twister works.\n");
GNUNET_OS_process_destroy (client_proc);
- GNUNET_OS_process_kill (proc, SIGTERM);
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (proc,
+ SIGTERM));
GNUNET_OS_process_wait (proc);
GNUNET_OS_process_destroy (proc);
TWISTER_FAIL ();
@@ -151,7 +157,9 @@ TALER_TWISTER_run_twister (const char *config_filename)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected error running `taler-twister'!\n");
GNUNET_OS_process_destroy (client_proc);
- GNUNET_OS_process_kill (proc, SIGTERM);
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (proc,
+ SIGTERM));
GNUNET_OS_process_wait (proc);
GNUNET_OS_process_destroy (proc);
TWISTER_FAIL ();
diff --git a/src/testing/valgrind.h b/src/testing/valgrind.h
new file mode 100644
index 000000000..eaf1632e1
--- /dev/null
+++ b/src/testing/valgrind.h
@@ -0,0 +1,7165 @@
+/* -*- c -*-
+ ----------------------------------------------------------------
+
+ Notice that the following BSD-style license applies to this one
+ file (valgrind.h) only. The rest of Valgrind is licensed under the
+ terms of the GNU General Public License, version 2, unless
+ otherwise indicated. See the COPYING file in the source
+ distribution for details.
+
+ ----------------------------------------------------------------
+
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2017 Julian Seward. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ----------------------------------------------------------------
+
+ Notice that the above BSD-style license applies to this one file
+ (valgrind.h) only. The entire rest of Valgrind is licensed under
+ the terms of the GNU General Public License, version 2. See the
+ COPYING file in the source distribution for details.
+
+ ----------------------------------------------------------------
+*/
+
+
+/* This file is for inclusion into client (your!) code.
+
+ You can use these macros to manipulate and query Valgrind's
+ execution inside your own programs.
+
+ The resulting executables will still run without Valgrind, just a
+ little bit more slowly than they otherwise would, but otherwise
+ unchanged. When not running on valgrind, each client request
+ consumes very few (eg. 7) instructions, so the resulting performance
+ loss is negligible unless you plan to execute client requests
+ millions of times per second. Nevertheless, if that is still a
+ problem, you can compile with the NVALGRIND symbol defined (gcc
+ -DNVALGRIND) so that client requests are not even compiled in. */
+
+#ifndef __VALGRIND_H
+#define __VALGRIND_H
+
+
+/* ------------------------------------------------------------------ */
+/* VERSION NUMBER OF VALGRIND */
+/* ------------------------------------------------------------------ */
+
+/* Specify Valgrind's version number, so that user code can
+ conditionally compile based on our version number. Note that these
+ were introduced at version 3.6 and so do not exist in version 3.5
+ or earlier. The recommended way to use them to check for "version
+ X.Y or later" is (eg)
+
+#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \
+ && (__VALGRIND_MAJOR__ > 3 \
+ || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
+*/
+#define __VALGRIND_MAJOR__ 3
+#define __VALGRIND_MINOR__ 19
+
+
+#include <stdarg.h>
+
+/* Nb: this file might be included in a file compiled with -ansi. So
+ we can't use C++ style "//" comments nor the "asm" keyword (instead
+ use "__asm__"). */
+
+/* Derive some tags indicating what the target platform is. Note
+ that in this file we're using the compiler's CPP symbols for
+ identifying architectures, which are different to the ones we use
+ within the rest of Valgrind. Note, __powerpc__ is active for both
+ 32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+ latter (on Linux, that is).
+
+ Misc note: how to find out what's predefined in gcc by default:
+ gcc -Wp,-dM somefile.c
+*/
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+#undef PLAT_x86_freebsd
+#undef PLAT_amd64_freebsd
+#undef PLAT_x86_win32
+#undef PLAT_amd64_win64
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64be_linux
+#undef PLAT_ppc64le_linux
+#undef PLAT_arm_linux
+#undef PLAT_arm64_linux
+#undef PLAT_s390x_linux
+#undef PLAT_mips32_linux
+#undef PLAT_mips64_linux
+#undef PLAT_nanomips_linux
+#undef PLAT_x86_solaris
+#undef PLAT_amd64_solaris
+
+
+#if defined(__APPLE__) && defined(__i386__)
+# define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+# define PLAT_amd64_darwin 1
+#elif defined(__FreeBSD__) && defined(__i386__)
+# define PLAT_x86_freebsd 1
+#elif defined(__FreeBSD__) && defined(__amd64__)
+# define PLAT_amd64_freebsd 1
+#elif (defined(__MINGW32__) && defined(__i386__)) \
+ || defined(__CYGWIN32__) \
+ || (defined(_WIN32) && defined(_M_IX86))
+# define PLAT_x86_win32 1
+#elif (defined(__MINGW32__) && defined(__x86_64__)) \
+ || (defined(_WIN32) && defined(_M_X64))
+/* __MINGW32__ and _WIN32 are defined in 64 bit mode as well. */
+# define PLAT_amd64_win64 1
+#elif defined(__linux__) && defined(__i386__)
+# define PLAT_x86_linux 1
+#elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__)
+# define PLAT_amd64_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
+# define PLAT_ppc32_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2
+/* Big Endian uses ELF version 1 */
+# define PLAT_ppc64be_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2
+/* Little Endian uses ELF version 2 */
+# define PLAT_ppc64le_linux 1
+#elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__)
+# define PLAT_arm_linux 1
+#elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__)
+# define PLAT_arm64_linux 1
+#elif defined(__linux__) && defined(__s390__) && defined(__s390x__)
+# define PLAT_s390x_linux 1
+#elif defined(__linux__) && defined(__mips__) && (__mips==64)
+# define PLAT_mips64_linux 1
+#elif defined(__linux__) && defined(__mips__) && (__mips==32)
+# define PLAT_mips32_linux 1
+#elif defined(__linux__) && defined(__nanomips__)
+# define PLAT_nanomips_linux 1
+#elif defined(__sun) && defined(__i386__)
+# define PLAT_x86_solaris 1
+#elif defined(__sun) && defined(__x86_64__)
+# define PLAT_amd64_solaris 1
+#else
+/* If we're not compiling for our target platform, don't generate
+ any inline asms. */
+# if !defined(NVALGRIND)
+# define NVALGRIND 1
+# endif
+#endif
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */
+/* in here of use to end-users -- skip to the next section. */
+/* ------------------------------------------------------------------ */
+
+/*
+ * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client
+ * request. Accepts both pointers and integers as arguments.
+ *
+ * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind
+ * client request that does not return a value.
+
+ * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind
+ * client request and whose value equals the client request result. Accepts
+ * both pointers and integers as arguments. Note that such calls are not
+ * necessarily pure functions -- they may have side effects.
+ */
+
+#define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \
+ _zzq_request, _zzq_arg1, _zzq_arg2, \
+ _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \
+ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \
+ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0)
+
+#define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \
+ _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
+ (_zzq_request), (_zzq_arg1), (_zzq_arg2), \
+ (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0)
+
+#if defined(NVALGRIND)
+
+/* Define NVALGRIND to completely remove the Valgrind magic sequence
+ from the compiled code (analogous to NDEBUG's effects on
+ assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ (_zzq_default)
+
+#else /* ! NVALGRIND */
+
+/* The following defines the magic code sequences which the JITter
+ spots and handles magically. Don't look too closely at them as
+ they will rot your brain.
+
+ The assembly code sequences for all architectures is in this one
+ file. This is because this file must be stand-alone, and we don't
+ want to have multiple files.
+
+ For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+ value gets put in the return slot, so that everything works when
+ this is executed not under Valgrind. Args are passed in a memory
+ block, and so there's no intrinsic limit to the number that could
+ be passed, but it's currently five.
+
+ The macro args are:
+ _zzq_rlval result lvalue
+ _zzq_default default value (result returned when running on real CPU)
+ _zzq_request request code
+ _zzq_arg1..5 request params
+
+ The other two macros are used to support function wrapping, and are
+ a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the
+ guest's NRADDR pseudo-register and whatever other information is
+ needed to safely run the call original from the wrapper: on
+ ppc64-linux, the R2 value at the divert point is also needed. This
+ information is abstracted into a user-visible type, OrigFn.
+
+ VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
+ guest, but guarantees that the branch instruction will not be
+ redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
+ branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a
+ complete inline asm, since it needs to be combined with more magic
+ inline asm stuff to be useful.
+*/
+
+/* ----------------- x86-{linux,darwin,solaris} ---------------- */
+
+#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \
+ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \
+ || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "roll $3, %%edi ; roll $13, %%edi\n\t" \
+ "roll $29, %%edi ; roll $19, %%edi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EDX = client_request ( %EAX ) */ \
+ "xchgl %%ebx,%%ebx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EAX = guest_NRADDR */ \
+ "xchgl %%ecx,%%ecx" \
+ : "=a" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_EAX \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir *%EAX */ \
+ "xchgl %%edx,%%edx\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "xchgl %%edi,%%edi\n\t" \
+ : : : "cc", "memory" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__)
+ || PLAT_x86_solaris */
+
+/* ------------------------- x86-Win32 ------------------------- */
+
+#if defined(PLAT_x86_win32) && !defined(__GNUC__)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#if defined(_MSC_VER)
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ __asm rol edi, 3 __asm rol edi, 13 \
+ __asm rol edi, 29 __asm rol edi, 19
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \
+ (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \
+ (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \
+ (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5))
+
+static __inline uintptr_t
+valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request,
+ uintptr_t _zzq_arg1, uintptr_t _zzq_arg2,
+ uintptr_t _zzq_arg3, uintptr_t _zzq_arg4,
+ uintptr_t _zzq_arg5)
+{
+ volatile uintptr_t _zzq_args[6];
+ volatile unsigned int _zzq_result;
+ _zzq_args[0] = (uintptr_t)(_zzq_request);
+ _zzq_args[1] = (uintptr_t)(_zzq_arg1);
+ _zzq_args[2] = (uintptr_t)(_zzq_arg2);
+ _zzq_args[3] = (uintptr_t)(_zzq_arg3);
+ _zzq_args[4] = (uintptr_t)(_zzq_arg4);
+ _zzq_args[5] = (uintptr_t)(_zzq_arg5);
+ __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default
+ __SPECIAL_INSTRUCTION_PREAMBLE
+ /* %EDX = client_request ( %EAX ) */
+ __asm xchg ebx,ebx
+ __asm mov _zzq_result, edx
+ }
+ return _zzq_result;
+}
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned int __addr; \
+ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EAX = guest_NRADDR */ \
+ __asm xchg ecx,ecx \
+ __asm mov __addr, eax \
+ } \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_EAX ERROR
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \
+ __asm xchg edi,edi \
+ } \
+ } while (0)
+
+#else
+#error Unsupported compiler.
+#endif
+
+#endif /* PLAT_x86_win32 */
+
+/* ----------------- amd64-{linux,darwin,solaris} --------------- */
+
+#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \
+ || defined(PLAT_amd64_solaris) \
+ || defined(PLAT_amd64_freebsd) \
+ || (defined(PLAT_amd64_win64) && defined(__GNUC__))
+
+typedef
+ struct {
+ unsigned long int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \
+ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({ volatile unsigned long int _zzq_args[6]; \
+ volatile unsigned long int _zzq_result; \
+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %RDX = client_request ( %RAX ) */ \
+ "xchgq %%rbx,%%rbx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %RAX = guest_NRADDR */ \
+ "xchgq %%rcx,%%rcx" \
+ : "=a" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_RAX \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir *%RAX */ \
+ "xchgq %%rdx,%%rdx\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "xchgq %%rdi,%%rdi\n\t" \
+ : : : "cc", "memory" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */
+
+/* ------------------------- amd64-Win64 ------------------------- */
+
+#if defined(PLAT_amd64_win64) && !defined(__GNUC__)
+
+#error Unsupported compiler.
+
+#endif /* PLAT_amd64_win64 */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \
+ "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ __extension__ \
+ ({ unsigned int _zzq_args[6]; \
+ unsigned int _zzq_result; \
+ unsigned int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 3,%1\n\t" /*default*/ \
+ "mr 4,%2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" /*result*/ \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_default), "b" (_zzq_ptr) \
+ : "cc", "memory", "r3", "r4"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "or 5,5,5\n\t" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64be_linux)
+
+typedef
+ struct {
+ unsigned long int nraddr; /* where's the code? */
+ unsigned long int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
+ "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ __extension__ \
+ ({ unsigned long int _zzq_args[6]; \
+ unsigned long int _zzq_result; \
+ unsigned long int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 3,%1\n\t" /*default*/ \
+ "mr 4,%2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" /*result*/ \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_default), "b" (_zzq_ptr) \
+ : "cc", "memory", "r3", "r4"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "or 5,5,5\n\t" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_ppc64be_linux */
+
+#if defined(PLAT_ppc64le_linux)
+
+typedef
+ struct {
+ unsigned long int nraddr; /* where's the code? */
+ unsigned long int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
+ "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ __extension__ \
+ ({ unsigned long int _zzq_args[6]; \
+ unsigned long int _zzq_result; \
+ unsigned long int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 3,%1\n\t" /*default*/ \
+ "mr 4,%2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" /*result*/ \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_default), "b" (_zzq_ptr) \
+ : "cc", "memory", "r3", "r4"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R12 */ \
+ "or 3,3,3\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "or 5,5,5\n\t" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_ppc64le_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \
+ "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ __extension__ \
+ ({volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile("mov r3, %1\n\t" /*default*/ \
+ "mov r4, %2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* R3 = client_request ( R4 ) */ \
+ "orr r10, r10, r10\n\t" \
+ "mov %0, r3" /*result*/ \
+ : "=r" (_zzq_result) \
+ : "r" (_zzq_default), "r" (&_zzq_args[0]) \
+ : "cc","memory", "r3", "r4"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* R3 = guest_NRADDR */ \
+ "orr r11, r11, r11\n\t" \
+ "mov %0, r3" \
+ : "=r" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R4 */ \
+ "orr r12, r12, r12\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "orr r9, r9, r9\n\t" \
+ : : : "cc", "memory" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ arm64-linux ------------------------- */
+
+#if defined(PLAT_arm64_linux)
+
+typedef
+ struct {
+ unsigned long int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \
+ "ror x12, x12, #51 ; ror x12, x12, #61 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ __extension__ \
+ ({volatile unsigned long int _zzq_args[6]; \
+ volatile unsigned long int _zzq_result; \
+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
+ __asm__ volatile("mov x3, %1\n\t" /*default*/ \
+ "mov x4, %2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* X3 = client_request ( X4 ) */ \
+ "orr x10, x10, x10\n\t" \
+ "mov %0, x3" /*result*/ \
+ : "=r" (_zzq_result) \
+ : "r" ((unsigned long int)(_zzq_default)), \
+ "r" (&_zzq_args[0]) \
+ : "cc","memory", "x3", "x4"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* X3 = guest_NRADDR */ \
+ "orr x11, x11, x11\n\t" \
+ "mov %0, x3" \
+ : "=r" (__addr) \
+ : \
+ : "cc", "memory", "x3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir X8 */ \
+ "orr x12, x12, x12\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "orr x9, x9, x9\n\t" \
+ : : : "cc", "memory" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_arm64_linux */
+
+/* ------------------------ s390x-linux ------------------------ */
+
+#if defined(PLAT_s390x_linux)
+
+typedef
+ struct {
+ unsigned long int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+/* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific
+ * code. This detection is implemented in platform specific toIR.c
+ * (e.g. VEX/priv/guest_s390_decoder.c).
+ */
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "lr 15,15\n\t" \
+ "lr 1,1\n\t" \
+ "lr 2,2\n\t" \
+ "lr 3,3\n\t"
+
+#define __CLIENT_REQUEST_CODE "lr 2,2\n\t"
+#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t"
+#define __CALL_NO_REDIR_CODE "lr 4,4\n\t"
+#define __VEX_INJECT_IR_CODE "lr 5,5\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({volatile unsigned long int _zzq_args[6]; \
+ volatile unsigned long int _zzq_result; \
+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
+ __asm__ volatile(/* r2 = args */ \
+ "lgr 2,%1\n\t" \
+ /* r3 = default */ \
+ "lgr 3,%2\n\t" \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ __CLIENT_REQUEST_CODE \
+ /* results = r3 */ \
+ "lgr %0, 3\n\t" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), \
+ "0" ((unsigned long int)_zzq_default) \
+ : "cc", "2", "3", "memory" \
+ ); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ __GET_NR_CONTEXT_CODE \
+ "lgr %0, 3\n\t" \
+ : "=a" (__addr) \
+ : \
+ : "cc", "3", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_R1 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ __CALL_NO_REDIR_CODE
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ __VEX_INJECT_IR_CODE); \
+ } while (0)
+
+#endif /* PLAT_s390x_linux */
+
+/* ------------------------- mips32-linux ---------------- */
+
+#if defined(PLAT_mips32_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+/* .word 0x342
+ * .word 0x742
+ * .word 0xC2
+ * .word 0x4C2*/
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "srl $0, $0, 13\n\t" \
+ "srl $0, $0, 29\n\t" \
+ "srl $0, $0, 3\n\t" \
+ "srl $0, $0, 19\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({ volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile("move $11, %1\n\t" /*default*/ \
+ "move $12, %2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* T3 = client_request ( T4 ) */ \
+ "or $13, $13, $13\n\t" \
+ "move %0, $11\n\t" /*result*/ \
+ : "=r" (_zzq_result) \
+ : "r" (_zzq_default), "r" (&_zzq_args[0]) \
+ : "$11", "$12", "memory"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %t9 = guest_NRADDR */ \
+ "or $14, $14, $14\n\t" \
+ "move %0, $11" /*result*/ \
+ : "=r" (__addr) \
+ : \
+ : "$11" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_T9 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir *%t9 */ \
+ "or $15, $15, $15\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "or $11, $11, $11\n\t" \
+ ); \
+ } while (0)
+
+
+#endif /* PLAT_mips32_linux */
+
+/* ------------------------- mips64-linux ---------------- */
+
+#if defined(PLAT_mips64_linux)
+
+typedef
+ struct {
+ unsigned long nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+/* dsll $0,$0, 3
+ * dsll $0,$0, 13
+ * dsll $0,$0, 29
+ * dsll $0,$0, 19*/
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \
+ "dsll $0,$0,29 ; dsll $0,$0,19\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({ volatile unsigned long int _zzq_args[6]; \
+ volatile unsigned long int _zzq_result; \
+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
+ __asm__ volatile("move $11, %1\n\t" /*default*/ \
+ "move $12, %2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* $11 = client_request ( $12 ) */ \
+ "or $13, $13, $13\n\t" \
+ "move %0, $11\n\t" /*result*/ \
+ : "=r" (_zzq_result) \
+ : "r" (_zzq_default), "r" (&_zzq_args[0]) \
+ : "$11", "$12", "memory"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* $11 = guest_NRADDR */ \
+ "or $14, $14, $14\n\t" \
+ "move %0, $11" /*result*/ \
+ : "=r" (__addr) \
+ : \
+ : "$11"); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_T9 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir $25 */ \
+ "or $15, $15, $15\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "or $11, $11, $11\n\t" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_mips64_linux */
+
+#if defined(PLAT_nanomips_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+/*
+ 8000 c04d srl zero, zero, 13
+ 8000 c05d srl zero, zero, 29
+ 8000 c043 srl zero, zero, 3
+ 8000 c053 srl zero, zero, 19
+*/
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE "srl[32] $zero, $zero, 13 \n\t" \
+ "srl[32] $zero, $zero, 29 \n\t" \
+ "srl[32] $zero, $zero, 3 \n\t" \
+ "srl[32] $zero, $zero, 19 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ __extension__ \
+ ({ volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile("move $a7, %1\n\t" /* default */ \
+ "move $t0, %2\n\t" /* ptr */ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* $a7 = client_request( $t0 ) */ \
+ "or[32] $t0, $t0, $t0\n\t" \
+ "move %0, $a7\n\t" /* result */ \
+ : "=r" (_zzq_result) \
+ : "r" (_zzq_default), "r" (&_zzq_args[0]) \
+ : "$a7", "$t0", "memory"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* $a7 = guest_NRADDR */ \
+ "or[32] $t1, $t1, $t1\n\t" \
+ "move %0, $a7" /*result*/ \
+ : "=r" (__addr) \
+ : \
+ : "$a7"); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_T9 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir $25 */ \
+ "or[32] $t2, $t2, $t2\n\t"
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "or[32] $t3, $t3, $t3\n\t" \
+ ); \
+ } while (0)
+
+#endif
+/* Insert assembly code for other platforms here... */
+
+#endif /* NVALGRIND */
+
+
+/* ------------------------------------------------------------------ */
+/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */
+/* ugly. It's the least-worst tradeoff I can think of. */
+/* ------------------------------------------------------------------ */
+
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+ guaranteed-no-redirection macros, so as to get from function
+ wrappers to the functions they are wrapping. The whole point is to
+ construct standard call sequences, but to do the call itself with a
+ special no-redirect call pseudo-instruction that the JIT
+ understands and handles specially. This section is long and
+ repetitious, and I can't see a way to make it shorter.
+
+ The naming scheme is as follows:
+
+ CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc}
+
+ 'W' stands for "word" and 'v' for "void". Hence there are
+ different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+ and for each, the possibility of returning a word-typed result, or
+ no result.
+*/
+
+/* Use these to write the name of your wrapper. NOTE: duplicates
+ VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts
+ the default behaviour equivalance class tag "0000" into the name.
+ See pub_tool_redir.h for details -- normally you don't need to
+ think about this, though. */
+
+/* Use an extra level of macroisation so as to ensure the soname/fnname
+ args are fully macro-expanded before pasting them together. */
+#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \
+ VG_CONCAT4(_vgw00000ZU_,soname,_,fnname)
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \
+ VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname)
+
+/* Use this macro from within a wrapper function to collect the
+ context (address and possibly other info) of the original function.
+ Once you have that you can then use it in one of the CALL_FN_
+ macros. The type of the argument _lval is OrigFn. */
+#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval)
+
+/* Also provide end-user facilities for function replacement, rather
+ than wrapping. A replacement function differs from a wrapper in
+ that it has no way to get hold of the original function being
+ called, and hence no way to call onwards to it. In a replacement
+ function, VALGRIND_GET_ORIG_FN always returns zero. */
+
+#define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \
+ VG_CONCAT4(_vgr00000ZU_,soname,_,fnname)
+
+#define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \
+ VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname)
+
+/* Derivatives of the main macros below, for calling functions
+ returning void. */
+
+#define CALL_FN_v_v(fnptr) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_v_W(fnptr, arg1) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
+
+#define CALL_FN_v_WW(fnptr, arg1,arg2) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
+
+#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
+
+#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0)
+
+#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0)
+
+#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0)
+
+#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
+
+/* ----------------- x86-{linux,darwin,solaris} ---------------- */
+
+#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \
+ || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd)
+
+/* These regs are trashed by the hidden call. No need to mention eax
+ as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+/* Macros to save and align the stack before making a function
+ call and restore it afterwards as gcc may not keep the stack
+ pointer aligned if it doesn't realise calls are being made
+ to other functions. */
+
+#define VALGRIND_ALIGN_STACK \
+ "movl %%esp,%%edi\n\t" \
+ "andl $0xfffffff0,%%esp\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "movl %%edi,%%esp\n\t"
+
+/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $12, %%esp\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $8, %%esp\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $4, %%esp\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $12, %%esp\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $8, %%esp\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $4, %%esp\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $12, %%esp\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $8, %%esp\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "subl $4, %%esp\n\t" \
+ "pushl 44(%%eax)\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "pushl 48(%%eax)\n\t" \
+ "pushl 44(%%eax)\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */
+
+/* ---------------- amd64-{linux,darwin,solaris} --------------- */
+
+#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \
+ || defined(PLAT_amd64_solaris) || defined(PLAT_amd64_freebsd)
+
+/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \
+ "rdi", "r8", "r9", "r10", "r11"
+
+/* This is all pretty complex. It's so as to make stack unwinding
+ work reliably. See bug 243270. The basic problem is the sub and
+ add of 128 of %rsp in all of the following macros. If gcc believes
+ the CFA is in %rsp, then unwinding may fail, because what's at the
+ CFA is not what gcc "expected" when it constructs the CFIs for the
+ places where the macros are instantiated.
+
+ But we can't just add a CFI annotation to increase the CFA offset
+ by 128, to match the sub of 128 from %rsp, because we don't know
+ whether gcc has chosen %rsp as the CFA at that point, or whether it
+ has chosen some other register (eg, %rbp). In the latter case,
+ adding a CFI annotation to change the CFA offset is simply wrong.
+
+ So the solution is to get hold of the CFA using
+ __builtin_dwarf_cfa(), put it in a known register, and add a
+ CFI annotation to say what the register is. We choose %rbp for
+ this (perhaps perversely), because:
+
+ (1) %rbp is already subject to unwinding. If a new register was
+ chosen then the unwinder would have to unwind it in all stack
+ traces, which is expensive, and
+
+ (2) %rbp is already subject to precise exception updates in the
+ JIT. If a new register was chosen, we'd have to have precise
+ exceptions for it too, which reduces performance of the
+ generated code.
+
+ However .. one extra complication. We can't just whack the result
+ of __builtin_dwarf_cfa() into %rbp and then add %rbp to the
+ list of trashed registers at the end of the inline assembly
+ fragments; gcc won't allow %rbp to appear in that list. Hence
+ instead we need to stash %rbp in %r15 for the duration of the asm,
+ and say that %r15 is trashed instead. gcc seems happy to go with
+ that.
+
+ Oh .. and this all needs to be conditionalised so that it is
+ unchanged from before this commit, when compiled with older gccs
+ that don't support __builtin_dwarf_cfa. Furthermore, since
+ this header file is freestanding, it has to be independent of
+ config.h, and so the following conditionalisation cannot depend on
+ configure time checks.
+
+ Although it's not clear from
+ 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)',
+ this expression excludes Darwin.
+ .cfi directives in Darwin assembly appear to be completely
+ different and I haven't investigated how they work.
+
+ For even more entertainment value, note we have to use the
+ completely undocumented __builtin_dwarf_cfa(), which appears to
+ really compute the CFA, whereas __builtin_frame_address(0) claims
+ to but actually doesn't. See
+ https://bugs.kde.org/show_bug.cgi?id=243270#c47
+*/
+#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
+# define __FRAME_POINTER \
+ ,"r"(__builtin_dwarf_cfa())
+# define VALGRIND_CFI_PROLOGUE \
+ "movq %%rbp, %%r15\n\t" \
+ "movq %2, %%rbp\n\t" \
+ ".cfi_remember_state\n\t" \
+ ".cfi_def_cfa rbp, 0\n\t"
+# define VALGRIND_CFI_EPILOGUE \
+ "movq %%r15, %%rbp\n\t" \
+ ".cfi_restore_state\n\t"
+#else
+# define __FRAME_POINTER
+# define VALGRIND_CFI_PROLOGUE
+# define VALGRIND_CFI_EPILOGUE
+#endif
+
+/* Macros to save and align the stack before making a function
+ call and restore it afterwards as gcc may not keep the stack
+ pointer aligned if it doesn't realise calls are being made
+ to other functions. */
+
+#define VALGRIND_ALIGN_STACK \
+ "movq %%rsp,%%r14\n\t" \
+ "andq $0xfffffffffffffff0,%%rsp\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "movq %%r14,%%rsp\n\t"
+
+/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
+ long) == 8. */
+
+/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_
+ macros. In order not to trash the stack redzone, we need to drop
+ %rsp by 128 before the hidden call, and restore afterwards. The
+ nastyness is that it is only by luck that the stack still appears
+ to be unwindable during the hidden call - since then the behaviour
+ of any routine using this macro does not match what the CFI data
+ says. Sigh.
+
+ Why is this important? Imagine that a wrapper has a stack
+ allocated local, and passes to the hidden call, a pointer to it.
+ Because gcc does not know about the hidden call, it may allocate
+ that local in the redzone. Unfortunately the hidden call may then
+ trash it before it comes to use it. So we must step clear of the
+ redzone, for the duration of the hidden call, to make it safe.
+
+ Probably the same problem afflicts the other redzone-style ABIs too
+ (ppc64-linux); but for those, the stack is
+ self describing (none of this CFI nonsense) so at least messing
+ with the stack pointer doesn't give a danger of non-unwindable
+ stack. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $136,%%rsp\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $136,%%rsp\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $136,%%rsp\n\t" \
+ "pushq 88(%%rax)\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ VALGRIND_ALIGN_STACK \
+ "subq $128,%%rsp\n\t" \
+ "pushq 96(%%rax)\n\t" \
+ "pushq 88(%%rax)\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ VALGRIND_RESTORE_STACK \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+/* This is useful for finding out about the on-stack stuff:
+
+ extern int f9 ( int,int,int,int,int,int,int,int,int );
+ extern int f10 ( int,int,int,int,int,int,int,int,int,int );
+ extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
+ extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int );
+
+ int g9 ( void ) {
+ return f9(11,22,33,44,55,66,77,88,99);
+ }
+ int g10 ( void ) {
+ return f10(11,22,33,44,55,66,77,88,99,110);
+ }
+ int g11 ( void ) {
+ return f11(11,22,33,44,55,66,77,88,99,110,121);
+ }
+ int g12 ( void ) {
+ return f12(11,22,33,44,55,66,77,88,99,110,121,132);
+ }
+*/
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* Macros to save and align the stack before making a function
+ call and restore it afterwards as gcc may not keep the stack
+ pointer aligned if it doesn't realise calls are being made
+ to other functions. */
+
+#define VALGRIND_ALIGN_STACK \
+ "mr 28,1\n\t" \
+ "rlwinm 1,1,0,0,27\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "mr 1,28\n\t"
+
+/* These CALL_FN_ macros assume that on ppc32-linux,
+ sizeof(unsigned long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-16\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-16\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-32\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,16(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ _argvec[12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-32\n\t" \
+ /* arg12 */ \
+ "lwz 3,48(11)\n\t" \
+ "stw 3,20(1)\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,16(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ VALGRIND_RESTORE_STACK \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64be_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* Macros to save and align the stack before making a function
+ call and restore it afterwards as gcc may not keep the stack
+ pointer aligned if it doesn't realise calls are being made
+ to other functions. */
+
+#define VALGRIND_ALIGN_STACK \
+ "mr 28,1\n\t" \
+ "rldicr 1,1,0,59\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "mr 1,28\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+ long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg12 */ \
+ "ld 3,96(11)\n\t" \
+ "std 3,136(1)\n\t" \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc64be_linux */
+
+/* ------------------------- ppc64le-linux ----------------------- */
+#if defined(PLAT_ppc64le_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* Macros to save and align the stack before making a function
+ call and restore it afterwards as gcc may not keep the stack
+ pointer aligned if it doesn't realise calls are being made
+ to other functions. */
+
+#define VALGRIND_ALIGN_STACK \
+ "mr 28,1\n\t" \
+ "rldicr 1,1,0,59\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "mr 1,28\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+ long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(12)\n\t" /* arg6->r8 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(12)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(12)\n\t" /* arg7->r9 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(12)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(12)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(12)\n\t" /* arg8->r10 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg9 */ \
+ "ld 3,72(12)\n\t" \
+ "std 3,96(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(12)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(12)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(12)\n\t" /* arg8->r10 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg10 */ \
+ "ld 3,80(12)\n\t" \
+ "std 3,104(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(12)\n\t" \
+ "std 3,96(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(12)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(12)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(12)\n\t" /* arg8->r10 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg11 */ \
+ "ld 3,88(12)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(12)\n\t" \
+ "std 3,104(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(12)\n\t" \
+ "std 3,96(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(12)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(12)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(12)\n\t" /* arg8->r10 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "mr 12,%1\n\t" \
+ "std 2,-16(12)\n\t" /* save tocptr */ \
+ "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg12 */ \
+ "ld 3,96(12)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg11 */ \
+ "ld 3,88(12)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(12)\n\t" \
+ "std 3,104(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(12)\n\t" \
+ "std 3,96(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(12)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(12)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(12)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(12)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(12)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(12)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(12)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(12)\n\t" /* arg8->r10 */ \
+ "ld 12, 0(12)\n\t" /* target->r12 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \
+ "mr 12,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(12)\n\t" /* restore tocptr */ \
+ VALGRIND_RESTORE_STACK \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc64le_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14"
+
+/* Macros to save and align the stack before making a function
+ call and restore it afterwards as gcc may not keep the stack
+ pointer aligned if it doesn't realise calls are being made
+ to other functions. */
+
+/* This is a bit tricky. We store the original stack pointer in r10
+ as it is callee-saves. gcc doesn't allow the use of r11 for some
+ reason. Also, we can't directly "bic" the stack pointer in thumb
+ mode since r13 isn't an allowed register number in that context.
+ So use r4 as a temporary, since that is about to get trashed
+ anyway, just after each use of this macro. Side effect is we need
+ to be very careful about any future changes, since
+ VALGRIND_ALIGN_STACK simply assumes r4 is usable. */
+#define VALGRIND_ALIGN_STACK \
+ "mov r10, sp\n\t" \
+ "mov r4, sp\n\t" \
+ "bic r4, r4, #7\n\t" \
+ "mov sp, r4\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "mov sp, r10\n\t"
+
+/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #4 \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "push {r0} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "push {r0, r1} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #4 \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "push {r0, r1, r2} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "push {r0, r1, r2, r3} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #4 \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #40] \n\t" \
+ "push {r0} \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #4 \n\t" \
+ "ldr r0, [%1, #40] \n\t" \
+ "ldr r1, [%1, #44] \n\t" \
+ "push {r0, r1} \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr r0, [%1, #40] \n\t" \
+ "ldr r1, [%1, #44] \n\t" \
+ "ldr r2, [%1, #48] \n\t" \
+ "push {r0, r1, r2} \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ arm64-linux ------------------------ */
+
+#if defined(PLAT_arm64_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \
+ "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \
+ "x18", "x19", "x20", "x30", \
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \
+ "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \
+ "v26", "v27", "v28", "v29", "v30", "v31"
+
+/* x21 is callee-saved, so we can use it to save and restore SP around
+ the hidden call. */
+#define VALGRIND_ALIGN_STACK \
+ "mov x21, sp\n\t" \
+ "bic sp, x21, #15\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "mov sp, x21\n\t"
+
+/* These CALL_FN_ macros assume that on arm64-linux,
+ sizeof(unsigned long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x5, [%1, #48] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x5, [%1, #48] \n\t" \
+ "ldr x6, [%1, #56] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x5, [%1, #48] \n\t" \
+ "ldr x6, [%1, #56] \n\t" \
+ "ldr x7, [%1, #64] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #0x20 \n\t" \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x5, [%1, #48] \n\t" \
+ "ldr x6, [%1, #56] \n\t" \
+ "ldr x7, [%1, #64] \n\t" \
+ "ldr x8, [%1, #72] \n\t" \
+ "str x8, [sp, #0] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #0x20 \n\t" \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x5, [%1, #48] \n\t" \
+ "ldr x6, [%1, #56] \n\t" \
+ "ldr x7, [%1, #64] \n\t" \
+ "ldr x8, [%1, #72] \n\t" \
+ "str x8, [sp, #0] \n\t" \
+ "ldr x8, [%1, #80] \n\t" \
+ "str x8, [sp, #8] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #0x30 \n\t" \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x5, [%1, #48] \n\t" \
+ "ldr x6, [%1, #56] \n\t" \
+ "ldr x7, [%1, #64] \n\t" \
+ "ldr x8, [%1, #72] \n\t" \
+ "str x8, [sp, #0] \n\t" \
+ "ldr x8, [%1, #80] \n\t" \
+ "str x8, [sp, #8] \n\t" \
+ "ldr x8, [%1, #88] \n\t" \
+ "str x8, [sp, #16] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11, \
+ arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "sub sp, sp, #0x30 \n\t" \
+ "ldr x0, [%1, #8] \n\t" \
+ "ldr x1, [%1, #16] \n\t" \
+ "ldr x2, [%1, #24] \n\t" \
+ "ldr x3, [%1, #32] \n\t" \
+ "ldr x4, [%1, #40] \n\t" \
+ "ldr x5, [%1, #48] \n\t" \
+ "ldr x6, [%1, #56] \n\t" \
+ "ldr x7, [%1, #64] \n\t" \
+ "ldr x8, [%1, #72] \n\t" \
+ "str x8, [sp, #0] \n\t" \
+ "ldr x8, [%1, #80] \n\t" \
+ "str x8, [sp, #8] \n\t" \
+ "ldr x8, [%1, #88] \n\t" \
+ "str x8, [sp, #16] \n\t" \
+ "ldr x8, [%1, #96] \n\t" \
+ "str x8, [sp, #24] \n\t" \
+ "ldr x8, [%1] \n\t" /* target->x8 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \
+ VALGRIND_RESTORE_STACK \
+ "mov %0, x0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_arm64_linux */
+
+/* ------------------------- s390x-linux ------------------------- */
+
+#if defined(PLAT_s390x_linux)
+
+/* Similar workaround as amd64 (see above), but we use r11 as frame
+ pointer and save the old r11 in r7. r11 might be used for
+ argvec, therefore we copy argvec in r1 since r1 is clobbered
+ after the call anyway. */
+#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
+# define __FRAME_POINTER \
+ ,"d"(__builtin_dwarf_cfa())
+# define VALGRIND_CFI_PROLOGUE \
+ ".cfi_remember_state\n\t" \
+ "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \
+ "lgr 7,11\n\t" \
+ "lgr 11,%2\n\t" \
+ ".cfi_def_cfa r11, 0\n\t"
+# define VALGRIND_CFI_EPILOGUE \
+ "lgr 11, 7\n\t" \
+ ".cfi_restore_state\n\t"
+#else
+# define __FRAME_POINTER
+# define VALGRIND_CFI_PROLOGUE \
+ "lgr 1,%1\n\t"
+# define VALGRIND_CFI_EPILOGUE
+#endif
+
+/* Nb: On s390 the stack pointer is properly aligned *at all times*
+ according to the s390 GCC maintainer. (The ABI specification is not
+ precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and
+ VALGRIND_RESTORE_STACK are not defined here. */
+
+/* These regs are trashed by the hidden call. Note that we overwrite
+ r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the
+ function a proper return address. All others are ABI defined call
+ clobbers. */
+#if defined(__VX__) || defined(__S390_VX__)
+#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \
+ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", \
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", \
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+#else
+#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7"
+#endif
+
+/* Nb: Although r11 is modified in the asm snippets below (inside
+ VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for
+ two reasons:
+ (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not
+ modified
+ (2) GCC will complain that r11 cannot appear inside a clobber section,
+ when compiled with -O -fno-omit-frame-pointer
+ */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-160\n\t" \
+ "lg 1, 0(1)\n\t" /* target->r1 */ \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,160\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+/* The call abi has the arguments in r2-r6 and stack */
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-160\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,160\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1, arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-160\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,160\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-160\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,160\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-160\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,160\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-160\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,160\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
+ arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-168\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "mvc 160(8,15), 48(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,168\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-176\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "mvc 160(8,15), 48(1)\n\t" \
+ "mvc 168(8,15), 56(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,176\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7 ,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-184\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "mvc 160(8,15), 48(1)\n\t" \
+ "mvc 168(8,15), 56(1)\n\t" \
+ "mvc 176(8,15), 64(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,184\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7 ,arg8, arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-192\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "mvc 160(8,15), 48(1)\n\t" \
+ "mvc 168(8,15), 56(1)\n\t" \
+ "mvc 176(8,15), 64(1)\n\t" \
+ "mvc 184(8,15), 72(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,192\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7 ,arg8, arg9, arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-200\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "mvc 160(8,15), 48(1)\n\t" \
+ "mvc 168(8,15), 56(1)\n\t" \
+ "mvc 176(8,15), 64(1)\n\t" \
+ "mvc 184(8,15), 72(1)\n\t" \
+ "mvc 192(8,15), 80(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,200\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7 ,arg8, arg9, arg10, arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-208\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "mvc 160(8,15), 48(1)\n\t" \
+ "mvc 168(8,15), 56(1)\n\t" \
+ "mvc 176(8,15), 64(1)\n\t" \
+ "mvc 184(8,15), 72(1)\n\t" \
+ "mvc 192(8,15), 80(1)\n\t" \
+ "mvc 200(8,15), 88(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,208\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ _argvec[12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "aghi 15,-216\n\t" \
+ "lg 2, 8(1)\n\t" \
+ "lg 3,16(1)\n\t" \
+ "lg 4,24(1)\n\t" \
+ "lg 5,32(1)\n\t" \
+ "lg 6,40(1)\n\t" \
+ "mvc 160(8,15), 48(1)\n\t" \
+ "mvc 168(8,15), 56(1)\n\t" \
+ "mvc 176(8,15), 64(1)\n\t" \
+ "mvc 184(8,15), 72(1)\n\t" \
+ "mvc 192(8,15), 80(1)\n\t" \
+ "mvc 200(8,15), 88(1)\n\t" \
+ "mvc 208(8,15), 96(1)\n\t" \
+ "lg 1, 0(1)\n\t" \
+ VALGRIND_CALL_NOREDIR_R1 \
+ "aghi 15,216\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ "lgr %0, 2\n\t" \
+ : /*out*/ "=d" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+
+#endif /* PLAT_s390x_linux */
+
+/* ------------------------- mips32-linux ----------------------- */
+
+#if defined(PLAT_mips32_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \
+"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \
+"$25", "$31"
+
+/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "subu $29, $29, 16 \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 16\n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "subu $29, $29, 16 \n\t" \
+ "lw $4, 4(%1) \n\t" /* arg1*/ \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 16 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "subu $29, $29, 16 \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 16 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "subu $29, $29, 16 \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 16 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "subu $29, $29, 16 \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 16 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 24\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 24 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 32\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 24(%1) \n\t" \
+ "nop\n\t" \
+ "sw $4, 20($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 32 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 32\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 24(%1) \n\t" \
+ "sw $4, 20($29) \n\t" \
+ "lw $4, 28(%1) \n\t" \
+ "sw $4, 24($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 32 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 40\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 24(%1) \n\t" \
+ "sw $4, 20($29) \n\t" \
+ "lw $4, 28(%1) \n\t" \
+ "sw $4, 24($29) \n\t" \
+ "lw $4, 32(%1) \n\t" \
+ "sw $4, 28($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 40 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 40\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 24(%1) \n\t" \
+ "sw $4, 20($29) \n\t" \
+ "lw $4, 28(%1) \n\t" \
+ "sw $4, 24($29) \n\t" \
+ "lw $4, 32(%1) \n\t" \
+ "sw $4, 28($29) \n\t" \
+ "lw $4, 36(%1) \n\t" \
+ "sw $4, 32($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 40 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 48\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 24(%1) \n\t" \
+ "sw $4, 20($29) \n\t" \
+ "lw $4, 28(%1) \n\t" \
+ "sw $4, 24($29) \n\t" \
+ "lw $4, 32(%1) \n\t" \
+ "sw $4, 28($29) \n\t" \
+ "lw $4, 36(%1) \n\t" \
+ "sw $4, 32($29) \n\t" \
+ "lw $4, 40(%1) \n\t" \
+ "sw $4, 36($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 48 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 48\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 24(%1) \n\t" \
+ "sw $4, 20($29) \n\t" \
+ "lw $4, 28(%1) \n\t" \
+ "sw $4, 24($29) \n\t" \
+ "lw $4, 32(%1) \n\t" \
+ "sw $4, 28($29) \n\t" \
+ "lw $4, 36(%1) \n\t" \
+ "sw $4, 32($29) \n\t" \
+ "lw $4, 40(%1) \n\t" \
+ "sw $4, 36($29) \n\t" \
+ "lw $4, 44(%1) \n\t" \
+ "sw $4, 40($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 48 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ "subu $29, $29, 8 \n\t" \
+ "sw $28, 0($29) \n\t" \
+ "sw $31, 4($29) \n\t" \
+ "lw $4, 20(%1) \n\t" \
+ "subu $29, $29, 56\n\t" \
+ "sw $4, 16($29) \n\t" \
+ "lw $4, 24(%1) \n\t" \
+ "sw $4, 20($29) \n\t" \
+ "lw $4, 28(%1) \n\t" \
+ "sw $4, 24($29) \n\t" \
+ "lw $4, 32(%1) \n\t" \
+ "sw $4, 28($29) \n\t" \
+ "lw $4, 36(%1) \n\t" \
+ "sw $4, 32($29) \n\t" \
+ "lw $4, 40(%1) \n\t" \
+ "sw $4, 36($29) \n\t" \
+ "lw $4, 44(%1) \n\t" \
+ "sw $4, 40($29) \n\t" \
+ "lw $4, 48(%1) \n\t" \
+ "sw $4, 44($29) \n\t" \
+ "lw $4, 4(%1) \n\t" \
+ "lw $5, 8(%1) \n\t" \
+ "lw $6, 12(%1) \n\t" \
+ "lw $7, 16(%1) \n\t" \
+ "lw $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "addu $29, $29, 56 \n\t" \
+ "lw $28, 0($29) \n\t" \
+ "lw $31, 4($29) \n\t" \
+ "addu $29, $29, 8 \n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_mips32_linux */
+
+/* ------------------------- nanomips-linux -------------------- */
+
+#if defined(PLAT_nanomips_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "$t4", "$t5", "$a0", "$a1", "$a2", \
+"$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", \
+"$t8","$t9", "$at"
+
+/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ "lw $a1, 8(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ "lw $a1, 8(%1)\n\t" \
+ "lw $a2,12(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ "lw $a1, 8(%1)\n\t" \
+ "lw $a2,12(%1)\n\t" \
+ "lw $a3,16(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ "lw $a1, 8(%1)\n\t" \
+ "lw $a2,12(%1)\n\t" \
+ "lw $a3,16(%1)\n\t" \
+ "lw $a4,20(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ "lw $a1, 8(%1)\n\t" \
+ "lw $a2,12(%1)\n\t" \
+ "lw $a3,16(%1)\n\t" \
+ "lw $a4,20(%1)\n\t" \
+ "lw $a5,24(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ "lw $a1, 8(%1)\n\t" \
+ "lw $a2,12(%1)\n\t" \
+ "lw $a3,16(%1)\n\t" \
+ "lw $a4,20(%1)\n\t" \
+ "lw $a5,24(%1)\n\t" \
+ "lw $a6,28(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ "lw $t9, 0(%1)\n\t" \
+ "lw $a0, 4(%1)\n\t" \
+ "lw $a1, 8(%1)\n\t" \
+ "lw $a2,12(%1)\n\t" \
+ "lw $a3,16(%1)\n\t" \
+ "lw $a4,20(%1)\n\t" \
+ "lw $a5,24(%1)\n\t" \
+ "lw $a6,28(%1)\n\t" \
+ "lw $a7,32(%1)\n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ "addiu $sp, $sp, -16 \n\t" \
+ "lw $t9,36(%1) \n\t" \
+ "sw $t9, 0($sp) \n\t" \
+ "lw $t9, 0(%1) \n\t" \
+ "lw $a0, 4(%1) \n\t" \
+ "lw $a1, 8(%1) \n\t" \
+ "lw $a2,12(%1) \n\t" \
+ "lw $a3,16(%1) \n\t" \
+ "lw $a4,20(%1) \n\t" \
+ "lw $a5,24(%1) \n\t" \
+ "lw $a6,28(%1) \n\t" \
+ "lw $a7,32(%1) \n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0 \n\t" \
+ "addiu $sp, $sp, 16 \n\t" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ "addiu $sp, $sp, -16 \n\t" \
+ "lw $t9,36(%1) \n\t" \
+ "sw $t9, 0($sp) \n\t" \
+ "lw $t9,40(%1) \n\t" \
+ "sw $t9, 4($sp) \n\t" \
+ "lw $t9, 0(%1) \n\t" \
+ "lw $a0, 4(%1) \n\t" \
+ "lw $a1, 8(%1) \n\t" \
+ "lw $a2,12(%1) \n\t" \
+ "lw $a3,16(%1) \n\t" \
+ "lw $a4,20(%1) \n\t" \
+ "lw $a5,24(%1) \n\t" \
+ "lw $a6,28(%1) \n\t" \
+ "lw $a7,32(%1) \n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0 \n\t" \
+ "addiu $sp, $sp, 16 \n\t" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ "addiu $sp, $sp, -16 \n\t" \
+ "lw $t9,36(%1) \n\t" \
+ "sw $t9, 0($sp) \n\t" \
+ "lw $t9,40(%1) \n\t" \
+ "sw $t9, 4($sp) \n\t" \
+ "lw $t9,44(%1) \n\t" \
+ "sw $t9, 8($sp) \n\t" \
+ "lw $t9, 0(%1) \n\t" \
+ "lw $a0, 4(%1) \n\t" \
+ "lw $a1, 8(%1) \n\t" \
+ "lw $a2,12(%1) \n\t" \
+ "lw $a3,16(%1) \n\t" \
+ "lw $a4,20(%1) \n\t" \
+ "lw $a5,24(%1) \n\t" \
+ "lw $a6,28(%1) \n\t" \
+ "lw $a7,32(%1) \n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0 \n\t" \
+ "addiu $sp, $sp, 16 \n\t" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ "addiu $sp, $sp, -16 \n\t" \
+ "lw $t9,36(%1) \n\t" \
+ "sw $t9, 0($sp) \n\t" \
+ "lw $t9,40(%1) \n\t" \
+ "sw $t9, 4($sp) \n\t" \
+ "lw $t9,44(%1) \n\t" \
+ "sw $t9, 8($sp) \n\t" \
+ "lw $t9,48(%1) \n\t" \
+ "sw $t9,12($sp) \n\t" \
+ "lw $t9, 0(%1) \n\t" \
+ "lw $a0, 4(%1) \n\t" \
+ "lw $a1, 8(%1) \n\t" \
+ "lw $a2,12(%1) \n\t" \
+ "lw $a3,16(%1) \n\t" \
+ "lw $a4,20(%1) \n\t" \
+ "lw $a5,24(%1) \n\t" \
+ "lw $a6,28(%1) \n\t" \
+ "lw $a7,32(%1) \n\t" \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $a0 \n\t" \
+ "addiu $sp, $sp, 16 \n\t" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_nanomips_linux */
+
+/* ------------------------- mips64-linux ------------------------- */
+
+#if defined(PLAT_mips64_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \
+"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \
+"$25", "$31"
+
+/* These CALL_FN_ macros assume that on mips64-linux,
+ sizeof(long long) == 8. */
+
+#define MIPS64_LONG2REG_CAST(x) ((long long)(long)x)
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[1]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ __asm__ volatile( \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[2]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" /* arg1*/ \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[3]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = _orig.nraddr; \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[4]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = _orig.nraddr; \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[5]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[6]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[7]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $9, 48(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[8]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \
+ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $9, 48(%1)\n\t" \
+ "ld $10, 56(%1)\n\t" \
+ "ld $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[9]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \
+ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \
+ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \
+ __asm__ volatile( \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $9, 48(%1)\n\t" \
+ "ld $10, 56(%1)\n\t" \
+ "ld $11, 64(%1)\n\t" \
+ "ld $25, 0(%1) \n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[10]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \
+ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \
+ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \
+ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \
+ __asm__ volatile( \
+ "dsubu $29, $29, 8\n\t" \
+ "ld $4, 72(%1)\n\t" \
+ "sd $4, 0($29)\n\t" \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $9, 48(%1)\n\t" \
+ "ld $10, 56(%1)\n\t" \
+ "ld $11, 64(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "daddu $29, $29, 8\n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[11]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \
+ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \
+ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \
+ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \
+ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \
+ __asm__ volatile( \
+ "dsubu $29, $29, 16\n\t" \
+ "ld $4, 72(%1)\n\t" \
+ "sd $4, 0($29)\n\t" \
+ "ld $4, 80(%1)\n\t" \
+ "sd $4, 8($29)\n\t" \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $9, 48(%1)\n\t" \
+ "ld $10, 56(%1)\n\t" \
+ "ld $11, 64(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "daddu $29, $29, 16\n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[12]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \
+ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \
+ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \
+ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \
+ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \
+ _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \
+ __asm__ volatile( \
+ "dsubu $29, $29, 24\n\t" \
+ "ld $4, 72(%1)\n\t" \
+ "sd $4, 0($29)\n\t" \
+ "ld $4, 80(%1)\n\t" \
+ "sd $4, 8($29)\n\t" \
+ "ld $4, 88(%1)\n\t" \
+ "sd $4, 16($29)\n\t" \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $9, 48(%1)\n\t" \
+ "ld $10, 56(%1)\n\t" \
+ "ld $11, 64(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "daddu $29, $29, 24\n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long long _argvec[13]; \
+ volatile unsigned long long _res; \
+ _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \
+ _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \
+ _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \
+ _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \
+ _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \
+ _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \
+ _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \
+ _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \
+ _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \
+ _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \
+ _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \
+ _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \
+ _argvec[12] = MIPS64_LONG2REG_CAST(arg12); \
+ __asm__ volatile( \
+ "dsubu $29, $29, 32\n\t" \
+ "ld $4, 72(%1)\n\t" \
+ "sd $4, 0($29)\n\t" \
+ "ld $4, 80(%1)\n\t" \
+ "sd $4, 8($29)\n\t" \
+ "ld $4, 88(%1)\n\t" \
+ "sd $4, 16($29)\n\t" \
+ "ld $4, 96(%1)\n\t" \
+ "sd $4, 24($29)\n\t" \
+ "ld $4, 8(%1)\n\t" \
+ "ld $5, 16(%1)\n\t" \
+ "ld $6, 24(%1)\n\t" \
+ "ld $7, 32(%1)\n\t" \
+ "ld $8, 40(%1)\n\t" \
+ "ld $9, 48(%1)\n\t" \
+ "ld $10, 56(%1)\n\t" \
+ "ld $11, 64(%1)\n\t" \
+ "ld $25, 0(%1)\n\t" /* target->t9 */ \
+ VALGRIND_CALL_NOREDIR_T9 \
+ "daddu $29, $29, 32\n\t" \
+ "move %0, $2\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) (long)_res; \
+ } while (0)
+
+#endif /* PLAT_mips64_linux */
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */
+/* */
+/* ------------------------------------------------------------------ */
+
+/* Some request codes. There are many more of these, but most are not
+ exposed to end-user view. These are the public ones, all of the
+ form 0x1000 + small_number.
+
+ Core ones are in the range 0x00000000--0x0000ffff. The non-public
+ ones start at 0x2000.
+*/
+
+/* These macros are used by tools -- they must be public, but don't
+ embed them into other programs. */
+#define VG_USERREQ_TOOL_BASE(a,b) \
+ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
+#define VG_IS_TOOL_USERREQ(a, b, v) \
+ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
+ This enum comprises an ABI exported by Valgrind to programs
+ which use client requests. DO NOT CHANGE THE NUMERIC VALUES OF THESE
+ ENTRIES, NOR DELETE ANY -- add new ones at the end of the most
+ relevant group. */
+typedef
+ enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001,
+ VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
+
+ /* These allow any function to be called from the simulated
+ CPU but run on the real CPU. Nb: the first arg passed to
+ the function is always the ThreadId of the running
+ thread! So CLIENT_CALL0 actually requires a 1 arg
+ function, etc. */
+ VG_USERREQ__CLIENT_CALL0 = 0x1101,
+ VG_USERREQ__CLIENT_CALL1 = 0x1102,
+ VG_USERREQ__CLIENT_CALL2 = 0x1103,
+ VG_USERREQ__CLIENT_CALL3 = 0x1104,
+
+ /* Can be useful in regression testing suites -- eg. can
+ send Valgrind's output to /dev/null and still count
+ errors. */
+ VG_USERREQ__COUNT_ERRORS = 0x1201,
+
+ /* Allows the client program and/or gdbserver to execute a monitor
+ command. */
+ VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202,
+
+ /* Allows the client program to change a dynamic command line
+ option. */
+ VG_USERREQ__CLO_CHANGE = 0x1203,
+
+ /* These are useful and can be interpreted by any tool that
+ tracks malloc() et al, by using vg_replace_malloc.c. */
+ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
+ VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b,
+ VG_USERREQ__FREELIKE_BLOCK = 0x1302,
+ /* Memory pool support. */
+ VG_USERREQ__CREATE_MEMPOOL = 0x1303,
+ VG_USERREQ__DESTROY_MEMPOOL = 0x1304,
+ VG_USERREQ__MEMPOOL_ALLOC = 0x1305,
+ VG_USERREQ__MEMPOOL_FREE = 0x1306,
+ VG_USERREQ__MEMPOOL_TRIM = 0x1307,
+ VG_USERREQ__MOVE_MEMPOOL = 0x1308,
+ VG_USERREQ__MEMPOOL_CHANGE = 0x1309,
+ VG_USERREQ__MEMPOOL_EXISTS = 0x130a,
+
+ /* Allow printfs to valgrind log. */
+ /* The first two pass the va_list argument by value, which
+ assumes it is the same size as or smaller than a UWord,
+ which generally isn't the case. Hence are deprecated.
+ The second two pass the vargs by reference and so are
+ immune to this problem. */
+ /* both :: char* fmt, va_list vargs (DEPRECATED) */
+ VG_USERREQ__PRINTF = 0x1401,
+ VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
+ /* both :: char* fmt, va_list* vargs */
+ VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403,
+ VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404,
+
+ /* Stack support. */
+ VG_USERREQ__STACK_REGISTER = 0x1501,
+ VG_USERREQ__STACK_DEREGISTER = 0x1502,
+ VG_USERREQ__STACK_CHANGE = 0x1503,
+
+ /* Wine support */
+ VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601,
+
+ /* Querying of debug info. */
+ VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701,
+
+ /* Disable/enable error reporting level. Takes a single
+ Word arg which is the delta to this thread's error
+ disablement indicator. Hence 1 disables or further
+ disables errors, and -1 moves back towards enablement.
+ Other values are not allowed. */
+ VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801,
+
+ /* Some requests used for Valgrind internal, such as
+ self-test or self-hosting. */
+ /* Initialise IR injection */
+ VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901,
+ /* Used by Inner Valgrind to inform Outer Valgrind where to
+ find the list of inner guest threads */
+ VG_USERREQ__INNER_THREADS = 0x1902
+ } Vg_ClientRequest;
+
+#if !defined(__GNUC__)
+# define __extension__ /* */
+#endif
+
+
+/* Returns the number of Valgrinds this code is running under. That
+ is, 0 if running natively, 1 if running under Valgrind, 2 if
+ running under Valgrind which is running under another Valgrind,
+ etc. */
+#define RUNNING_ON_VALGRIND \
+ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \
+ VG_USERREQ__RUNNING_ON_VALGRIND, \
+ 0, 0, 0, 0, 0) \
+
+
+/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
+ _qzz_len - 1]. Useful if you are debugging a JITter or some such,
+ since it provides a way to make sure valgrind will retranslate the
+ invalidated area. Returns no value. */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \
+ _qzz_addr, _qzz_len, 0, 0, 0)
+
+#define VALGRIND_INNER_THREADS(_qzz_addr) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__INNER_THREADS, \
+ _qzz_addr, 0, 0, 0, 0)
+
+
+/* These requests are for getting Valgrind itself to print something.
+ Possibly with a backtrace. This is a really ugly hack. The return value
+ is the number of characters printed, excluding the "**<pid>** " part at the
+ start and the backtrace (if present). */
+
+#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER)
+/* Modern GCC will optimize the static routine out if unused,
+ and unused attribute will shut down warnings about it. */
+static int VALGRIND_PRINTF(const char *format, ...)
+ __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF(const char *format, ...)
+{
+#if defined(NVALGRIND)
+ (void)format;
+ return 0;
+#else /* NVALGRIND */
+#if defined(_MSC_VER) || defined(__MINGW64__)
+ uintptr_t _qzz_res;
+#else
+ unsigned long _qzz_res;
+#endif
+ va_list vargs;
+ va_start(vargs, format);
+#if defined(_MSC_VER) || defined(__MINGW64__)
+ _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
+ VG_USERREQ__PRINTF_VALIST_BY_REF,
+ (uintptr_t)format,
+ (uintptr_t)&vargs,
+ 0, 0, 0);
+#else
+ _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
+ VG_USERREQ__PRINTF_VALIST_BY_REF,
+ (unsigned long)format,
+ (unsigned long)&vargs,
+ 0, 0, 0);
+#endif
+ va_end(vargs);
+ return (int)_qzz_res;
+#endif /* NVALGRIND */
+}
+
+#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER)
+static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+ __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+{
+#if defined(NVALGRIND)
+ (void)format;
+ return 0;
+#else /* NVALGRIND */
+#if defined(_MSC_VER) || defined(__MINGW64__)
+ uintptr_t _qzz_res;
+#else
+ unsigned long _qzz_res;
+#endif
+ va_list vargs;
+ va_start(vargs, format);
+#if defined(_MSC_VER) || defined(__MINGW64__)
+ _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
+ VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+ (uintptr_t)format,
+ (uintptr_t)&vargs,
+ 0, 0, 0);
+#else
+ _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
+ VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+ (unsigned long)format,
+ (unsigned long)&vargs,
+ 0, 0, 0);
+#endif
+ va_end(vargs);
+ return (int)_qzz_res;
+#endif /* NVALGRIND */
+}
+
+
+/* These requests allow control to move from the simulated CPU to the
+ real CPU, calling an arbitrary function.
+
+ Note that the current ThreadId is inserted as the first argument.
+ So this call:
+
+ VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
+
+ requires f to have this signature:
+
+ Word f(Word tid, Word arg1, Word arg2)
+
+ where "Word" is a word-sized type.
+
+ Note that these client requests are not entirely reliable. For example,
+ if you call a function with them that subsequently calls printf(),
+ there's a high chance Valgrind will crash. Generally, your prospects of
+ these working are made higher if the called function does not refer to
+ any global variables, and does not refer to any libc or other functions
+ (printf et al). Any kind of entanglement with libc or dynamic linking is
+ likely to have a bad outcome, for tricky reasons which we've grappled
+ with a lot in the past.
+*/
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL0, \
+ _qyy_fn, \
+ 0, 0, 0, 0)
+
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL1, \
+ _qyy_fn, \
+ _qyy_arg1, 0, 0, 0)
+
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL2, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, 0, 0)
+
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL3, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, \
+ _qyy_arg3, 0)
+
+
+/* Counts the number of errors that have been recorded by a tool. Nb:
+ the tool must record the errors with VG_(maybe_record_error)() or
+ VG_(unique_error)() for them to be counted. */
+#define VALGRIND_COUNT_ERRORS \
+ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ 0 /* default return */, \
+ VG_USERREQ__COUNT_ERRORS, \
+ 0, 0, 0, 0, 0)
+
+/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing
+ when heap blocks are allocated in order to give accurate results. This
+ happens automatically for the standard allocator functions such as
+ malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete,
+ delete[], etc.
+
+ But if your program uses a custom allocator, this doesn't automatically
+ happen, and Valgrind will not do as well. For example, if you allocate
+ superblocks with mmap() and then allocates chunks of the superblocks, all
+ Valgrind's observations will be at the mmap() level and it won't know that
+ the chunks should be considered separate entities. In Memcheck's case,
+ that means you probably won't get heap block overrun detection (because
+ there won't be redzones marked as unaddressable) and you definitely won't
+ get any leak detection.
+
+ The following client requests allow a custom allocator to be annotated so
+ that it can be handled accurately by Valgrind.
+
+ VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated
+ by a malloc()-like function. For Memcheck (an illustrative case), this
+ does two things:
+
+ - It records that the block has been allocated. This means any addresses
+ within the block mentioned in error messages will be
+ identified as belonging to the block. It also means that if the block
+ isn't freed it will be detected by the leak checker.
+
+ - It marks the block as being addressable and undefined (if 'is_zeroed' is
+ not set), or addressable and defined (if 'is_zeroed' is set). This
+ controls how accesses to the block by the program are handled.
+
+ 'addr' is the start of the usable block (ie. after any
+ redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator
+ can apply redzones -- these are blocks of padding at the start and end of
+ each block. Adding redzones is recommended as it makes it much more likely
+ Valgrind will spot block overruns. `is_zeroed' indicates if the memory is
+ zeroed (or filled with another predictable value), as is the case for
+ calloc().
+
+ VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a
+ heap block -- that will be used by the client program -- is allocated.
+ It's best to put it at the outermost level of the allocator if possible;
+ for example, if you have a function my_alloc() which calls
+ internal_alloc(), and the client request is put inside internal_alloc(),
+ stack traces relating to the heap block will contain entries for both
+ my_alloc() and internal_alloc(), which is probably not what you want.
+
+ For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out
+ custom blocks from within a heap block, B, that has been allocated with
+ malloc/calloc/new/etc, then block B will be *ignored* during leak-checking
+ -- the custom blocks will take precedence.
+
+ VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For
+ Memcheck, it does two things:
+
+ - It records that the block has been deallocated. This assumes that the
+ block was annotated as having been allocated via
+ VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued.
+
+ - It marks the block as being unaddressable.
+
+ VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a
+ heap block is deallocated.
+
+ VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For
+ Memcheck, it does four things:
+
+ - It records that the size of a block has been changed. This assumes that
+ the block was annotated as having been allocated via
+ VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued.
+
+ - If the block shrunk, it marks the freed memory as being unaddressable.
+
+ - If the block grew, it marks the new area as undefined and defines a red
+ zone past the end of the new block.
+
+ - The V-bits of the overlap between the old and the new block are preserved.
+
+ VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block
+ and before deallocation of the old block.
+
+ In many cases, these three client requests will not be enough to get your
+ allocator working well with Memcheck. More specifically, if your allocator
+ writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call
+ will be necessary to mark the memory as addressable just before the zeroing
+ occurs, otherwise you'll get a lot of invalid write errors. For example,
+ you'll need to do this if your allocator recycles freed blocks, but it
+ zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK).
+ Alternatively, if your allocator reuses freed blocks for allocator-internal
+ data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary.
+
+ Really, what's happening is a blurring of the lines between the client
+ program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the
+ memory should be considered unaddressable to the client program, but the
+ allocator knows more than the rest of the client program and so may be able
+ to safely access it. Extra client requests are necessary for Valgrind to
+ understand the distinction between the allocator and the rest of the
+ program.
+
+ Ignored if addr == 0.
+*/
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \
+ addr, sizeB, rzB, is_zeroed, 0)
+
+/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
+ Ignored if addr == 0.
+*/
+#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \
+ addr, oldSizeB, newSizeB, rzB, 0)
+
+/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
+ Ignored if addr == 0.
+*/
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \
+ addr, rzB, 0, 0, 0)
+
+/* Create a memory pool. */
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \
+ pool, rzB, is_zeroed, 0, 0)
+
+/* Create a memory pool with some flags specifying extended behaviour.
+ When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL.
+
+ The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory
+ associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used
+ by the application as superblocks to dole out MALLOC_LIKE blocks using
+ VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels"
+ pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC.
+ The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK.
+ Note that the association between the pool and the second level blocks
+ is implicit : second level blocks will be located inside first level
+ blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag
+ for such 2 levels pools, as otherwise valgrind will detect overlapping
+ memory blocks, and will abort execution (e.g. during leak search).
+
+ Such a meta pool can also be marked as an 'auto free' pool using the flag
+ VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the
+ VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE
+ will automatically free the second level blocks that are contained
+ inside the first level block freed with VALGRIND_MEMPOOL_FREE.
+ In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls
+ to VALGRIND_FREELIKE_BLOCK for all the second level blocks included
+ in the first level block.
+ Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag
+ without the VALGRIND_MEMPOOL_METAPOOL flag.
+*/
+#define VALGRIND_MEMPOOL_AUTO_FREE 1
+#define VALGRIND_MEMPOOL_METAPOOL 2
+#define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \
+ pool, rzB, is_zeroed, flags, 0)
+
+/* Destroy a memory pool. */
+#define VALGRIND_DESTROY_MEMPOOL(pool) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \
+ pool, 0, 0, 0, 0)
+
+/* Associate a piece of memory with a memory pool. */
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \
+ pool, addr, size, 0, 0)
+
+/* Disassociate a piece of memory from a memory pool. */
+#define VALGRIND_MEMPOOL_FREE(pool, addr) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \
+ pool, addr, 0, 0, 0)
+
+/* Disassociate any pieces outside a particular range. */
+#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \
+ pool, addr, size, 0, 0)
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \
+ poolA, poolB, 0, 0, 0)
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \
+ pool, addrA, addrB, size, 0)
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool) \
+ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
+ VG_USERREQ__MEMPOOL_EXISTS, \
+ pool, 0, 0, 0, 0)
+
+/* Mark a piece of memory as being a stack. Returns a stack id.
+ start is the lowest addressable stack byte, end is the highest
+ addressable stack byte. */
+#define VALGRIND_STACK_REGISTER(start, end) \
+ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
+ VG_USERREQ__STACK_REGISTER, \
+ start, end, 0, 0, 0)
+
+/* Unmark the piece of memory associated with a stack id as being a
+ stack. */
+#define VALGRIND_STACK_DEREGISTER(id) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \
+ id, 0, 0, 0, 0)
+
+/* Change the start and end address of the stack id.
+ start is the new lowest addressable stack byte, end is the new highest
+ addressable stack byte. */
+#define VALGRIND_STACK_CHANGE(id, start, end) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \
+ id, start, end, 0, 0)
+
+/* Load PDB debug info for Wine PE image_map. */
+#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \
+ fd, ptr, total_size, delta, 0)
+
+/* Map a code address to a source file name and line number. buf64
+ must point to a 64-byte buffer in the caller's address space. The
+ result will be dumped in there and is guaranteed to be zero
+ terminated. If no info is found, the first byte is set to zero. */
+#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \
+ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
+ VG_USERREQ__MAP_IP_TO_SRCLOC, \
+ addr, buf64, 0, 0, 0)
+
+/* Disable error reporting for this thread. Behaves in a stack like
+ way, so you can safely call this multiple times provided that
+ VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times
+ to re-enable reporting. The first call of this macro disables
+ reporting. Subsequent calls have no effect except to increase the
+ number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable
+ reporting. Child threads do not inherit this setting from their
+ parents -- they are always created with reporting enabled. */
+#define VALGRIND_DISABLE_ERROR_REPORTING \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \
+ 1, 0, 0, 0, 0)
+
+/* Re-enable error reporting, as per comments on
+ VALGRIND_DISABLE_ERROR_REPORTING. */
+#define VALGRIND_ENABLE_ERROR_REPORTING \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \
+ -1, 0, 0, 0, 0)
+
+/* Execute a monitor command from the client program.
+ If a connection is opened with GDB, the output will be sent
+ according to the output mode set for vgdb.
+ If no connection is opened, output will go to the log output.
+ Returns 1 if command not recognised, 0 otherwise. */
+#define VALGRIND_MONITOR_COMMAND(command) \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \
+ command, 0, 0, 0, 0)
+
+
+/* Change the value of a dynamic command line option.
+ Note that unknown or not dynamically changeable options
+ will cause a warning message to be output. */
+#define VALGRIND_CLO_CHANGE(option) \
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CLO_CHANGE, \
+ option, 0, 0, 0, 0)
+
+
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+#undef PLAT_x86_win32
+#undef PLAT_amd64_win64
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64be_linux
+#undef PLAT_ppc64le_linux
+#undef PLAT_arm_linux
+#undef PLAT_s390x_linux
+#undef PLAT_mips32_linux
+#undef PLAT_mips64_linux
+#undef PLAT_nanomips_linux
+#undef PLAT_x86_solaris
+#undef PLAT_amd64_solaris
+
+#endif /* __VALGRIND_H */