From 72a629a8be1ed2adc7402285e0f19f8f06816a26 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 19 Jan 2020 15:23:19 +0100 Subject: move testing logic and integration tests into separate directory --- .gitignore | 18 +- configure.ac | 1 + src/Makefile.am | 1 + src/benchmark/Makefile.am | 2 +- src/lib/.gitignore | 8 - src/lib/Makefile.am | 302 +---- src/lib/afl-generate.sh | 34 - src/lib/baseline/admin_add_incoming.req | 7 - src/lib/baseline/deposit.req | 8 - src/lib/baseline/keys.req | 7 - src/lib/baseline/refresh_link.req | 5 - src/lib/baseline/refresh_melt.req | 8 - src/lib/baseline/refresh_reveal.req | 7 - src/lib/baseline/reserve_status.req | 4 - src/lib/baseline/reserve_withdraw.req | 7 - src/lib/baseline/wire.req | 5 - src/lib/baseline/wire_sepa.req | 5 - src/lib/baseline/wire_test.req | 5 - .../test-taler-exchange-aggregator-postgres.conf | 98 -- .../test-taler-exchange-wirewatch-postgres.conf | 105 -- src/lib/test_auditor_api.c | 710 ---------- src/lib/test_auditor_api.conf | 210 --- src/lib/test_auditor_api_expire_reserve_now.conf | 4 - src/lib/test_auditor_api_version.c | 163 --- src/lib/test_bank_api.c | 186 --- src/lib/test_bank_api_fakebank.conf | 17 - src/lib/test_bank_api_fakebank_twisted.conf | 34 - src/lib/test_bank_api_pybank.conf | 17 - src/lib/test_bank_api_pybank_twisted.conf | 46 - src/lib/test_bank_api_twisted.c | 221 --- src/lib/test_exchange_api.c | 832 ------------ src/lib/test_exchange_api.conf | 210 --- src/lib/test_exchange_api_expire_reserve_now.conf | 4 - .../.config/taler/account-1.json | 5 - .../.config/taler/account-2.json | 4 - .../test_exchange_api_home/.config/taler/sepa.json | 9 - .../test_exchange_api_home/.config/taler/test.json | 8 - .../.config/taler/x-taler-bank.json | 5 - .../share/taler/exchange/offline-keys/master.priv | 1 - src/lib/test_exchange_api_interpreter_on-off.c | 128 -- src/lib/test_exchange_api_keys_cherry_picking.c | 263 ---- src/lib/test_exchange_api_keys_cherry_picking.conf | 184 --- ..._exchange_api_keys_cherry_picking_extended.conf | 5 - ...xchange_api_keys_cherry_picking_extended_2.conf | 5 - .../.config/taler/x-taler-bank.json | 4 - .../share/taler/exchange/offline-keys/master.priv | 1 - src/lib/test_exchange_api_overlapping_keys_bug.c | 130 -- src/lib/test_exchange_api_revocation.c | 231 ---- src/lib/test_exchange_api_twisted.c | 332 ----- src/lib/test_exchange_api_twisted.conf | 196 --- src/lib/test_taler_exchange_aggregator.c | 524 -------- .../.config/taler/account-1.json | 4 - .../share/taler/exchange/offline-keys/master.priv | 1 - src/lib/test_taler_exchange_wirewatch.c | 182 --- .../testing_api_cmd_auditor_deposit_confirmation.c | 444 ------ src/lib/testing_api_cmd_auditor_exchanges.c | 361 ----- src/lib/testing_api_cmd_auditor_exec_auditor.c | 166 --- .../testing_api_cmd_auditor_exec_auditor_dbinit.c | 167 --- .../testing_api_cmd_auditor_exec_wire_auditor.c | 166 --- src/lib/testing_api_cmd_bank_admin_add_incoming.c | 596 --------- src/lib/testing_api_cmd_bank_admin_check.c | 225 ---- src/lib/testing_api_cmd_bank_check.c | 306 ----- src/lib/testing_api_cmd_bank_check_empty.c | 103 -- src/lib/testing_api_cmd_bank_history_credit.c | 599 --------- src/lib/testing_api_cmd_bank_history_debit.c | 602 --------- src/lib/testing_api_cmd_bank_transfer.c | 405 ------ src/lib/testing_api_cmd_batch.c | 228 ---- src/lib/testing_api_cmd_check_keys.c | 359 ----- src/lib/testing_api_cmd_deposit.c | 568 -------- src/lib/testing_api_cmd_exec_aggregator.c | 167 --- src/lib/testing_api_cmd_exec_auditor-sign.c | 233 ---- src/lib/testing_api_cmd_exec_keyup.c | 236 ---- src/lib/testing_api_cmd_exec_wirewatch.c | 168 --- src/lib/testing_api_cmd_insert_deposit.c | 319 ----- src/lib/testing_api_cmd_recoup.c | 620 --------- src/lib/testing_api_cmd_refresh.c | 1411 -------------------- src/lib/testing_api_cmd_refund.c | 333 ----- src/lib/testing_api_cmd_serialize_keys.c | 296 ---- src/lib/testing_api_cmd_signal.c | 116 -- src/lib/testing_api_cmd_sleep.c | 134 -- src/lib/testing_api_cmd_status.c | 238 ---- src/lib/testing_api_cmd_track.c | 806 ----------- src/lib/testing_api_cmd_wait.c | 134 -- src/lib/testing_api_cmd_wire.c | 235 ---- src/lib/testing_api_cmd_withdraw.c | 535 -------- src/lib/testing_api_helpers_auditor.c | 229 ---- src/lib/testing_api_helpers_bank.c | 494 ------- src/lib/testing_api_helpers_exchange.c | 976 -------------- src/lib/testing_api_loop.c | 829 ------------ src/lib/testing_api_trait_amount.c | 77 -- src/lib/testing_api_trait_blinding_key.c | 78 -- src/lib/testing_api_trait_cmd.c | 81 -- src/lib/testing_api_trait_coin_priv.c | 79 -- src/lib/testing_api_trait_contract.c | 74 - src/lib/testing_api_trait_denom_pub.c | 78 -- src/lib/testing_api_trait_denom_sig.c | 80 -- src/lib/testing_api_trait_exchange_pub.c | 78 -- src/lib/testing_api_trait_exchange_sig.c | 78 -- src/lib/testing_api_trait_fresh_coin.c | 78 -- src/lib/testing_api_trait_json.c | 124 -- src/lib/testing_api_trait_merchant_key.c | 128 -- src/lib/testing_api_trait_number.c | 150 --- src/lib/testing_api_trait_process.c | 83 -- src/lib/testing_api_trait_reserve_priv.c | 77 -- src/lib/testing_api_trait_reserve_pub.c | 77 -- src/lib/testing_api_trait_string.c | 232 ---- src/lib/testing_api_trait_time.c | 77 -- src/lib/testing_api_trait_wtid.c | 77 -- src/lib/testing_api_traits.c | 82 -- src/testing/.gitignore | 8 + src/testing/Makefile.am | 308 +++++ src/testing/afl-generate.sh | 34 + src/testing/baseline/admin_add_incoming.req | 7 + src/testing/baseline/deposit.req | 8 + src/testing/baseline/keys.req | 7 + src/testing/baseline/refresh_link.req | 5 + src/testing/baseline/refresh_melt.req | 8 + src/testing/baseline/refresh_reveal.req | 7 + src/testing/baseline/reserve_status.req | 4 + src/testing/baseline/reserve_withdraw.req | 7 + src/testing/baseline/wire.req | 5 + src/testing/baseline/wire_sepa.req | 5 + src/testing/baseline/wire_test.req | 5 + .../test-taler-exchange-aggregator-postgres.conf | 98 ++ .../test-taler-exchange-wirewatch-postgres.conf | 105 ++ src/testing/test_auditor_api.c | 710 ++++++++++ src/testing/test_auditor_api.conf | 210 +++ .../test_auditor_api_expire_reserve_now.conf | 4 + src/testing/test_auditor_api_version.c | 163 +++ src/testing/test_bank_api.c | 186 +++ src/testing/test_bank_api_fakebank.conf | 17 + src/testing/test_bank_api_fakebank_twisted.conf | 34 + src/testing/test_bank_api_pybank.conf | 17 + src/testing/test_bank_api_pybank_twisted.conf | 46 + src/testing/test_bank_api_twisted.c | 221 +++ src/testing/test_exchange_api.c | 832 ++++++++++++ src/testing/test_exchange_api.conf | 210 +++ .../test_exchange_api_expire_reserve_now.conf | 4 + .../.config/taler/account-1.json | 5 + .../.config/taler/account-2.json | 4 + .../test_exchange_api_home/.config/taler/sepa.json | 9 + .../test_exchange_api_home/.config/taler/test.json | 8 + .../.config/taler/x-taler-bank.json | 5 + .../share/taler/exchange/offline-keys/master.priv | 1 + src/testing/test_exchange_api_interpreter_on-off.c | 128 ++ .../test_exchange_api_keys_cherry_picking.c | 263 ++++ .../test_exchange_api_keys_cherry_picking.conf | 184 +++ ..._exchange_api_keys_cherry_picking_extended.conf | 5 + ...xchange_api_keys_cherry_picking_extended_2.conf | 5 + .../.config/taler/x-taler-bank.json | 4 + .../share/taler/exchange/offline-keys/master.priv | 1 + .../test_exchange_api_overlapping_keys_bug.c | 130 ++ src/testing/test_exchange_api_revocation.c | 231 ++++ src/testing/test_exchange_api_twisted.c | 332 +++++ src/testing/test_exchange_api_twisted.conf | 196 +++ src/testing/test_taler_exchange_aggregator.c | 524 ++++++++ .../.config/taler/account-1.json | 4 + .../share/taler/exchange/offline-keys/master.priv | 1 + src/testing/test_taler_exchange_wirewatch.c | 182 +++ .../testing_api_cmd_auditor_deposit_confirmation.c | 444 ++++++ src/testing/testing_api_cmd_auditor_exchanges.c | 361 +++++ src/testing/testing_api_cmd_auditor_exec_auditor.c | 165 +++ .../testing_api_cmd_auditor_exec_auditor_dbinit.c | 166 +++ .../testing_api_cmd_auditor_exec_wire_auditor.c | 165 +++ .../testing_api_cmd_bank_admin_add_incoming.c | 596 +++++++++ src/testing/testing_api_cmd_bank_admin_check.c | 224 ++++ src/testing/testing_api_cmd_bank_check.c | 305 +++++ src/testing/testing_api_cmd_bank_check_empty.c | 102 ++ src/testing/testing_api_cmd_bank_history_credit.c | 599 +++++++++ src/testing/testing_api_cmd_bank_history_debit.c | 602 +++++++++ src/testing/testing_api_cmd_bank_transfer.c | 405 ++++++ src/testing/testing_api_cmd_batch.c | 227 ++++ src/testing/testing_api_cmd_check_keys.c | 358 +++++ src/testing/testing_api_cmd_deposit.c | 567 ++++++++ src/testing/testing_api_cmd_exec_aggregator.c | 166 +++ src/testing/testing_api_cmd_exec_auditor-sign.c | 232 ++++ src/testing/testing_api_cmd_exec_keyup.c | 235 ++++ src/testing/testing_api_cmd_exec_wirewatch.c | 167 +++ src/testing/testing_api_cmd_insert_deposit.c | 318 +++++ src/testing/testing_api_cmd_recoup.c | 619 +++++++++ src/testing/testing_api_cmd_refresh.c | 1410 +++++++++++++++++++ src/testing/testing_api_cmd_refund.c | 332 +++++ src/testing/testing_api_cmd_serialize_keys.c | 295 ++++ src/testing/testing_api_cmd_signal.c | 115 ++ src/testing/testing_api_cmd_sleep.c | 133 ++ src/testing/testing_api_cmd_status.c | 237 ++++ src/testing/testing_api_cmd_track.c | 805 +++++++++++ src/testing/testing_api_cmd_wait.c | 133 ++ src/testing/testing_api_cmd_wire.c | 234 ++++ src/testing/testing_api_cmd_withdraw.c | 534 ++++++++ src/testing/testing_api_helpers_auditor.c | 229 ++++ src/testing/testing_api_helpers_bank.c | 494 +++++++ src/testing/testing_api_helpers_exchange.c | 975 ++++++++++++++ src/testing/testing_api_loop.c | 828 ++++++++++++ src/testing/testing_api_trait_amount.c | 76 ++ src/testing/testing_api_trait_blinding_key.c | 77 ++ src/testing/testing_api_trait_cmd.c | 80 ++ src/testing/testing_api_trait_coin_priv.c | 78 ++ src/testing/testing_api_trait_contract.c | 74 + src/testing/testing_api_trait_denom_pub.c | 77 ++ src/testing/testing_api_trait_denom_sig.c | 79 ++ src/testing/testing_api_trait_exchange_pub.c | 77 ++ src/testing/testing_api_trait_exchange_sig.c | 77 ++ src/testing/testing_api_trait_fresh_coin.c | 77 ++ src/testing/testing_api_trait_json.c | 123 ++ src/testing/testing_api_trait_merchant_key.c | 127 ++ src/testing/testing_api_trait_number.c | 149 +++ src/testing/testing_api_trait_process.c | 82 ++ src/testing/testing_api_trait_reserve_priv.c | 76 ++ src/testing/testing_api_trait_reserve_pub.c | 76 ++ src/testing/testing_api_trait_string.c | 231 ++++ src/testing/testing_api_trait_time.c | 76 ++ src/testing/testing_api_trait_wtid.c | 76 ++ src/testing/testing_api_traits.c | 81 ++ 214 files changed, 21161 insertions(+), 21187 deletions(-) delete mode 100644 src/lib/.gitignore delete mode 100644 src/lib/afl-generate.sh delete mode 100644 src/lib/baseline/admin_add_incoming.req delete mode 100644 src/lib/baseline/deposit.req delete mode 100644 src/lib/baseline/keys.req delete mode 100644 src/lib/baseline/refresh_link.req delete mode 100644 src/lib/baseline/refresh_melt.req delete mode 100644 src/lib/baseline/refresh_reveal.req delete mode 100644 src/lib/baseline/reserve_status.req delete mode 100644 src/lib/baseline/reserve_withdraw.req delete mode 100644 src/lib/baseline/wire.req delete mode 100644 src/lib/baseline/wire_sepa.req delete mode 100644 src/lib/baseline/wire_test.req delete mode 100644 src/lib/test-taler-exchange-aggregator-postgres.conf delete mode 100644 src/lib/test-taler-exchange-wirewatch-postgres.conf delete mode 100644 src/lib/test_auditor_api.c delete mode 100644 src/lib/test_auditor_api.conf delete mode 100644 src/lib/test_auditor_api_expire_reserve_now.conf delete mode 100644 src/lib/test_auditor_api_version.c delete mode 100644 src/lib/test_bank_api.c delete mode 100644 src/lib/test_bank_api_fakebank.conf delete mode 100644 src/lib/test_bank_api_fakebank_twisted.conf delete mode 100644 src/lib/test_bank_api_pybank.conf delete mode 100644 src/lib/test_bank_api_pybank_twisted.conf delete mode 100644 src/lib/test_bank_api_twisted.c delete mode 100644 src/lib/test_exchange_api.c delete mode 100644 src/lib/test_exchange_api.conf delete mode 100644 src/lib/test_exchange_api_expire_reserve_now.conf delete mode 100644 src/lib/test_exchange_api_home/.config/taler/account-1.json delete mode 100644 src/lib/test_exchange_api_home/.config/taler/account-2.json delete mode 100644 src/lib/test_exchange_api_home/.config/taler/sepa.json delete mode 100644 src/lib/test_exchange_api_home/.config/taler/test.json delete mode 100644 src/lib/test_exchange_api_home/.config/taler/x-taler-bank.json delete mode 100644 src/lib/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv delete mode 100644 src/lib/test_exchange_api_interpreter_on-off.c delete mode 100644 src/lib/test_exchange_api_keys_cherry_picking.c delete mode 100644 src/lib/test_exchange_api_keys_cherry_picking.conf delete mode 100644 src/lib/test_exchange_api_keys_cherry_picking_extended.conf delete mode 100644 src/lib/test_exchange_api_keys_cherry_picking_extended_2.conf delete mode 100644 src/lib/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json delete mode 100644 src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv delete mode 100644 src/lib/test_exchange_api_overlapping_keys_bug.c delete mode 100644 src/lib/test_exchange_api_revocation.c delete mode 100644 src/lib/test_exchange_api_twisted.c delete mode 100644 src/lib/test_exchange_api_twisted.conf delete mode 100644 src/lib/test_taler_exchange_aggregator.c delete mode 100644 src/lib/test_taler_exchange_httpd_home/.config/taler/account-1.json delete mode 100644 src/lib/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv delete mode 100644 src/lib/test_taler_exchange_wirewatch.c delete mode 100644 src/lib/testing_api_cmd_auditor_deposit_confirmation.c delete mode 100644 src/lib/testing_api_cmd_auditor_exchanges.c delete mode 100644 src/lib/testing_api_cmd_auditor_exec_auditor.c delete mode 100644 src/lib/testing_api_cmd_auditor_exec_auditor_dbinit.c delete mode 100644 src/lib/testing_api_cmd_auditor_exec_wire_auditor.c delete mode 100644 src/lib/testing_api_cmd_bank_admin_add_incoming.c delete mode 100644 src/lib/testing_api_cmd_bank_admin_check.c delete mode 100644 src/lib/testing_api_cmd_bank_check.c delete mode 100644 src/lib/testing_api_cmd_bank_check_empty.c delete mode 100644 src/lib/testing_api_cmd_bank_history_credit.c delete mode 100644 src/lib/testing_api_cmd_bank_history_debit.c delete mode 100644 src/lib/testing_api_cmd_bank_transfer.c delete mode 100644 src/lib/testing_api_cmd_batch.c delete mode 100644 src/lib/testing_api_cmd_check_keys.c delete mode 100644 src/lib/testing_api_cmd_deposit.c delete mode 100644 src/lib/testing_api_cmd_exec_aggregator.c delete mode 100644 src/lib/testing_api_cmd_exec_auditor-sign.c delete mode 100644 src/lib/testing_api_cmd_exec_keyup.c delete mode 100644 src/lib/testing_api_cmd_exec_wirewatch.c delete mode 100644 src/lib/testing_api_cmd_insert_deposit.c delete mode 100644 src/lib/testing_api_cmd_recoup.c delete mode 100644 src/lib/testing_api_cmd_refresh.c delete mode 100644 src/lib/testing_api_cmd_refund.c delete mode 100644 src/lib/testing_api_cmd_serialize_keys.c delete mode 100644 src/lib/testing_api_cmd_signal.c delete mode 100644 src/lib/testing_api_cmd_sleep.c delete mode 100644 src/lib/testing_api_cmd_status.c delete mode 100644 src/lib/testing_api_cmd_track.c delete mode 100644 src/lib/testing_api_cmd_wait.c delete mode 100644 src/lib/testing_api_cmd_wire.c delete mode 100644 src/lib/testing_api_cmd_withdraw.c delete mode 100644 src/lib/testing_api_helpers_auditor.c delete mode 100644 src/lib/testing_api_helpers_bank.c delete mode 100644 src/lib/testing_api_helpers_exchange.c delete mode 100644 src/lib/testing_api_loop.c delete mode 100644 src/lib/testing_api_trait_amount.c delete mode 100644 src/lib/testing_api_trait_blinding_key.c delete mode 100644 src/lib/testing_api_trait_cmd.c delete mode 100644 src/lib/testing_api_trait_coin_priv.c delete mode 100644 src/lib/testing_api_trait_contract.c delete mode 100644 src/lib/testing_api_trait_denom_pub.c delete mode 100644 src/lib/testing_api_trait_denom_sig.c delete mode 100644 src/lib/testing_api_trait_exchange_pub.c delete mode 100644 src/lib/testing_api_trait_exchange_sig.c delete mode 100644 src/lib/testing_api_trait_fresh_coin.c delete mode 100644 src/lib/testing_api_trait_json.c delete mode 100644 src/lib/testing_api_trait_merchant_key.c delete mode 100644 src/lib/testing_api_trait_number.c delete mode 100644 src/lib/testing_api_trait_process.c delete mode 100644 src/lib/testing_api_trait_reserve_priv.c delete mode 100644 src/lib/testing_api_trait_reserve_pub.c delete mode 100644 src/lib/testing_api_trait_string.c delete mode 100644 src/lib/testing_api_trait_time.c delete mode 100644 src/lib/testing_api_trait_wtid.c delete mode 100644 src/lib/testing_api_traits.c create mode 100644 src/testing/.gitignore create mode 100644 src/testing/Makefile.am create mode 100644 src/testing/afl-generate.sh create mode 100644 src/testing/baseline/admin_add_incoming.req create mode 100644 src/testing/baseline/deposit.req create mode 100644 src/testing/baseline/keys.req create mode 100644 src/testing/baseline/refresh_link.req create mode 100644 src/testing/baseline/refresh_melt.req create mode 100644 src/testing/baseline/refresh_reveal.req create mode 100644 src/testing/baseline/reserve_status.req create mode 100644 src/testing/baseline/reserve_withdraw.req create mode 100644 src/testing/baseline/wire.req create mode 100644 src/testing/baseline/wire_sepa.req create mode 100644 src/testing/baseline/wire_test.req create mode 100644 src/testing/test-taler-exchange-aggregator-postgres.conf create mode 100644 src/testing/test-taler-exchange-wirewatch-postgres.conf create mode 100644 src/testing/test_auditor_api.c create mode 100644 src/testing/test_auditor_api.conf create mode 100644 src/testing/test_auditor_api_expire_reserve_now.conf create mode 100644 src/testing/test_auditor_api_version.c create mode 100644 src/testing/test_bank_api.c create mode 100644 src/testing/test_bank_api_fakebank.conf create mode 100644 src/testing/test_bank_api_fakebank_twisted.conf create mode 100644 src/testing/test_bank_api_pybank.conf create mode 100644 src/testing/test_bank_api_pybank_twisted.conf create mode 100644 src/testing/test_bank_api_twisted.c create mode 100644 src/testing/test_exchange_api.c create mode 100644 src/testing/test_exchange_api.conf create mode 100644 src/testing/test_exchange_api_expire_reserve_now.conf create mode 100644 src/testing/test_exchange_api_home/.config/taler/account-1.json create mode 100644 src/testing/test_exchange_api_home/.config/taler/account-2.json create mode 100644 src/testing/test_exchange_api_home/.config/taler/sepa.json create mode 100644 src/testing/test_exchange_api_home/.config/taler/test.json create mode 100644 src/testing/test_exchange_api_home/.config/taler/x-taler-bank.json create mode 100644 src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv create mode 100644 src/testing/test_exchange_api_interpreter_on-off.c create mode 100644 src/testing/test_exchange_api_keys_cherry_picking.c create mode 100644 src/testing/test_exchange_api_keys_cherry_picking.conf create mode 100644 src/testing/test_exchange_api_keys_cherry_picking_extended.conf create mode 100644 src/testing/test_exchange_api_keys_cherry_picking_extended_2.conf create mode 100644 src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json create mode 100644 src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv create mode 100644 src/testing/test_exchange_api_overlapping_keys_bug.c create mode 100644 src/testing/test_exchange_api_revocation.c create mode 100644 src/testing/test_exchange_api_twisted.c create mode 100644 src/testing/test_exchange_api_twisted.conf create mode 100644 src/testing/test_taler_exchange_aggregator.c create mode 100644 src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json create mode 100644 src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv create mode 100644 src/testing/test_taler_exchange_wirewatch.c create mode 100644 src/testing/testing_api_cmd_auditor_deposit_confirmation.c create mode 100644 src/testing/testing_api_cmd_auditor_exchanges.c create mode 100644 src/testing/testing_api_cmd_auditor_exec_auditor.c create mode 100644 src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c create mode 100644 src/testing/testing_api_cmd_auditor_exec_wire_auditor.c create mode 100644 src/testing/testing_api_cmd_bank_admin_add_incoming.c create mode 100644 src/testing/testing_api_cmd_bank_admin_check.c create mode 100644 src/testing/testing_api_cmd_bank_check.c create mode 100644 src/testing/testing_api_cmd_bank_check_empty.c create mode 100644 src/testing/testing_api_cmd_bank_history_credit.c create mode 100644 src/testing/testing_api_cmd_bank_history_debit.c create mode 100644 src/testing/testing_api_cmd_bank_transfer.c create mode 100644 src/testing/testing_api_cmd_batch.c create mode 100644 src/testing/testing_api_cmd_check_keys.c create mode 100644 src/testing/testing_api_cmd_deposit.c create mode 100644 src/testing/testing_api_cmd_exec_aggregator.c create mode 100644 src/testing/testing_api_cmd_exec_auditor-sign.c create mode 100644 src/testing/testing_api_cmd_exec_keyup.c create mode 100644 src/testing/testing_api_cmd_exec_wirewatch.c create mode 100644 src/testing/testing_api_cmd_insert_deposit.c create mode 100644 src/testing/testing_api_cmd_recoup.c create mode 100644 src/testing/testing_api_cmd_refresh.c create mode 100644 src/testing/testing_api_cmd_refund.c create mode 100644 src/testing/testing_api_cmd_serialize_keys.c create mode 100644 src/testing/testing_api_cmd_signal.c create mode 100644 src/testing/testing_api_cmd_sleep.c create mode 100644 src/testing/testing_api_cmd_status.c create mode 100644 src/testing/testing_api_cmd_track.c create mode 100644 src/testing/testing_api_cmd_wait.c create mode 100644 src/testing/testing_api_cmd_wire.c create mode 100644 src/testing/testing_api_cmd_withdraw.c create mode 100644 src/testing/testing_api_helpers_auditor.c create mode 100644 src/testing/testing_api_helpers_bank.c create mode 100644 src/testing/testing_api_helpers_exchange.c create mode 100644 src/testing/testing_api_loop.c create mode 100644 src/testing/testing_api_trait_amount.c create mode 100644 src/testing/testing_api_trait_blinding_key.c create mode 100644 src/testing/testing_api_trait_cmd.c create mode 100644 src/testing/testing_api_trait_coin_priv.c create mode 100644 src/testing/testing_api_trait_contract.c create mode 100644 src/testing/testing_api_trait_denom_pub.c create mode 100644 src/testing/testing_api_trait_denom_sig.c create mode 100644 src/testing/testing_api_trait_exchange_pub.c create mode 100644 src/testing/testing_api_trait_exchange_sig.c create mode 100644 src/testing/testing_api_trait_fresh_coin.c create mode 100644 src/testing/testing_api_trait_json.c create mode 100644 src/testing/testing_api_trait_merchant_key.c create mode 100644 src/testing/testing_api_trait_number.c create mode 100644 src/testing/testing_api_trait_process.c create mode 100644 src/testing/testing_api_trait_reserve_priv.c create mode 100644 src/testing/testing_api_trait_reserve_pub.c create mode 100644 src/testing/testing_api_trait_string.c create mode 100644 src/testing/testing_api_trait_time.c create mode 100644 src/testing/testing_api_trait_wtid.c create mode 100644 src/testing/testing_api_traits.c diff --git a/.gitignore b/.gitignore index 278ce1c42..af6e0cfa9 100644 --- a/.gitignore +++ b/.gitignore @@ -47,16 +47,16 @@ src/lib/test_taler_exchange_httpd_home/.local/share/taler/exchange/wirefees/ src/lib/test_taler_exchange_httpd_home/.local/share/taler/auditor/ src/lib/test_taler_exchange_httpd_home/.local/share/taler/auditors/ -src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/live-keys/ -src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/ -src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditor/ -src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditors/ -src/lib/test_exchange_api_home/.local/share/taler/exchange/live-keys/ -src/lib/test_exchange_api_home/.local/share/taler/exchange/wirefees/ -src/lib/test_exchange_api_home/.local/share/taler/auditor/ -src/lib/test_exchange_api_home/.local/share/taler/auditors/ +src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/live-keys/ +src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/ +src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditor/ +src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditors/ +src/testing/test_exchange_api_home/.local/share/taler/exchange/live-keys/ +src/testing/test_exchange_api_home/.local/share/taler/exchange/wirefees/ +src/testing/test_exchange_api_home/.local/share/taler/auditor/ +src/testing/test_exchange_api_home/.local/share/taler/auditors/ src/lib/auditor.in -src/lib/test_exchange_api_twisted +src/testing/test_exchange_api_twisted src/exchange/taler-exchange-aggregator src/exchange/test_taler_exchange_aggregator-postgres src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/live-keys/ diff --git a/configure.ac b/configure.ac index 8b2548e3b..8e6b6f260 100644 --- a/configure.ac +++ b/configure.ac @@ -487,6 +487,7 @@ AC_CONFIG_FILES([Makefile src/exchangedb/Makefile src/exchange-tools/Makefile src/lib/Makefile + src/testing/Makefile src/benchmark/Makefile src/include/Makefile src/json/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 8ad3e88e9..4b07a1161 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,4 +25,5 @@ SUBDIRS = \ auditordb \ auditor \ lib \ + testing \ benchmark diff --git a/src/benchmark/Makefile.am b/src/benchmark/Makefile.am index 03dfdf3b5..62aadf604 100644 --- a/src/benchmark/Makefile.am +++ b/src/benchmark/Makefile.am @@ -20,7 +20,7 @@ taler_exchange_benchmark_LDADD = \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/lib/libtalerexchange.la \ - $(top_builddir)/src/lib/libtalertesting.la \ + $(top_builddir)/src/testing/libtalertesting.la \ $(top_builddir)/src/bank-lib/libtalerfakebank.la \ $(top_builddir)/src/bank-lib/libtalerbank.la \ -lgnunetjson \ diff --git a/src/lib/.gitignore b/src/lib/.gitignore deleted file mode 100644 index 17a848cce..000000000 --- a/src/lib/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -test_auditor_api_version -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 diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 077616752..f03522a69 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -1,20 +1,21 @@ # This Makefile.am is in the public domain + AM_CPPFLAGS = \ - -I$(top_srcdir)/src/include \ - $(LIBGCRYPT_CFLAGS) \ - $(POSTGRESQL_CPPFLAGS) + -I$(top_srcdir)/src/include \ + $(LIBGCRYPT_CFLAGS) \ + $(POSTGRESQL_CPPFLAGS) if USE_COVERAGE AM_CFLAGS = --coverage -O0 XLIB = -lgcov endif + # Libraries lib_LTLIBRARIES = \ libtalerauditor.la \ - libtalerexchange.la \ - libtalertesting.la + libtalerexchange.la libtalerexchange_la_LDFLAGS = \ -version-info 4:0:0 \ @@ -62,294 +63,3 @@ libtalerauditor_la_LIBADD = \ -ljansson \ $(LIBGNURLCURL_LIBS) \ $(XLIB) - -libtalertesting_la_LDFLAGS = \ - -version-info 0:0:0 \ - -no-undefined -libtalertesting_la_SOURCES = \ - exchange_api_curl_defaults.c \ - testing_api_cmd_auditor_deposit_confirmation.c \ - testing_api_cmd_auditor_exchanges.c \ - testing_api_cmd_auditor_exec_auditor.c \ - testing_api_cmd_auditor_exec_auditor_dbinit.c \ - testing_api_cmd_auditor_exec_wire_auditor.c \ - testing_api_cmd_bank_admin_add_incoming.c \ - testing_api_cmd_bank_check.c \ - testing_api_cmd_bank_admin_check.c \ - testing_api_cmd_bank_check_empty.c \ - testing_api_cmd_bank_history_credit.c \ - testing_api_cmd_bank_history_debit.c \ - testing_api_cmd_bank_transfer.c \ - testing_api_cmd_batch.c \ - testing_api_cmd_check_keys.c \ - testing_api_cmd_deposit.c \ - testing_api_cmd_exec_aggregator.c \ - testing_api_cmd_exec_wirewatch.c \ - testing_api_cmd_exec_keyup.c \ - testing_api_cmd_exec_auditor-sign.c \ - testing_api_cmd_recoup.c \ - testing_api_cmd_refund.c \ - testing_api_cmd_refresh.c \ - testing_api_cmd_serialize_keys.c \ - testing_api_cmd_signal.c \ - testing_api_cmd_sleep.c \ - testing_api_cmd_status.c \ - testing_api_cmd_track.c \ - testing_api_cmd_wait.c \ - testing_api_cmd_wire.c \ - testing_api_cmd_withdraw.c \ - testing_api_cmd_insert_deposit.c \ - testing_api_helpers_auditor.c \ - testing_api_helpers_bank.c \ - testing_api_helpers_exchange.c \ - testing_api_loop.c \ - testing_api_traits.c \ - testing_api_trait_amount.c \ - testing_api_trait_blinding_key.c \ - testing_api_trait_cmd.c \ - testing_api_trait_coin_priv.c \ - testing_api_trait_contract.c \ - testing_api_trait_denom_pub.c \ - testing_api_trait_denom_sig.c \ - testing_api_trait_exchange_pub.c \ - testing_api_trait_exchange_sig.c \ - testing_api_trait_fresh_coin.c \ - testing_api_trait_json.c \ - testing_api_trait_merchant_key.c \ - testing_api_trait_number.c \ - testing_api_trait_process.c \ - testing_api_trait_reserve_pub.c \ - testing_api_trait_reserve_priv.c \ - testing_api_trait_string.c \ - testing_api_trait_time.c \ - testing_api_trait_wtid.c -libtalertesting_la_LIBADD = \ - libtalerexchange.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - -lgnunetcurl \ - -lgnunetjson \ - -lgnunetutil \ - -ljansson \ - $(XLIB) - -# Testcases - -AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; - -check_PROGRAMS = \ - test_auditor_api \ - test_auditor_api_version \ - test_bank_api_with_fakebank \ - test_bank_api_with_pybank \ - test_exchange_api \ - test_exchange_api_keys_cherry_picking \ - test_exchange_api_revocation \ - test_exchange_api_overlapping_keys_bug \ - test_taler_exchange_aggregator-postgres \ - test_taler_exchange_wirewatch-postgres -if HAVE_TWISTER - check_PROGRAMS += \ - test_exchange_api_twisted \ - test_bank_api_with_fakebank_twisted \ - test_bank_api_with_pybank_twisted -endif - -TESTS = \ - $(check_PROGRAMS) - -test_auditor_api_SOURCES = \ - test_auditor_api.c -test_auditor_api_LDADD = \ - libtalerauditor.la \ - libtalertesting.la \ - libtalerexchange.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_auditor_api_version_SOURCES = \ - test_auditor_api_version.c -test_auditor_api_version_LDADD = \ - libtalerauditor.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_bank_api_with_fakebank_SOURCES = \ - test_bank_api.c -test_bank_api_with_fakebank_LDADD = \ - $(top_builddir)/src/lib/libtalertesting.la \ - -ltalerexchange \ - -lgnunetutil \ - $(top_builddir)/src/bank-lib/libtalerbank.la - -test_bank_api_with_pybank_SOURCES = \ - test_bank_api.c -test_bank_api_with_pybank_LDADD = \ - libtalertesting.la \ - libtalerexchange.la \ - -lgnunetutil \ - $(top_builddir)/src/bank-lib/libtalerbank.la - -test_exchange_api_SOURCES = \ - test_exchange_api.c -test_exchange_api_LDADD = \ - libtalertesting.la \ - libtalerexchange.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_exchange_api_revocation_SOURCES = \ - test_exchange_api_revocation.c -test_exchange_api_revocation_LDADD = \ - libtalertesting.la \ - libtalerexchange.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_exchange_api_keys_cherry_picking_SOURCES = \ - test_exchange_api_keys_cherry_picking.c -test_exchange_api_keys_cherry_picking_LDADD = \ - libtalertesting.la \ - libtalerexchange.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_exchange_api_overlapping_keys_bug_SOURCES = \ - test_exchange_api_overlapping_keys_bug.c -test_exchange_api_overlapping_keys_bug_LDADD = \ - libtalertesting.la \ - libtalerexchange.la \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_taler_exchange_aggregator_postgres_SOURCES = \ - test_taler_exchange_aggregator.c -test_taler_exchange_aggregator_postgres_LDADD = \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/lib/libtalertesting.la \ - -lmicrohttpd \ - -lgnunetutil \ - -lgnunetjson \ - -ljansson \ - -lpthread - -test_taler_exchange_wirewatch_postgres_SOURCES = \ - test_taler_exchange_wirewatch.c -test_taler_exchange_wirewatch_postgres_LDADD = \ - $(LIBGCRYPT_LIBS) \ - $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - $(top_builddir)/src/lib/libtalertesting.la \ - -lmicrohttpd \ - -lgnunetutil \ - -lgnunetjson \ - -lgnunetpq \ - -ljansson \ - -lpthread - -test_exchange_api_twisted_SOURCES = \ - test_exchange_api_twisted.c -test_exchange_api_twisted_LDADD = \ - $(LIBGCRYPT_LIBS) \ - libtalertesting.la \ - libtalerexchange.la \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libtalerutil.la \ - -ltalertwistertesting \ - -lgnunetjson \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_bank_api_with_fakebank_twisted_SOURCES = \ - test_bank_api_twisted.c -test_bank_api_with_fakebank_twisted_LDADD = \ - $(top_builddir)/src/lib/libtalertesting.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/lib/libtalerexchange.la \ - $(top_builddir)/src/json/libtalerjson.la \ - -ltalertwistertesting \ - -lgnunetjson \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - -test_bank_api_with_pybank_twisted_SOURCES = \ - test_bank_api_twisted.c -test_bank_api_with_pybank_twisted_LDADD = \ - $(top_builddir)/src/lib/libtalertesting.la \ - $(top_builddir)/src/bank-lib/libtalerbank.la \ - $(top_builddir)/src/bank-lib/libtalerfakebank.la \ - $(top_builddir)/src/lib/libtalerexchange.la \ - $(top_builddir)/src/json/libtalerjson.la \ - -ltalertwistertesting \ - -lgnunetjson \ - -lgnunetcurl \ - -lgnunetutil \ - -ljansson - - -# Distribution - -EXTRA_DIST = \ - test_bank_api.conf \ - test_bank_api_bank_twisted.conf \ - test_auditor_api.conf \ - test_auditor_api_expire_reserve_now.conf \ - test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \ - test_exchange_api_home/.config/taler/account-2.json \ - test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json \ - test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \ - test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv \ - test_exchange_api_home/.config/taler/test.json \ - test_exchange_api_home/.config/taler/sepa.json \ - test_exchange_api.conf \ - test_exchange_api_twisted.conf \ - test_exchange_api_keys_cherry_picking.conf \ - test_exchange_api_keys_cherry_picking_extended.conf \ - test_exchange_api_keys_cherry_picking_extended_2.conf \ - test_exchange_api_expire_reserve_now.conf \ - test-taler-exchange-aggregator-postgres.conf \ - test-taler-exchange-wirewatch-postgres.conf diff --git a/src/lib/afl-generate.sh b/src/lib/afl-generate.sh deleted file mode 100644 index b0afcab35..000000000 --- a/src/lib/afl-generate.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -# -# This file is part of TALER -# Copyright (C) 2015 GNUnet e.V. -# -# TALER is free software; you can redistribute it and/or modify it under the -# terms of the GNU Affero 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License along with -# TALER; see the file COPYING. If not, If not, see -# -# -# This will generate testcases in a directory 'afl-tests', which can then -# be moved into src/exchange/afl-tests/ to be run during exchange-testing. -# -# This script uses American Fuzzy Loop (AFL) to fuzz the exchange to -# automatically create tests with good coverage. You must install -# AFL and set AFL_HOME to the directory where AFL is installed -# before running. Also, a directory "baseline/" should exist with -# templates for inputs for AFL to fuzz. These can be generated -# by running wireshark on loopback while running 'make check' in -# this directory. Save each HTTP request to a new file. -# -# Note that you want to switch 'TESTRUN = NO' and pre-init the -# database before running this, otherwise it will be awfully slow. -# -# Must be run from this directory. -# -$AFL_HOME/afl-fuzz -i baseline/ -m 250 -o afl-tests/ -f /tmp/afl-input taler-exchange-httpd -i -f /tmp/afl-input -d test-exchange-home/ -C diff --git a/src/lib/baseline/admin_add_incoming.req b/src/lib/baseline/admin_add_incoming.req deleted file mode 100644 index 677678b5d..000000000 --- a/src/lib/baseline/admin_add_incoming.req +++ /dev/null @@ -1,7 +0,0 @@ -POST /admin/add/incoming HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json -Content-Length: 220 - -{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}} \ No newline at end of file diff --git a/src/lib/baseline/deposit.req b/src/lib/baseline/deposit.req deleted file mode 100644 index a400796f1..000000000 --- a/src/lib/baseline/deposit.req +++ /dev/null @@ -1,8 +0,0 @@ -POST /deposit HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json -Content-Length: 1658 -Expect: 100-continue - -{"ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26E9M8S0M6CSH6X334GSN8RW30D9G8MT46CA660W34GSG6MT4AD9K8GT3ECSH6MVK0E2374V38H1M8MR4CDJ66MWK4E1S6MR3GCT28CV32H1Q8N23GCHG70S36C1K8MS3GCSN8RV36D9S710KGD9K6GWKEGJ28GRM4CJ56X1K6DJ18D2KGHA46D13GDA66GVK4GHJ8N13AE9J8RVK6GT184S48E1K6X336G9Q8N142CJ4692M6EA16GRKJD9N6523ADA36X13GG9G70TK6DHN68R36CT18GR4CDSJ6CW3GCT364W46CSR8RV42GJ474SMADSH851K4H9Q8GS42CHS8RV3GCSJ64V46DSN8RSM6HHN6N246D9S6934AH9P6X23JGSH652K0DJ5612KJGA26N242CH35452081918G2J2G0","timestamp":"/Date(1442821652)/","f":{"currency":"EUR","value":5,"fraction":0},"wire":{"type":"TEST","bank":"dest bank","account":42},"coin_pub":"JXWK4NS0H2W4V4BETQ90CCEDADP6QQ3MV3YZ7RV2KXEM8PWXE8Q0","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","h_contract_terms":"1CMEEFQ5S4QJGGAMVYFV07XQRHQA311CR2MTRNC5M9KZV6ETDV1SY00WJFEV2CG9BXQTEQPZAF8A54C2HX32TZCN20VBGPFPS2Z16B0","merchant_pub":"C36TEXQXFW00170C2EJ66ZR0000CX9VPZNZG00109NX020000000","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","refund_deadline":"/Date(0)/","coin_sig":"X16E0DP8C2BJNVNX09G24FFC5GA4W7RN2YXZP9WJTAN9BY6B4GMA39QNYR51XNNEZ3H1J7TP0K9G55JZ8V7WS7CZMD7E64HWYBFWM00"} diff --git a/src/lib/baseline/keys.req b/src/lib/baseline/keys.req deleted file mode 100644 index a9503a864..000000000 --- a/src/lib/baseline/keys.req +++ /dev/null @@ -1,7 +0,0 @@ -GET /keys HTTP/1.1 -User-Agent: Wget/1.16.3 (linux-gnu) -Accept: */* -Accept-Encoding: identity -Host: 127.0.0.1:8081 -Connection: Keep-Alive - diff --git a/src/lib/baseline/refresh_link.req b/src/lib/baseline/refresh_link.req deleted file mode 100644 index acf3dff51..000000000 --- a/src/lib/baseline/refresh_link.req +++ /dev/null @@ -1,5 +0,0 @@ -GET /refresh/link?coin_pub=WQHES0X5XK43VBG1Y8FXR2YEJM04HQVMDTCS07MH691XWADG8QCG HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json - diff --git a/src/lib/baseline/refresh_melt.req b/src/lib/baseline/refresh_melt.req deleted file mode 100644 index 98b5b6389..000000000 --- a/src/lib/baseline/refresh_melt.req +++ /dev/null @@ -1,8 +0,0 @@ -POST /refresh/melt HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json -Content-Length: 34136 -Expect: 100-continue - -{"new_denoms":["51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSN8CV38D9G8MT46CSG650M4GHQ6N0M6HHR6X142EA26H13JG9N6RV3AD1P6GV34HHK8S0M6CT28RTMAH9R8H0K2GHN68W46G9K8RT32CT560RKCC268RRKJCSJ70S30CA564SKAD9J84VM8DSG611MAG9R6H2MAG9M8MT4CDHG8CWM8HHH84T3AD1N6X0KEH9P8RRMCCSQ8MT30CSK6MVK0GA48CW30D9J6WTK0CSN650MAD1R70TM4CHG850K2G9H89142DT488S42DT36RVM6DSS6GTK2CSJ84WMCDHP8CV3GDSP6GTM4G9H6N246GHH6GWKGD1N70R34HA689148GHP8RVK2E9M8MRKJCJ28D0KEGT26CS3EH256RVKEDSJ74WKGGT16RSM6H9M6GVKGDS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSN8CV38D9G8MT46CSG650M4GHQ6N0M6HHR6X142EA26H13JG9N6RV3AD1P6GV34HHK8S0M6CT28RTMAH9R8H0K2GHN68W46G9K8RT32CT560RKCC268RRKJCSJ70S30CA564SKAD9J84VM8DSG611MAG9R6H2MAG9M8MT4CDHG8CWM8HHH84T3AD1N6X0KEH9P8RRMCCSQ8MT30CSK6MVK0GA48CW30D9J6WTK0CSN650MAD1R70TM4CHG850K2G9H89142DT488S42DT36RVM6DSS6GTK2CSJ84WMCDHP8CV3GDSP6GTM4G9H6N246GHH6GWKGD1N70R34HA689148GHP8RVK2E9M8MRKJCJ28D0KEGT26CS3EH256RVKEDSJ74WKGGT16RSM6H9M6GVKGDS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSN8CV38D9G8MT46CSG650M4GHQ6N0M6HHR6X142EA26H13JG9N6RV3AD1P6GV34HHK8S0M6CT28RTMAH9R8H0K2GHN68W46G9K8RT32CT560RKCC268RRKJCSJ70S30CA564SKAD9J84VM8DSG611MAG9R6H2MAG9M8MT4CDHG8CWM8HHH84T3AD1N6X0KEH9P8RRMCCSQ8MT30CSK6MVK0GA48CW30D9J6WTK0CSN650MAD1R70TM4CHG850K2G9H89142DT488S42DT36RVM6DSS6GTK2CSJ84WMCDHP8CV3GDSP6GTM4G9H6N246GHH6GWKGD1N70R34HA689148GHP8RVK2E9M8MRKJCJ28D0KEGT26CS3EH256RVKEDSJ74WKGGT16RSM6H9M6GVKGDS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0"],"transfer_pubs":[["J65E5480S6ZVPBA5HV9D4APYXFS527DAJGN5HKZ5EWP89EFSKGK0"],["TYZZG5HSXTYJMA9XD3EMTX2S36V7F4VPR1RHQPKJSTWXJD2KPDAG"],["2MN2X2X7P6GJCN09Z6ZDF2R9W1W3BSYJER7FTBSDDSWMRJ7DG0DG"]],"melt_coins":[{"value_with_fee":{"currency":"EUR","value":4,"fraction":0},"coin_pub":"WQHES0X5XK43VBG1Y8FXR2YEJM04HQVMDTCS07MH691XWADG8QCG","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","denom_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26DJ384R4CCHP8RTK6DJ46X344C9M6S1KEDSQ8923EE9P84SKAH9R84SMAGT670SM4GT66123EDJ46RVK0E1N65336H226H2K8CA38CVKCH9N711K2H1S6X134GHJ6924CGJ68RRMAH9P6MT30H23651KCD1N6X0M8GA58CS34E9K70V32E1S8MTK8GJ270WK0HA368V3GDHM68RK2CHS610MAH1H8RR42CT58H342DSG8D1MCC1J6N0KEHHS6WVM2GHS60WM8G9G6GTMAC258D338HHP8MWM2GSS8MW3GCA270TK6G9G6WRM2GA56RSMCC9R88T3JEA270SK0HJ284R3CC9Q6WVK0DT570TKJE9P68SK0CSG88T3CCHJ60R48C9N611KAD9N6WVMAC9N70T46GH35452081918G2J2G0","confirm_sig":"ZKYCWKVTVQCWMWTAQRNRSKGQP6AC14VF7W525ZQYFZ6J2T1GM7PE7945W3HNW32S0MZBX8K65VQPXH83NMQR2SGTY7DX2T60RKHFP00"}],"secret_encs":[["DCZPFTHF1GZRXFVSYJ4AK1HH4QE46T8F60X1AQ6T6BF1WHBNTJ3FEGH7Y1TH5A6YT10GFYGV12S8V9MB4HEKHRYBBMR7JJ9KB264TNR"],["ANBQS74BACGAWEC0F0654HYGZB3NBSNXVD4KZY4TRP4JMRADJE2Y5BYV513Y37PPMR6V5P200FEAHTZ5TS3R9G9MBYM6Z144N853PQG"],["1X6P2JR301MPR5JYMKPV1HXAFXKH9M09HWVQ4PS6JNK1K6E8ZSMW1C6NS79CPFP443QBVEW9SRWXXJQT91EHFKJ8007AB4S64SPWN3G"]],"coin_evs":[["1XB4A97X8ATPH1KG5NAMJGJY258AGK0MKVJRHN4NGKPRD17DQM0CMTT351FB7T56NTVA9E5VTH9Q12A10C3YVDEYJB4B66EC1NPXNPMNSVTBJ7HGM4DXFB03K1BXK247QK581CGE54286BTK6B5VW0FTS4AZ3NQP43V9E6VV1HTKG1CM5WQJEY14TAC8P2YSV2XH61RG4E84R","JVNGX2AR684RF4VRYFSS69WNMJBDDS9Y4AXFRX5JRFES5QBTMM51SB84BN61S5W0R7PZGK09NQ8QMX7Z90AE0JJH76J7DCM94DKWMV88K966NEA2CNMS50PG6D0K73619K67S9HJ0PQTQH8YD91P4CQQZTRPV7Y2RHEGMBB2G67ZBVVH1S9Q0HYX69Y2B3J2WYFMH3BJESVGE","6MZ6ZDF26MSAZN3VK3QDY62MD3AXZTK8K46A7ZFNBVCR33AE6H3A309F822EKPHT2YTJB6PMSPSJ3ZAE99Z5Q2J8F87X5N723J713A0QR87KYJ2NZ3PFCS5CC8FXJYK6YXZ4ND6FHNJRJZZZZRXE05VP14XW1BZFYZGQQZ8J05FYKY8AYFNCZ50WT7W8M83XS50GTYJGQTNPT","Q0JWR4WRPYT7TCNCV47RJ1FW3HEFQABN9EE27DBMDB4FYAVK8X9KM38HH9KN8QW28RXFXAKT3MGHXPGRWCY9P313CPR5Z2XSR3ZGKFHQHTP1A02SSD0DHH12RCV5TJ7M86WXWT7F00CQ8HV5H90MFEDX6J2X9JNX26NC0PRH0YXHGW7XVWXF00ZEJCGJDEZ1EVXA5BNW3SAEY","B20PSGCM77EVSXEC6T41N1T55KX76B5K3X38VBQ8NSAN2BKNH0W4DQGVZQTBA2588YCRW1TN9G721GP7ZCP9H32BBC9HM3XFTNJ4QBV2FMM7KSG6T0H418EBNBGKZXMTD9ZDVV6A2TEBMXSEKYVK9HCZT8EEQ7E44DWBDHN274N9D4ZDEFCZXNF0MKBM3TYZGHJ5T71T88CE4","F95WT8Y2WRXGK07MY3FMV1Y6PS44CMP59KK8G82EKW3Z0Y6C6QZ2CVC4A6DF9N3E6HW8SQ3CF4FSD1QC2DN5E9DM5G762DW491BAE5RC2A3YPGJTZ3XBFJ3R3NSRDRZMHR6Y755QDRZZEVFTEPN7MZ90SE6KTQS80CHNMTX15NMZPNFJSCQSEJ9RQJKZBH9ZZFMNXT8BXM7K4","1B8GKDJYJYCZ8Y2HCETV6EWA8FRVR0AAD7TRXFXBHNF7G10CZYDFTKBJ8X0J0M7VR1KQV67SF5VMM7VVG5ZQ4F9QEKRV3GSBB4M75CAXSEXSHDT36RJ6A98EKP3EZXT65HX2K788ZE4SVE5N2NJ8Q26P318PK9X69YWB4W7R1F1F9WHZ8WKJ69G5YZ1T9WR1N8CXTJASXW3A8","FV0Y6B21F01D5EH31R80BHG7GKA08C7HN3FYDMGQE6HJ2Y9ZSVJ17HR8Y22WGPN98T08E6XP4PZNMJ3RHAFK8DAVW3AYM5VNPHV3JSB5B64F0H60EMQNA59A2QAFRV3FCHJQATY87SGT9E67HRVE5QDP9HJC7A351WM55VV5MW3T251VVZ8N5V2GVX6MD14MR9ZX9TBS4N30J","K8QSPQTEV9YZC7MC6AT9R8Y0QGG4PT1V45KSSZR2YY9SBA3QEQG7R6YR4RKEKR5DGDM2K4DN9K128TQMMPFWZR8N95F29Q8E2WBD22F5SRFPJ2KJA6SEZ6RMPCHG6C4BJEV7PZAEVTNJDK8T79PJCB5B97D5WQ52TT2DB6Q4S599D61AA54FCVM9R3AB03PDTYZ0PCKBMJ23G","1655VA0GT3ASG2JVEZ93BWE01YDEA70ZW2FD1W3AZTD4B4WK9GYPMM9Y6KXDGDDB2TMDF5CWXNAX0B7E396E1NH3GCK8KFHMGXNPG0CTD2KNW9X3QB4HKK68JM2WGMF05VJ6K4G76R4A10JWPEZTD554TSFYVEM0355C9E5P9W5GFFFYQMTAXG43V8GP7P4BDBD81Q9G87MXG","J3T1MSDB9ZHCCNAYDXEQAMETNSCX5DJYQBCXGREMYAWAQ8AJCY5JV00HHX31DVT7X5S25CEX88707E81X4KNCN7RBRFMFNP8QZHFZHXNS6MN7BD4MGRVQEC50EWH6N6EFY1GA039KYJKX24XMGZXKB27H5R0RKN7YC00EKN99SGKF3YN7DPR8880MG457438G1YJR7BGRCG7J","DX73NQ14FVC978B1HP03MWBD83YT6NVP607WB126RAJPKPB11GSWB7H9W0QJSH9WD4SN9JJE6FDMQZTMJXCN1AKDBKKVPWW9VBEAE0YVCG64S16TXMSF5FTWNXYG7RDTHK03BXDGVXSPZFE7A2F6FPK9WCBBZSMKB8EJFGJK1PKKBHVA1Q2MX91NK32XPF00WFWZCC3N72JY2","PKSMQXMCT9H53FHGKVVPPTTHJ0M5X4SSR0XARN34VV7DX9ZA9N8379NVQKN4E5V6JXAPEVGPREWD720RZCVB90DDHRFW8GG6G434GR1A77SVPG9GKP2DEKBVP3CZ9WDMQD9RFZZ2Z3ZQ34YVD2J1Y4AZ52ADY5FXPB06W9NQ9NH7AQVHTPMSTP181MZM507M777SAPSCR9J8M","1XV578XYBQYYSV9V8ZRACRG3JTN103BZFPF5JXHF8YDCCCJM9XS343JYM8N6Q3J8D0NF2T8TPZKCB32MC1GXWZZRRWQW77JSSYXGA8136DNFYTCKB8EP277KBXAYXBW0ZX7S13J5NDGR7ZJ7QTAAPTEAG9MX6QBT9Z7ZZ1MECV7Z0D7GE7Z6KWASE5T4SW0MFHKVD1EAFNG0P","86PDN3KMT8AW8TVXEBGG3199YSEDMQX91QW82QVZ9TPYCNS3YKK3NCK5J64VKPKGJGQJP8E3RX97NZ4RDQ0PR21QS93MTWXSHKCTK2KTH7TQPKVQSWPGVC8CZDEGD9X484HJKMQG56RP1MZE7AWKK9C5ZK7MSN21GTG1KNF591Q8DVX0TM06BD8VGF6QNC745CFRMRSYHXK7P","KGXXZAECQ6DETR97HRYKFC4A1WAKC3S0FYNHS16J342WMPPP78NHWZXSEPN04XEQY6QNR9ECWZNXY6BZHXWAW2EV42295GBVA4R2J2KAK9EF7MR2789EHY0MVQJME1ADGEPGCQ02WHWT3C173SPDKW1DA5C8HBF847KV00A3F3ZM2HE18N5MFFQXBB014HK0MC4NW6G19AESR","92G786WTFN4BP3Z2RX1Q79ZPHGMPYC21K646XA8AB97V103DSJY0S4Y1FHHSHYQ8WZPWF0W07VY6CDG66438K8E8DWN7CCSB6R8KSC2VNAQBVC1ZD2H9VG33309B6QEKK5PYAGJZN5NG0CJXW9RFGPCNJJZW6KHM4TCMDJVKV9P953Q0TWVM2YZWK37504QJ41MZ4KXN52M30"],["NG0RYVSNPXP4B2NEYCTVC5A0EW5PFFW8V3PH9X5FFQ2VHCETMWDPZ75HBSC8QDBCWZ6EV9SEN1SMEMXABK3YTXBDDXYTN0JNKX1ME9T71JJTZZQ7XA1890DZR3ZAMD0XW8GZENDNAP4R5B80DQYFDEENSB141DZ0HG3A3FZA7JMCSBY0Y0PB2AXNS25Q6CQ5WA7GWCWA09PD2","R70NVRHFT6HCP69K8QQM9HQX0CZQYG09VV2VA7RKCVFDRTNH44XZHRBEJTBW1ASDS7WYA47PBVPB9T77B32ER6V2745Y8B1P22CZ5T70WTE6Y4HSS60CM5SFB6QT1VXTVW9G0DAC3XY2QDX6TKKQA1HX3RB0GPJH47D08KB1Y4EP1SXW851CFNEE373YJHBNYXMSE3MJBCQFP","JGZK4NS2E8D1CTR8ZAR5CHGN7T09Q41P545ZNNB7RMYV0CZ9CQWJWZZWRQZDRDCHV5PQS9G6WZB37CHQMZ7Y207D23FQAPMN6CP30CXYEQ449R3V7B8BYGJ84VYW60201B4343GG75TTTN947VVEYA3BWKRY4M5XCXSPAGW1TTAH9VAE8CBXBKAKJESX8XWS4W5PYBG8793TR","CEVHPNNSWR438ZWEK27YRYBKZXVBT8AM9QP2KXWC59ZSM8Q7J0GZNXZYBES04RB7BJY4D5YCPT3VRT7EPK0576809CG98X5SPTQPSR4TZ0R6DWMXH9893FCTVJX2A4H2EGSGP3Q6H53FD4CSDBMZFZVACXPMW1CR07A1GG7XFXSK1BP1BTGMBQD0818G6BC6SBFTXS1Z68PD8","72BFMSPJ57Q1B88JS6NX8YETQP0GSSRHXM25ZBGNW06YGYJ7FT1D7KVGF4PRKKQK8KN4MGHK5DXRQDTNEJSRZYGAN6DV5QAW9PACT7FQQXG6G4JS7J129VXFQP3DYTV0455Q37H5YPVGMWXZ4GNBQJ86HWWD670XY8JAR4WTYHX8FWJXZW57Q94KK79SD51HBJH1SJ4Q5C04W","2MDED6PYFV264D0SETN9MD4F0SADGVD75J8Y16DTSABNPW09AKE7A5F4QNB2124WDQ0HW4SGHCX26NAG46Q960Y01VYSX0GQHVKESSMEAZ2426GJ8KR0E6KTAXDZY6HZ6DRSPXXGZ07YZT2XF696CP8215HE92RGT7A50H5XXV2FDGFWJXYNCB7QND27ZWYWTK0KTCRYT104Y","267QZPCB0QGC63V9E75Y41J5285Q3FX6KQHM08MAKZ248X9WJK5H6H903C0T02W4G3EA22E0C1MHCWP5VRAEC8D0J0VYW9JNCH9YGPQJ3P941AADABVXG4M2K724C8VCFZQNXYJAMY4Q65WYHW6VYPN9H1K7ZABPAZX82SSSBPYKJZBREJ15MSS50R9HJ6FWW7T9P8ES015PY","7W8HPWAGBVFK0KTWG02RRTWKAE4W0PJH76GH9JWD7H48BS7CVD1T38QBX7HJVC6PJEAJ5NGP7MSJ9D5H1FD2T9Q5X4YQMQ1F80H4G8GRGXFKS863G48HN15D72EZSM9V8M75FXCH3639PHENNV35GA6TWPRS70HEJSBAX9A52DWTB63ZCSZXFGACZEQFGR0EKEE0AZB3HKE2J","JMGGS2DPDKNQKTM593M69Z1R331654KR6N12Q7EZPX20BMHV1P9JZZ8HNN6VHQ76YKWNMW9HR3173C2J66R8EVVWZAR001Z18F9HJ9YBVSM1Y94PJSM57GNVRNN0GH11A3ZRCA4WBKFC64A4RE6KTYMMJKJNHTR9A75QC7JWG5YY9D0J8TM9KXQW8495V702VS0E40121HNHY","REH6B17HSBJGMMPYKG7EA1J4G1D7H95N20P647AWHJKY3VA5BDZKN84FEG0G0FK6TKNN8D0TDFQ41610SK9CBR27SFD16PKEZ7AP97NB9ENPQRQ9PEKR76KB6VFWP666MJBTQJ5R7WGKTTE3ZN5Z2VWY2CPB437746CYBN52G2P2Q7V6SDGXV5HPYJBKXESS1JMVH3EHDC988","MRE9Q877Z18VMFNH1PWNH9N3Z5YE2SDZCVVFBZAA41SSRC2F81D6F9TCZP2AGYAEXWM3977KWJ6SV215ZJ24RAWA94NCKEFQ1CMW8MYJ063EP68NVVPH51SFVYQVHYC45MGNEXK61R9KFK6RWYV5Y6CHMAYZTW5M17WBSHBZ79F4DSWHVVY7774FX3WEEVM8EZ0WMJWY99A1P","2CM59NJVJ68NYX5ZJM2ZX7JK8EW7JXAVE0H2D1ZTX9X6X72P9768WK5GG3ED7MGEYGFQBK5YSSJ0DM68DRPDPTAHQGWTGJ7E79GAW96BXHYV64BQXXEV9YQ0XR84G8VZWQ8Z7T9VX7VQ0HHX1SAS3NGNZAH1H03KPFNAZMNMGV3H4Q3PC96JHGAP5JNDWA1FAFJ410REB33D0","2KEXQVJHACQX7V1XGF8PA6DV0EVAKFNSA037YJ3BP91NNQB60ZBAEFT9DKVW2M19R51B8HGQ2RCBSWBRHD0RFC95TYGJVKNJSCMQPXV7SM6A1JH18DFPWB1AJBS4SSVJXZ9V72TY2P8Q8ZTBMGCYERXCT4QJMASTQM1T22C9AXMMPZ1BHKNB2FBJ3TY9AQP4ZGHRSRBKR75E4","5Q9ZFEFF6C6XPGM78EXAWJF2CKJVJ0SPA113XT7R5JTRW7MKE70TETKK1MBRSTF566AEZB2CBX6CR10J6DPAQ92GC6XYK27A52KQGQHR5W346RGF28WE2PPC8S3XWTGCGVP318AKKTC8GZQ62FRYZVPTVF07HWYHDESQFKYNSDRNV8Q5KPGRQM27SK3CX14RA2K9KZ0NJJ0FE","7ZK7H90WBS080M9TH8XH9DNENKQ78YHYSXWF16VRM76YDKP4RG97DEM1DBX84VXH98M64CJS1GYTDKG4XA8XCNSZ4KQ12GAXCJC168DBR8Q4M29X2Q70WNR7BZDNH0DQJMR154M0C1NH2EHJBKA76PNZT2369PT9Q4961EBCY5FE85EKCX7584GXBMHQF1GRDVCCDVY7TH210","CFSSPFE27VKZHPS7D48AAHE0C2XKXS774CDPFE530P5C4EFZVZEP1PTS3NYB7KBNHNAGMZX8YZJVTNJAB1DE7GCRG43Q2JVS15RGJC4K9PDA0Q2MG4DGRX1CM28HE8CB1XWVW7MCDJHPNE28NWN0CYHDES8GHAZ6Y50NNZRN31FV8C28V0PRNZK4WFAPJ4EGV5NQPHGSZAWNG","9XJB29QY06J1DYBXQRV9F7M3T11JTGSZHX8D0Y80Q07M646VTHNFKNA19CG84BA2DKRE1D5DS3M72QH29S9EZEADW6PCS1FXGCMGZ0RQXT5ASSX7VBQ40NGPYY6PFE6CYV45YYEGPGJ2DCQCNYP2Q9E78SBD53QTQVYZG7W3QE8EASEPSZXP1VVB1TYYHN0B1BZGY2JKGWWPY"],["CSATAT8AQRB91XKHJD1B7MK1DPVPV991WZM4Y2NF0G8SNQSR391KBDGHR0AWGZ8V6EYXKNGTACT9GRBWWAPYTDPWFZ5QPY9GY8Z4YDXRK1QW30YT6JMAYQM2TH36XP81G2X55785ZJWCRXZ9QQDGGMMM8QZTWN9TPW8JXH4XM8A0DPG5354PF3782GVC8J8DXD7KY88KT0FZY","4MG8W9X1M5361HRRG6W9QF13EQDRFWVAQGMWJKEESZ3FBCWP7QQGQBBDT3ZYE3XARBVGJAVFQRQPAYA1PC4CQYRX0CZTS0E4QZB3ACMXG9XJ91VPP7X0ZG08WXWMT02M9V4HCHJ7MJQZ7EWCRJAG7E14BQ465R123P6QFGY770GN0BBNT040S3XPC88CD8X3D8497DE2YA1MT","DCSBAHV955VGACX5WE2N02QZSPQ9N375DCS0W3298N8KF59YHVTS7FYJ1NE011VWF8ET7F6SQZHW1NWJZW3XYWN2ZMWXCRGH80CD6N8YA6EE8Z2N2PW4T65M0DDX4YFXZPG61E7JJGK03VTDW5J8WS2F2R88GNNJMWBQCYBWWTZ34H7J5XAPBBY3AF4M6A8C0RAHPX0FS044W","5CKW4V17Q2XAV54F07X0C2NZCRZ21B9M79JM37F10DZJ3YMY9WPEWSYEDC6DP1QZ2DRRAXDCFG1WZH3C0Z58Y26XGSC28R9Q3ZFSKZHS0F0DC08JWY01W9GPECCN0CP0Q19N7GWX7HAFVR0PR89P0DTBPJ02NKCG14HZK933C6C62AFS8GFWNWN7FJ042YVSH69BAM9FQX4JT","G3J5ZS034N9TKESCEBQJQVXJMYB7HX48QT7QTEZA688019KSSCFVDG2TD963JA9NQF2G80Q3J1853PRB8QD2WFWDSMPP9X4FXKAEH79Q2X8K2KZJ120848KY421H81WAA1AMPZ6APD67RDRBKM0H5GN974TBQ8S5ENFRJSNTJRJEDY57GRHAN8V2R2PCNCY1VWH92EN1MJA4P","BFTC88T9TMD6EQPMBN6M7ZES14AGZMK8CYF0BQ7JAPPAPKXRTW83Q2ZF5270PG9WN0SET02R2HHFEM4J66GDWK2GYCF6GBZWF0GAH9ZC0AHVT3JW2XWDZ2X1DH2WB9Y10A7QB83S3E1S5DQEJXD6AS4J6HCBJBZJPC1EJZP3E5R5ANY1EYZ7P1692WSNABA0KWZS5T05DK51M","HFBFB0NVHM82461FBYT7SKWR1R38QD6MPMTSZXQAAH7CKVSKE21M4KZMWE3EF2C0FFJ6QGZPFWYXM58NANQMHP293WNJD5NYM31ZGV3ZS8SDP9DK1ZVSF5WXW3PEKYCAR3C7J6QZKAT1CVQF86P6M3S7XPVN8EV212SG4ENANH650EF7H5RDBN29PRREWB5JA4PSX9TQR1Y92","1JT0M6407RNBHQFZ0SKEPHQW2ZTZTQ5X7BZ1Q1FBQVR9QBH3EP20CH1KJSP71PC8Z4WFKJ97442BWG991RJC0XE7Y71PW9SXMPX4MG1SVN371ZG3GNCBX3Z9AZAAR9PGHS46AVG1RH71X1WQZ7W9HGQPRYDPCMQBQ7N2PD0AH8EJMT2ASXKPNK09S9H9B0ZTYMB5KK2VB7C72","E5PWK8V063470P271354CCZ3JS5H6GB8GWPDCDB125CVT4YHR3MGTYAFTDJP38F2WSNERY5KNE9VK85N70WC6VZ22WF7MABK2FJZM3179NHBV92FQC19BR21002AZHHE4A171QYFX69NXV3XA90HY27ECQ28YCPZNKEPQXXVCNHVSFJJE8553M68KM81EW45GXEV3797W2KX4","JQGN8RXXYMHG8MD2GSNQ6NQ8QCH8A6WDT0S0WY4ZP5424RGY975300CQC1C575K619FY2JN71RQ62RM6W2TBVZX0Z5B8A2PQ2MTN6W486AHBJKX6ST9HA05EQ9VMJN3PGDSF1GACENFK8CA1EW4KNG185PG6CP7YY1TNX3FZ43H020K8SYTQWMPM6FAZ5N4MA6CQND1ZJ6AC0","NJ5PM2Z4VNYKG6X93KWH0GQZNMBKHYM2FWX0BSNPGJ18Q7R32YC9FPC2Z45MPJ5EZY4E3FD0CD67TB9K4879SQ33SCG4Z9BARNQVWXMK975GRGAB4306D1W7PF1QD1MTVW79DHY3M2VVC01R4T41M3TXYTD1X3JF1PBGC4T63MF9MJS4KZTS03Z84AY6C9WK9RTNHXN7R0VJC","1ERPPXVG2NJ4RHCD8QED1E25R6QCAKKZWRV3EAVS4Y17ZDTXK46TSBJ1MF4HN26K3FHRE3PVBV4DA1RJ36R70BSAHSW7KTEGJNR8M5FBJ7ZDT907X2H0RMPCDANGGT9Q8VWYKBAHQ1T72S0ZAEC079SKV16XWTRX698P3P2TCJQDT7EA0G67N82YFPRE7YVGFKTMYXYC7EH1E","91CHR983Z222JN1695J11YY836RHP6J02SSZ8T5ACZ15X0D1YAW8VTCMECW3CPMCHG2RWTS5C30HSRWTYHAE3J3F61Q5N34ZSBVFPWJMN8WSFTAFEG7WZDWCM1VJZX5KZGXF7RTCS09MHJ0WRMCGC18WSR2SDV64P9HE1WTNCD8KT65JGQ3ZPWAWVJNJS63YNTGDPZ4RHTZ78","8Y2GMEETX3N9XTAB124JYKMHQH29009WJ5KF6V31WWZ99GXWZJHC5C03P3CKMB4R8M7ARQ3XD7AHPJTY2EKKPPF9QXWN7685HDTPT2SBCQ67XHHRA2RJ5E1S4VFP2YB1H0W1D9RE4C6WDT7FNVWXFHXAEQAJRJ577QNJD8G4ZSARSJ2SP6625AW9VQVVRFS0FWMBWJZNHXGWE","33MH8RQ5PXQFB0Q2T0H30VM9G4J0ZQHB3JHH8MWF5K3F3KDBAR20ZG4APHCTF1XRG530W7K2476P7BNFKENP2WXJ4HAW6RS91EQKGYD6PEHRYCVF8JJTMWR32WFVPV5Z2M1FWKNNC5N4CC3MK7S2K1V05PQMZ347KYD45FW7Y4KKJJ89TDPT7SFSQP1A0J00SN3MMTSEGXMVC","HR05CWNNQ5VBAF0WNHP8DZGN3S0DGYJ37EYP8S57MK8KDXQHXTPV2SXNJ2M5SZMS43BR168FJTB1SC9EW9P9YT7DYRBRM7G0VSD86P4QBG42NH06XYCCF7TVN9H9EB5K1G07M2Y3TT4WBAZ2Z350PV67ZANG43054GZA4N08BN2WEDFN94BNFKF45C10C3FFG77D9P3PDMGVG","JS43E6R3YEVTRZGRTS3RF0F9PCW7NBTWB6XEV146AXNTSKEKCDQ8CX76GX6HA06N0RTA699M99FXMD4JX04VY961YXJ18G96Z1AEEJ5BR5A8GYEWSNJSR5Y55ETBCKHBHR6CJ8A3659Y45FNG7H4C1K44WZ520PE4NAQVJ9QS1H2RWQ5ZZ8H8J8WGBDQC6DQYRTQHR0WF2156"]],"link_encs":[["7A1HVQDZ7C2M4K913020KMYGK4K86PM30APZ8AH5ERT5Z83QZPJRTGEFXF0TGYH36R1N36N3VKB5V845FK33ZW3R4G01X6CZNE37XHXE707T0TA4DYGYNX295QSVF5VEPD8QMK1J7ZAGDS27QP9H1QVK3NRBTZVRZ23XAV642CGEFS1ZMPWEDSHWECQ4G6CFK1V0K2118BQYS41R9P05NZ18PY3Z1FWNZH472HTKWT74KC752S0W1C2ASM428009","VN0WT37PVBAEYW3GH2ZGZ6X37R0XATMMGHJ86G953NVD6TE608Z3A6P9PG9XAFAGPQ13GSQ435C8763NR5T28RQHH4JB9N578TW7FHA5Z4Z6MDS6CMFK9A6ZGGT35G28NH6YG55EZR6GCM5E2ZKA8A9TR8Z8C6N4BTEVJCCJRWQ5MG8W4TR5N3YNPA7NAM49TYECT56BHJPCD6DHJ3XQF2XTZQTCECDJWZG4TXK3DEZM7Y55XFJ49C7F1P17MWQJ","88RWAYX9765MBR4KBM2BN9NSQ5KHWFC0AQZ6B0RF617VF5CSJJZBB69XEVDFC12K5D0T06KBE71BHK9E5ZTEWD5FK4Z2JVKD6WV6QBFHQ8Y1ZPP7Y2EYB9XFW7S9NVM27FNX8RKWTAJ45FFYKJPNR7MX5HZZ77B25ZB57Q0NJB1E7ECH4QP5BKZG63CF5M75VA633AJC7A4XWR8JJTTQDZ40KJMXE15X9KPABVZM6HSGF19P3N2SE2VSSWFXF3XH","MBPTJC2E7C7YQMAKCJN8EYBX1Z0CG8Z35G5VW3AZH3PAM6DF32AXKFX06Y9686R1CC1TP5BWX94DMN78RXSZGXFTEKPK3RSEVWQZCBR6BWB7YEEJZTV0C5MGREJE73RP40730074SPPW6CW665XV5TJA5329ZM0XC0KJ3MR9V70TDCE3M9DMB1JXPN3M97A74XG6KNJ57FKDQH4C4NV3Z3MJ276Y9MDAPDF7GM7MW7AQ7T1Y98RJ4H6163WCSN6V","Q2YNH71E69EDZ1NF8PFRS66PJYZ360SPQVQK73422944P34FGDZVJPMF59Y5KVJSB8VTJRPVMBJQX5Q8M8BHEJX1YAHDXAAWBTTBFM12CACZT72CYH6S80TJ8GYGS9ED1HBBWWT8RTZGMD8R4NMBJJRED107EASZJTH4SW32FJ04X62EA7YAMAJFTPCC5E6QJ43F0H592Y3J81NXQS66P6GQXKQMCN5W3FX8ZJ3160V542YVE2FNV3X7WD88FVX3","5H1650VJX95VFVA0G8ZNGWBCACCZ53D6SNJ2S4QVD27X2128KWC4MXRH8B3FK89QXV07NTEAJEXGDZC8BSYW11JZGF7H3D2YVXX8ZEEZBHWESCN7TNSE9AQK5NBV709PNHP9KHE0K7KEJTY2GY08CWAN1G9CQ3ZPF71NEHC7C0C47GYNVHX9PTXAYH2ZKQJSRNNSERC62CFX7NQD5TPF6WFEYC9R1AB3TWEQQF3FKY5EAE04EAEQJWSW0ZFGRCZZ","F5DZP7M59MGX6YJ3M3CEXVSJ0FGD3Q3EVHSQDSDDKSFPJ7ZBN60SYEBB293PDCFZVKC7K4HZ54E3XM7G3GECK2ENZYRCQMS6PS7VM7DYKF7S56KP0N4SE6X69Z6EDA309XPHHPDGRG1593SZ63YN63M815C2JP9M5E7H4FWYWQQNA9C81FQFNH48NVF43G3A54EEM3JV6VKB7X9H3SESC7YRA862NZF42C2FP5MCSACPQBSX0HV2Y6QRZW53BTW2","HJ9AV53HDRMNPEJJPSEPJV98XXVK1D93WT9CQNNY7B0GKY2TTAW55C83EHJQ6SHMRYEWQPBS096ZKRDFHNM5YJF09V0NFEYTTJGSMFCDYKW5GYCZRH3FGZHKEMNN3S98WV5KWDG5PT0S9TCYTDW074WPNMTH9V9KE08E6N8ATBX62PZ2X326TT3N15RG3ZKHQ09360981ANE6MVMTM2J4RXPFMA936KTXAS0EF4FTTGZA1GHS4FNG0JRFBXTNF0D","BXGHTGZ5EWJY0XKATMGECZB8QM74WH1RY4FB4KZP0VQ4STWVBY0NMQ8832YWB04GQ2B50Q5RTD61091HH1R3S2DK6QD7VJYE9BZ4EEQJTDTSSQT86DQEK2QPTXQ8W39WBTAT8PKBT037JM9DCYAC4CRPGTQWBZK3M1Q8BZHRVXYVGGVC5GWG3YQX075EQCSD9Y18N08JKNFHJKVZH6X27ABDHC323HQS30VS15BD65GZ35MH4HBFT7CAHPDZ5C4D","D3EF8ZKVNK6PCTC7KWGDGTSA3804J3N76R186NKQC3YJPW9P9B6CXDN9910S5RNEGST7MSY566PFZY2NP95WZNJTMG8988H3HFVXTXK2TST59AFBNDNTGAK3Y149WVWNDAVZ3G4NM9R75HSWC75BGNDRJ1F6DQ8QACZRAN9E4K6J3NZ3BNG5A2JY48TVXEC3E6TEDMF3E4Q9QSWQXPEHE48TJB5J7Y98WTDDWWV3S186BGM5V06PTGS3V2QRMRW1","YXS4AQF8X7VR35BBA8RBRMCJCSRJ1K2820ERJV75TZ5X3XBB4S5A1EKAGQHRF6KENMX4GEM3NT30K20FD9W03B79AKARV0KK6SMW0W1DY68KWGF69JH95RCHXCSVVV8XGVC48CBW1ZBVPFXS1BEJRDBHJV5229R5CZ9AXC3DNSS7S2QYENQZT7ZSKM9VKYGN604GT55SXD0NXJ0QCVT6TG8MTGTTKSM9D1DFKGDRMP251FCEZVG4XGZSVHKGVHGY","2QYSG97X93Z5TR1JT9FJJG05T1ZKZCPKZ4FNTBNF3DT2WPJR12QF1EPB5NSYQK068XFRKK46YGTT5GX6QEJJZ2B61A35RM30HNTP9S794V2TSME26S4RG32M6AYCNZFR6YEXBKF828ER3HMS1XAF8H475HQSM4M0004GN2S2EHMBXR62TYBEYE20GB123X5V9B31W9650S1E833Y6AH8SKQRE5JY1AK0NATPP6DBKWRC3FTEV6QBDVDGB8B3FKVB","XHTD1E2BZMY311GRBP3PJ6TNJ5S9MMWYZEPFKBF98X6Z3B9GK8EKYZ9DMN0CR9JYQ95KVWETVEKGWMF3V9VT3KK29WGDBPCX1V44J09E2AA1V72A6Y6B6KXPPESB3SM2TH0DZZC1AYQG7TNAMWTQ028ECEZAW30DE3S4ZWKE78ZZJVKP4ZXFXWN3JTRY2TX112B3TRYH94GNYJ1JKGHVG55ESYQTFN7VPPW8GMRSJRVNJZ09S4P37G21HBH46NCK","2N7GXE2T60XCGFPMTS8YJZ64G6STTNPQ4R31CCRJ9Q3F7KJK9RNW4JAQ0VP0A0SCQGR12HJ09NW0TMWKFP46XHQWRJP9WMQA8TXPP6F1SR9XQX7A8KB73EGH3BPN8X5N7YY95M7ZBD1F4SJK24HR0P0GV6BMEEQFTE86QGTP67Z7KC1JPANYM1B3MX9Z9CVESD83WX4VG459X6YR2HR8T576M0EV5K73P9397H25ZSP0NXSAMGY87R0DCQM1GFR3","7WKT07H36FAWM8W3X54AN2VAGJC5DWKP2MJMHES1NA2VFVJD3WAWJJCNWARWP17SQSEWS38HF36A63BNR5Q0Z2R7VETVASYVEYRFQYFGW3KXCVT5AS2ZHJCDMWRJ0N5EQXP0J7MNMCCCQZ8F304SKWWMAQJ8EB5Z7KKM1T0Z8WQHZACR8YTATF4XSXSSJVPGGCXNC47B11QM4RN3HDGXF9MBZZMKASBZRF8AA2EH4M1VFG8NR243ZE3ZKK3818C7","FKZQB344EWN58WPNVZ0BR5A7D30ZR58HZN0PQPVJBKWK3F4A4DPNEV3Q8QXR70E8V5WT4JX8AG9H3X5RZ74DQPKH7RT4M4747NY98P4J09R58JP7BR58KA8Q0AHS6069GHNWC0SX9GF33RV9SA5ZYA75CV37V1N5GRAPX6A0SWR76B6HYSPA94G5PY02R9B05W8Y5MDWDEY70NW4ZXWG2ZH3S68SSNP6SASAJV85KMH6CH7FZXTDYQTAR0HDB4K7","3073VTHEC9679DTAPZZ2J52N4PXFJ2B5JDQQ4FEPWCDFWMTXJK4KTSVMSF6DNMY8BH3EJDS192CK16JZG95JGDGYXMYBAFCY4X77AGA33DZSNXT32VWNVKKP6PN5E7JWRDJT8SSCRJ6C90P9YZ31SFF4PPKFPSVZFRC3PD87CKT8M9D6XDWN61D0PMXKMWGJVSNQDR8NP86MJYE8KGHSX0SWDV2J9N3X9212CXV1JDQNS3DFJ7XEX38EEKWQDSJP"],["8HRTEYDE0W9T678MM8X20QADH4XHBW7JTHJVFDJDANF90K84P7FK7TN0KJGE5BW52VQQFB10YNEQ8S9J3WVRV229RSMC9FKNRJ60968J536EYP24C5WNACGATG6AG8N4YNDQNQQM8V2KQ6DX2XVEH3Z86W9ZYKW7SS4V4B2WM1ZT9WA80SM1H73H9JN62GMMQE37XHVQZ212836WQJMFFKR29ZSYZAE45FJ14AQMP6YKF56M4F1PSATNFZ62VC87","R2CW58HWX89YHVRJ8WYRJ1A2GSC24H1BQW38VGBXP0MXYZS939BWPG8KQM4ED9M19QVXKZ4RC21RN62EC7E1SSAF5VW0BFBGER1FWW3ZHJ78FFF1TNJGRVBE2PF18W1ZXMATHZ12RRKDPSYT81YTGRGAYZ71GHYD1SKYD711P2J80ZTKC6YCWJ6172Z14VWVFA6H8JWWA8VYZ4XTARPXZRWR1Y1YE4232XYZ8X6A8HHWQXS5ZNSM0WPK8BW0KSTA","DE3DY2F0TCKEXVV65EHTWFKKAB2ANTDS435K869BXNVA8NQH4JA6X3WM0H5VAVFT3RCAVQ1WYCRWZ2PKDABAFEXF8RP1R4ABX04ZZS4XPB9K4R1T5KK2HX7GMWQX8RZ16Q40C44DJ70YTHVBD0BM6AF2R5G86SRZ8KERPS21RMPYWYBBWM8DR5YS1D3HM6CEJE6ZX6K398XJGK59E3FCHYJX0B2SCRKJB5E5G1S6PAB3QXKZ2SDGGQR7F8XSESZR","ZNXFM7CDW0M2XRNBTD1GM4FDG74G2XDMTF53N7R71J93YPMPXTT4G6CVZM9YZHCK6GQ35P9CHEKNWK9Q3VESZCYR7TDMMQYYFBNPPM8E4CVHNHFZSBSAHP6MMSWQJ07GZA9FRW7ZGDH6ZNEWNVMQK0V8GV0035C8PP2SYMH66FWMA24E3D15RMJSF4C817TD7SD4F7WG6RCBQ6Y0DDHAY4VW1TB5V4W55J3N0GEMX7AJ98T0TSZQRS6R9PSP1JA2","2J8G5KH2TYWDYHA2KX2CEPW58CRDHK05YX5TER84CGAEBAQASD9Q0ED8R67VBVMDQE2C9NG7V4T3QZ2VRPJPYGQXFPCXBQF99FXK1GBMEGCVP8Y4S4TTN8NJCRBTY6CXA03KQ00JKVJMVSWA85969C2F8YAG8GS5TBPF3D8ZT2C56D2ZD65ZB7F0E11S7B2RWWES7TXQ7HKXDWEBFMYTC2WNGZT1NET0JG21MP03KPS6BEMAX5Q5B139QJNCW8F2","K1605K54DR7EXXPBSWWFNJMXQE6QZS3BN3WWVBF2Y83WD42NMB9FZJG0HXPXVGVJTV1EFEXBAV7PY28FAXTVJHAZ06CDD13ZF7JE12D1BN6T6AT4RHN6N00A2ZJQTE1VCWGBF49Y5B75ZXNS7F9K352AR5A5ZXG21KV7VNT2ZPJ2B1YQG11QY05W920TEGSC8TW0J41HN035ZHCG8KBF5QN5RMGKSVZQV708K7DPVYM7NC2V7X2ZHZ44CBCPEXHD","MGQFD9DMYZD61RHS6KFGC5YGRG2Q56CYNX4GYBGASQ1P69N76M6P4CA3WZV163VFR71JPAXPK11BFCVVCS3A9E59WAR6R0ZWXXN5P9XJXD7DSA1PWCS0JVJ851BCMPWE54M23JGHNRJ03VE76HW8ZH45B6WGG809T8T2HQRBHBPFN3WC9NSE7NY07YWH6V3MFMVPQ2GZJ6QJP4C9D2AGM88H71PD0H65YZY07HD72F3VV1QBJX6T1GPY3NYPEHH3","KWJQX6FGX9XTEXEXYVWJ657TGZHYWHX24KEE1XA5TW5NVVQMQGQVC6HE6GA4RBC1MM0S1GWN7Q838QQEP5DQNDZS7VDBSEP7SPHC832WRN492FN8CEVSJ01AAE36HRXNM8DN6JPK160DJ4M842W9STXQRWPPF94S6HER2WZX330EZ9CECD2NKWTPTYSDGA5FVZS2GC9ERQGYP4YKZWZ8DXRJWCNVE1G7BYYPWNTHPVX0EW5F9GHT4MR29YG9YMRS","50FNFP9CQNHME6EDC0JFNXDVHW58CMC0TJRRZ0FGAYK0MAYQ9EV5WZEYBDV5Y967H72AQBJ28GXD394BDW949KGEMNSAWYE3YX5GSZZNZ9CCXEDKJJSC7W1P1Z04B9VAAM07SPWN4EMREMR9R4XXCD014YHPMMKP64C58X93FCSFJNW8XDF5FW0S2KZJHSP8FGRNQ6D62CQJCVPS615D4N52XNPWTFS1R379GVKSZ4FRR6SRTT4R3PA271HTX3ZQ","NA6QQDXM6SB52138M8CN3E4ZY7P0P9QS9AJ6EGNKYYK58XTRR4D4BANF0ARSTVZGMSJ7FP803B87J21SR2KT35V5K4FEHWVQ9WB9F9ZFMREFAA3SP3NWXNYJQQS0YA2K3RRAWJYJ2XSPQERXW71702QAEQRZQPMGXCMDKFNY9V7Q77147RQ7M87G8ZHZHX83D9C6QHKWGKTSQ0R66MZRCX29C6P6A5EGHACWVXD32Z8SA1ZPNJBDZY0PNJJM68D0","4M00E1KQVQ5KTJPXTCT3EYFN1SH975ZASNAWN7Y0NB12ANR6VZ1163GKCK9WBQJ34Q9P0G763PQ0B68WCJT2KXYXX5X3AV91BPDGGWBYB220HQ52V5VES6H7D75KYS176MA27G09X9PAGTQJ78VQHDAZCYZ5TS82D7HM5GT618605NVEYTYQYT3BA38R6V0RHYGE0CHNEXZTM0TFGDXQZ3P6CTNMYPPPM4E4PMCCQC4XR2S6CGVWYE1TXN0DC59S","N98TSJ6HGBS2N3K3MRPW6WEHBP409B4DC7PW8GMHM2QM2VGC0XQE1AQQ9AT1J4MZAK0B3RAMWF74XZT0D1CBDFABDY8M2M3X6QM7M4C8Z2DV7B2KHF3GBV4FMEG2PWAPW97QJ47383BT5XEYC4KQNXNK1K22NXYQJK0W5GS64KRFZWWKENZABG8VYZ7AYDAXMPVRSCQCCDE1RS6V8MDAVP65SAB59NSM0QQMBAPVBDTWD0P3HCZMG4F17QGTYZYP","ABT20WXHNAHYANMGCVGR9VC1QEQMS5YYRMMPS8GE04RK7XDF4CFXV9HEC1TAN77PBZJXAGX8GVZ8Y0068T84M1DQ90F2VEZGHR1JBBJ91S6RER8FKC301STT9MSF0CYBQTG5GAZK948305FBT6QRFX5BYS4NB5ZX86YMTNZ01V5C26W6Q6T78E5MHC7PH21SQ2VERSMDBWC640068HDX4PCJWBV7809DBSHR2ASJBMM32C49SG4EYVW74H4385QA","M0HBDKZV4TAYEBJJFBMMV55735T3F114RQMHBW2FRTDNNEM6NVBYR65Q25GJ1XNZJV0J7CY55CWMNEARHS2F9TYZPM0BVFZ429DVB2BTX8ZJ6Y9M1RSMVZZZM3GVE865PFEYCVG40AVC5T01Q8XGW1FDZKZTXBVCR5J7H24870S3BJB820X7MQMXDHNNT7VA4XZQJRN96JNHFC3RWB8R2X6Z4BZA9AYETNHP180MY0CJB8CJ8P9DTFHFRAY4M8WE","HV2FVXRE3NGW0WR4XMX0QZX2Z0B7MQB2ANCC95GY0FY9WD74D6CSM11YC0HNMBYCX8CTX7QJS28FGK9FC2RP79M8MKBGHHP0E3SK33AHRQ6457TSMARYKRY2SNSTV7JC8Z1KPV55EH5EH9C736G42J9W84E61JRWG8PMD24V1TS0MJZWKNP1QKSET7N40VAJXZE6B2QDPH2D7F26S4SND52B8KS1HB0NH762F41QE22ANVSXV6S2TN73Y5MXTB9S","70M04PP2WVXGK3NJCMPXGQQCCCDTRW0AF5F8N8A605DHY4CKBFFXX9F5Y512JS3CY6MD9T7K1X0ANT3N5VJRWPF9Y1S97EA2NAZ2W783DEP32Q1M3Y93VBHKCBQNM9M456VSMZA16E8SP3EGPJ9K7QVE0KYV0VWFJRXCA2CWDNNFDEKEJ6GK164SKGZ5MV1QQEDM258SKTQQ0EER895QRAA50PHNNQF1Z8MGHMZCV9WP0ZSJASVK63E4Z073TTVD","799TV24HVN9JDQBG0WFGA5FH0RNJYFJG2XF1B93W5W571CRPMEAHCAKA294YT63VV0K7C46AQYF1AVS58ZJ58CESDYWMY770P95EXPM5H38NV3F3RDTDB7EX5Q9XN0X8QRW37BTN8VBQ4PZ6Z1Y4539C7QGE2F012RBKGK47BST1TQP3XA427H1CDGT8HJBHBY8BD4TH1N7EE0XZF2QV6AJ0JCPWD0H6TKPVMGH1QYKVEKEPQBX20S8K502AYGKQ"],["23NQ8CW42D7FAY7FD7636SFA7THRQA2EGJYMFYF75FA1ZATVSMPPYSHTEC58J84PKDHRD0KPFMK811CTSGW0W274D8A3E5FKEX6P5AZ2ST0K9PK65ZP6R6CR8RMWSGQQX5VAJ2YVJ3RNV20C7YJA0CDCJNQX3JKGRX5NRY8GY3RNA38HG3SM0NW85AKZ0SXP1XRZRY0A0T3SM6E4Q6PTJMJZJ677BRZHXAGB7BEMSK6KDERXHVN9AGN4J9SZ5AY0","ZNZFHJ4X5T79G4DXBX8TPG0RV8SV4B7ZKV56CAN893MZ6Z00CNFPH6KPPXTKM8MB6MTPSCHEA0PRGRHSAKPBSAVR019GB9E75TFSXV452ZQN8Q54ZH9BJPKMAMB26X8BDQKGYK01FAWRWZXJ1TW9GVPJ9TS03WKQS64TVRNH17TTFVED3K8MFMDC9SFSJ4FZC2J19XTSWASXSY4BDE4T8Z2VGWEGDTYF0PNPMHDN2FQN2T25T6TA2DW702HM9MBC","SCC6Y84J99YQ598PR67G5VDT1N9E6S2VEZ22QWD7PQDX108ZZJ2AK16YF9PS8WSAP1PCPM0AYD1R9522XZNGWEHX92RE3R0WVM43A38450XH0EHY6XYKCK0NWJJ9XKN0FG4GACRF6X1WG4Y7AYW6FBFMBKHWDHP8BCTT0J9Q9XXZEBC88C57DMG18ABP6S248JAX9JCN0GZ4Q25AX6XYA2W2KD7CW97H23H11NS47XMC0GFKF7FDZK11JQXASJMT","PJBV9WQ064WKS9WVV0JWN3JHGNCY82T42FC0ANKNV5SEE8BBPJTQ6HXM76D8FAH00A6GNB2HMRYAAS0ZTGESRE2JFDD5HFAWW2EX9BN1QA7T6EB1G4PBFFZXVD3AN3GZKK72A4VT5AFM9QF7GHEXVWC29AHH5HH3ZHYQ1AR5TB5G7CNRCM8GA1Q61P574H0G2DWJJ35XE79D3G6SEWPCPB3VZS89B3XY9A1HV86R6BVY6C48D7FHXEA903AVVSMP","7HS65FGXB1Y1E39DHB5J0SRX8KDS7K6YBNP1XAPBQQNBM8N2T1QAVVS37XG15A2ABWK9J2CP16WCWNMG1ZCS6KEY98DXRNKNEQ099M9P392D00R8HDE1Y8C918PV0DVXKM3141CYJFXTQCYM9A5ZYKDEXNF09NTWHNDT3F990R6EWYS0TT4F4YDW9605SWTPJ2G29CKQNP13N1KKFRJS4BME8VE800YH6HTCSWTPXQ19TFXCHET6PF9EZE00RF9D","39HPW4NZCE7T1TF3ZFW6FGSSSETD2NMY5ED7T49572WAZ5FBJJSGGK8G45CQSSS488KZ2WRVM2N79ZKD78AX08X7TAW7DGWKB5KX9KRFCAF7ZZJQP5W6A1652XYNV2NWR51MS30ME0Y6RPXCMVC7K2B3HK5TFQ893HE8JJJSD2TF3AS9RGMPRBXXPCTC1R3Y5MZJQ79RKV70PVW65MA00RPMC27VGBWW5MA7FWK4X8JWQ8PHB9666MVM64AZJZSC","WFPTT5ZYQZNF2TYKSMFT6D7RP85980PTXNP6PS1HY3J5Y4ZY8DEVNPGFDP85SQ2DST4QQ1EHQQ9CHP9T1Q25XSGNKAHF9QAXX6N029SNH3C0MTG5VAQWQMCSPAYBW08EKFJS560JXX1AT9JCD0CJXZTX1P7TC4XD1JJCBDYKQ592CJZDKBCVMDN2CAG7RNXVSKQ8EWCRM7NCEF3YVWBJ7SQRE9B3BB067SVSRJQ9SB0PTGRP93WRNQ2JEGC584K8","P0VHPX17WERWA5G19P5NV2ZBWXGX3YWFTYHMSWQ2C5H82TPQ08BNDPE813NYWWT231EMTY7VRW2ZS8S447T4K5BCD7S0YQX2D92G5VRP10YTC57P16QZ37T0QZ9JENVPT6665TZ97JERST3M8SG7BD3ZDM5H0S9KCQTXXDJCR9NB1WHNJFTYZ0DJYJFDNZMTKREQG3R5VF5DQXXWKJ2GVKZG6ED2VTJR11MKYTQBMXSKP50RJYEZMVCZQ8H5KZBV","VDS1SGX5A31KBPTBPBR82C4ZD5FG2XRDM5KGVAR7X8XGXP7ZMGREXS9CYFKA9SZ3GMF0H7X4H733C81HPNDDC2NPF4443CB0KY0XSMJ34SA6TY99SE0NTZ96RZ36CZP77HRQQ93WC2EN3FBGS9WQMZEQ7GKNZSH6RBGXMF237ZGRN4FPRGX771VXY5DQXFMPTFYRDHCPWJR9FZKF7TQT0MB1K412PRFHSHM9S8FZJCHYR2PP443WF9SZWGNM2CV8","J8KEHBYBAQVMTR1XTNDY23VSTQVW5CYE2EDNRE9DBP56DV1PSC2XXFH8KKHXT8D3TM5G6MCHE0JWNHN6417G696MHY5NZ6CRAYYBNR4YBPHDF94CHBMZSXH6KD3N0AVW3F0KK88DPA9G2CZ8C82QTV8Z8C8WRRWAHRH0X6SEGK4BJPEB3WEGRMD9AFYTXCPQ0N7BXK83052V4HD6W7AB0AE7EQ789XF6C8AD4TN7ARF7MJDMTCY624B6QR5K15Y5","R5D4QJ0HM2A9E8WEVZYKG9V612D1ZRRB6RCGK4S8MDBM7NRBP7DDJGV1H7SN0JEZJSTW7DGVA7WRK0Z8HSH6VGB2NZ2CRZKZTTX15W58EB2XKJKZJYA0AR5MKTNHPP7D39PFF8BP39PJX9VRFHGXMWB84GHVMND6S2M2WWVHMBVNK2D19TJ1240NZFV6GP64416JT0QW06ZQMXVHVD4GFRESTSVBH1G78AMJ972RAHBF4DM0PJXY0PTXYWQSP2GZ","KZ0R0MPKXYKS13894TAC8SMNGYQ9F1EB9VN9S4P7VJ8KDXJEREYR64HDRAP4HBRY9D50YDKDPE9AHMW9ETR4CXK3E0YQJQ2YGPAWJ823GH7KHJXK1GTFSZ3TERT1VB31FGXC0950TY0MAHESMPHNRXSG9738C0CEJ5Z1TNBVV48WJCH2JPCKAPDMTSFYFAECZ28WJ7J9EW459NNT5H4D0DB5ZZ2CY16CCC8PBC0K4ZYP1Y2ZW5MK0N0MJTXGQ49T","YVH178SVB7QK1HM2HVSDGBZ1QJN9NRTG3RXMC9YVS74VXTW719NRFMAXKJHVZJE77HNRW53S8DSD3QTYDZ9ZNZ1185GZXP0NNP40NQFYJQSBHWVE7WDPR5KZT42BWQE1P20B3F5HCHV3VD1ZCGCZ1NF5K5P4WKT01K7XKXNGFTX9HY5YAG30THBY4S3Q3CPMQBVCBXDHW929DHRBZWHZGGGBCTVNRRNDA7J0EVBAVYYHES2PDK9YW5STCG83S5AB","MA1RKAT9SCJSXJG7T5P1QF1VW9GRBCYK03P8Z55KSCK4SN1K0MFSXR3YERD4VA5QQ1N7KKHPDAPNYHQ6QW2TPBVM932A5G42VEKZ9CH5ZH7346RKDT8BMNSFYQ799W6042CCJ3JSESFYMER8JHZNBVFWFGMKMJJ642BCP9PPA9H7B0XSSGK2CZYWK3RQX5WKZK4V40AMTRJ9JRZNX7QKXRN9W464J3X3BRYHR8Y70C42HH0HVW86CPNVKWE0Q36C","K8CP0BM60F6P218ZMC4HW307DNN3FHHEG3XMWN55KEZR4RQ86ADXGJF2FKD7QW2TVQ3AWN2KVJ6QMP6SFJHF11C6T68FWKWMQVGQWYY28591XTQ3D78FB9N06T2W3R6EERTHRQNK7X9WP2BV3VM43A39YXVJ0W0BHJ0XSZQENN218ZR4GTVDX48788WXFD6064ZXGMWGD2EKWMS4BBVWK59FVZPGDRQD6EN3TRA784HBBWE831JWBEVX3YGPX9T0","QC2WWZPKJDCFZA65QKSGKW7YTAS9RP0W4H0FP96Z5TGCCD0K9FXFX4F75MQEDNKCM0B34D8ZR46CHR97HMMEB3W2T8W6P8X5289Z729365HVDQWCGHMJSGM7AHA1HS6ZND695X67D42H7XB7NQ5X57XG2S32R767YPQJERZ0ESG3S01NGNQ0P62KM3AT28JX41GMHPEA92V1Z80RYS8GWE9CGZ6K66NVGW72SN8DJGDFVC7771HP93X6DYN0TF63","H3P6CNRKH4BSCAWG3T9RRA89EBF1F91JEYEY4RZJQ2NNCZZASY362XHME0KNM36R4SNQD956CBW15XAXVK70TZM6TBVMHJ8KKQQQKBG4Q91ZHKAS10NEVD5B36QGYM7CMJM3DVJ00KTK0ZAM8C4YRNZDZKV5CNFGDR0DDP1P38704Y3G9KFRJ455SD39J7ZYDB5GQV17ZF2PE7GY927S1KSXV4KKXQ7FRX1VZRJGAD1F3DY4KJFRZJGAT5951JNS"]]} diff --git a/src/lib/baseline/refresh_reveal.req b/src/lib/baseline/refresh_reveal.req deleted file mode 100644 index 3fb143960..000000000 --- a/src/lib/baseline/refresh_reveal.req +++ /dev/null @@ -1,7 +0,0 @@ -POST /refresh/reveal HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json -Content-Length: 255 - -{"session_hash":"V97SB8T670M9V71D1Q0KVQ4GSJCVQ5AAKTTH9QKT0ZJZZBFNZAV4NA8NMWRRGVPFEBEGB6ANCN9BPQASJ40TM4Y1C49648TJJ07PGSG","transfer_privs":[["EQKJA401A9NJ2YJDFZJ1EV8AYXBHWZB6NT5T0TWSJHVKVDM6W8A0"],["TKDJ4DF3GZVG0DGAB9E3RGBGSTANYB6JVVWXJGPMB2AY4VQNTBA0"]]} \ No newline at end of file diff --git a/src/lib/baseline/reserve_status.req b/src/lib/baseline/reserve_status.req deleted file mode 100644 index 4f988f669..000000000 --- a/src/lib/baseline/reserve_status.req +++ /dev/null @@ -1,4 +0,0 @@ -GET /reserve/status?reserve_pub=TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0 HTTP/1.1 -Host: localhost:8081 -Accept: */* - diff --git a/src/lib/baseline/reserve_withdraw.req b/src/lib/baseline/reserve_withdraw.req deleted file mode 100644 index 484950250..000000000 --- a/src/lib/baseline/reserve_withdraw.req +++ /dev/null @@ -1,7 +0,0 @@ -POST /reserve/withdraw HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json -Content-Length: 919 - -{"coin_ev":"Q5X8A8TCBFH7E5BMY7HSB17SHFTM1JPJGV61P2CA7Z9EXG8P2HYS69B31NZESKXHSZHNJ2DQN3CC2AWFNC6V90J577JD3TXBMAY8Y5M9V60KKT73Z1DW24JFSNAK91G1F2WT55ADP1EG7N5F9AY7A7ZJD03MPYSH0RDP7SVZS2KRPA5JRHFR4GDJ59CFNE7A43M95ZKQHQAS8","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","reserve_sig":"8427B3RTB217124EB1C37ZVJFC08KN17RHGHE9ENZQMQVJ0S11SAX6H8Z06SWCKT06DRQ9DQ8XD786XKQ94T27PYR9GC9EMT1Y02W10"} \ No newline at end of file diff --git a/src/lib/baseline/wire.req b/src/lib/baseline/wire.req deleted file mode 100644 index a4f1d0749..000000000 --- a/src/lib/baseline/wire.req +++ /dev/null @@ -1,5 +0,0 @@ -GET /wire HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json - diff --git a/src/lib/baseline/wire_sepa.req b/src/lib/baseline/wire_sepa.req deleted file mode 100644 index 80d3d4619..000000000 --- a/src/lib/baseline/wire_sepa.req +++ /dev/null @@ -1,5 +0,0 @@ -GET /wire/sepa HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json - diff --git a/src/lib/baseline/wire_test.req b/src/lib/baseline/wire_test.req deleted file mode 100644 index 684352c96..000000000 --- a/src/lib/baseline/wire_test.req +++ /dev/null @@ -1,5 +0,0 @@ -GET /wire/test HTTP/1.1 -Host: localhost:8081 -Accept: */* -Content-Type: application/json - diff --git a/src/lib/test-taler-exchange-aggregator-postgres.conf b/src/lib/test-taler-exchange-aggregator-postgres.conf deleted file mode 100644 index 7f22acd29..000000000 --- a/src/lib/test-taler-exchange-aggregator-postgres.conf +++ /dev/null @@ -1,98 +0,0 @@ -[PATHS] -# Persistant data storage for the testcase -TALER_TEST_HOME = test_taler_exchange_httpd_home/ - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR - -[exchange] -# The DB plugin to use -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 = "https://exchange.taler.net/" - -[auditor] -BASE_URL = "http://auditor.example.com/" - -[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 - -[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 - -[account-1] - -# What is the account URL? -URL = "payto://x-taler-bank/localhost/2" -WIRE_GATEWAY_URL = "http://localhost:8082/2/" -WIRE_GATEWAY_AUTH_METHOD = basic -USERNAME = Exchange -PASSWORD = x -method = "x-taler-bank" -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json -ENABLE_DEBIT = YES -ENABLE_CREDIT = YES -TALER_BANK_AUTH_METHOD = NONE - -[bank] -HTTP_PORT = 8082 - -[fees-x-taler-bank] - -# Fees for the forseeable future... -# If you see this after 2018, update to match the next 10 years... -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 - -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 diff --git a/src/lib/test-taler-exchange-wirewatch-postgres.conf b/src/lib/test-taler-exchange-wirewatch-postgres.conf deleted file mode 100644 index ae5cd7ef6..000000000 --- a/src/lib/test-taler-exchange-wirewatch-postgres.conf +++ /dev/null @@ -1,105 +0,0 @@ -[PATHS] -# Persistant data storage for the testcase -TALER_TEST_HOME = test_taler_exchange_httpd_home/ - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR - -[exchange] -# The DB plugin to use -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 - -[account-1] - -# What is the account URL? -URL = "payto://x-taler-bank/localhost/2" -WIRE_GATEWAY_URL = "http://localhost:8082/2/" - -WIRE_GATEWAY_AUTH_METHOD = basic -USERNAME = Exchange -PASSWORD = x - -METHOD = x-taler-bank -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json -PLUGIN = "taler_bank" -ENABLE_DEBIT = YES -ENABLE_CREDIT = YES -TALER_BANK_AUTH_METHOD = NONE - -[bank] -HTTP_PORT = 8082 - -[fees-x-taler-bank] - -# Fees for the forseeable future... -# If you see this after 2018, update to match the next 10 years... -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 - -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 - -# Need at least one coin, otherwise Exchange -# refuses to start. -[coin_eur_ct_1] -value = EUR:0.01 -duration_overlap = 5 minutes -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 - diff --git a/src/lib/test_auditor_api.c b/src/lib/test_auditor_api.c deleted file mode 100644 index d4971f6cf..000000000 --- a/src/lib/test_auditor_api.c +++ /dev/null @@ -1,710 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/test_auditor_api.c - * @brief testcase to test auditor's HTTP API interface - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_auditor_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_auditor_api.conf" - -#define CONFIG_FILE_EXPIRE_RESERVE_NOW \ - "test_auditor_api_expire_reserve_now.conf" - -/** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Execute the taler-exchange-wirewatch command with - * our configuration file. - * - * @param label label to use for the command. - */ -#define CMD_EXEC_WIREWATCH(label) \ - TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE) - -/** - * Execute the taler-exchange-aggregator command with - * our configuration file. - * - * @param label label to use for the command. - */ -#define CMD_EXEC_AGGREGATOR(label) \ - TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE) - -/** - * Run wire transfer of funds from some user's account to the - * exchange. - * - * @param label label to use for the command. - * @param amount amount to transfer, i.e. "EUR:1" - */ -#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ - TALER_TESTING_cmd_admin_add_incoming (label, amount, \ - &bc.exchange_auth, \ - bc.user42_payto) - -/** - * Run the taler-auditor. - * - * @param label label to use for the command. - */ -#define CMD_RUN_AUDITOR(label) \ - TALER_TESTING_cmd_exec_auditor (label, CONFIG_FILE) - -/** - * Run the taler-wire-auditor. - * - * @param label label to use for the command. - */ -#define CMD_RUN_WIRE_AUDITOR(label) \ - TALER_TESTING_cmd_exec_wire_auditor (label, CONFIG_FILE) - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - /** - * Test withdraw. - */ - struct TALER_TESTING_Command withdraw[] = { - /** - * Move money to the exchange's bank account. - */ - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer - ("check-create-reserve-1", - "EUR:5.01", bc.user42_payto, bc.exchange_payto, - "create-reserve-1"), - /** - * Make a reserve exist, according to the previous transfer. - */ - CMD_EXEC_WIREWATCH ("wirewatch-1"), - /** - * Withdraw EUR:5. - */ - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1", - "create-reserve-1", - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command spend[] = { - /** - * Spend the coin. - */ - TALER_TESTING_cmd_deposit ("deposit-simple", - "withdraw-coin-1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command refresh[] = { - /* Fill reserve with EUR:5, 1ct is for fees. NOTE: the old - * test-suite gave a account number of _424_ to the user at - * this step; to type less, here the _42_ number is reused. - * Does this change the tests semantics? */// - CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer - ("check-refresh-create-reserve-1", - "EUR:5.01", bc.user42_payto, bc.exchange_payto, - "refresh-create-reserve-1"), - /** - * Make previous command effective. - */ - CMD_EXEC_WIREWATCH ("wirewatch-2"), - /** - * Withdraw EUR:5. - */ - TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1", - "refresh-create-reserve-1", - "EUR:5", - MHD_HTTP_OK), - /** - * Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in - * full) Merchant receives EUR:0.99 due to 1 ct deposit fee. - */ - TALER_TESTING_cmd_deposit ("refresh-deposit-partial", - "refresh-withdraw-coin-1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:1\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - /** - * Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x - * EUR:0.13) */ - TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1", - "refresh-withdraw-coin-1", - MHD_HTTP_OK, - NULL), - /** - * Complete (successful) melt operation, and withdraw the coins - */ - TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1", - "refresh-melt-1", - MHD_HTTP_OK), - /** - * Try to spend a refreshed EUR:0.1 coin - */ - TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b", - "refresh-reveal-1", - 3, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:0.1", - MHD_HTTP_OK), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command track[] = { - /** - * Run transfers. Note that _actual_ aggregation will NOT - * happen here, as each deposit operation is run with a - * fresh merchant public key! NOTE: this comment comes - * "verbatim" from the old test-suite, and IMO does not explain - * a lot!*/// - CMD_EXEC_AGGREGATOR ("run-aggregator"), - - /** - * Check all the transfers took place. - */ - TALER_TESTING_cmd_check_bank_transfer - ("check_bank_transfer-499c", ec.exchange_url, - "EUR:4.98", bc.exchange_payto, bc.user42_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check_bank_transfer-99c1", ec.exchange_url, - "EUR:0.98", bc.exchange_payto, bc.user42_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check_bank_transfer-99c", ec.exchange_url, - "EUR:0.08", bc.exchange_payto, bc.user43_payto), - - /* The following transactions got originated within - * the "massive deposit confirms" batch. */ - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-1", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-2", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-3", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-4", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-5", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-6", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-7", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-8", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-9", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_transfer - ("check-massive-transfer-10", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, bc.user43_payto), - TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"), - TALER_TESTING_cmd_end () - }; - - /** - * This block checks whether a wire deadline - * very far in the future does NOT get aggregated now. - */ - struct TALER_TESTING_Command unaggregation[] = { - TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"), - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated", - "EUR:5.01"), - CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"), - /* "consume" reserve creation transfer. */ - TALER_TESTING_cmd_check_bank_admin_transfer ( - "check_bank_transfer-unaggregated", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "create-reserve-unaggregated"), - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", - "create-reserve-unaggregated", - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit ("deposit-unaggregated", - "withdraw-coin-unaggregated", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_YEARS, - 3000), - "EUR:5", - MHD_HTTP_OK), - CMD_EXEC_AGGREGATOR ("aggregation-attempt"), - TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-b"), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command refund[] = { - /** - * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config. - */ - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1", - "EUR:5.01"), - /** - * Run wire-watch to trigger the reserve creation. - */ - CMD_EXEC_WIREWATCH ("wirewatch-3"), - /** - * Withdraw a 5 EUR coin, at fee of 1 ct - */ - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1", - "create-reserve-r1", - "EUR:5", - MHD_HTTP_OK), - /** - * Spend 5 EUR of the 5 EUR coin (in full). Merchant would - * receive EUR:4.99 due to 1 ct deposit fee. - */ - TALER_TESTING_cmd_deposit ("deposit-refund-1", - "withdraw-coin-r1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_MINUTES, - "EUR:5", - MHD_HTTP_OK), - - TALER_TESTING_cmd_refund ("refund-ok", - MHD_HTTP_OK, - "EUR:5", - "EUR:0.01", - "deposit-refund-1"), - /** - * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone - * due to refund) (merchant would receive EUR:4.98 due to - * 1 ct deposit fee) */ - TALER_TESTING_cmd_deposit ("deposit-refund-2", - "withdraw-coin-r1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"more\",\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:4.99", - MHD_HTTP_OK), - /** - * Run transfers. This will do the transfer as refund deadline was - * 0. - */ - CMD_EXEC_AGGREGATOR ("run-aggregator-3"), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command recoup[] = { - /** - * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per - * config. - */ - CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1", - "EUR:5.01"), - /** - * Run wire-watch to trigger the reserve creation. - */ - CMD_EXEC_WIREWATCH ("wirewatch-4"), - /** - * Withdraw a 5 EUR coin, at fee of 1 ct - */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1", - "recoup-create-reserve-1", - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_revoke ("revoke-1", - MHD_HTTP_OK, - "recoup-withdraw-coin-1", - CONFIG_FILE), - TALER_TESTING_cmd_recoup ("recoup-1", - MHD_HTTP_OK, - "recoup-withdraw-coin-1", - "EUR:5", - NULL), - /** - * Re-withdraw from this reserve - */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2", - "recoup-create-reserve-1", - "EUR:1", - MHD_HTTP_OK), - /** - * These commands should close the reserve because the aggregator - * is given a config file that ovverrides the reserve expiration - * time (making it now-ish) - */CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve", - "EUR:5.01"), - TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation", - CONFIG_FILE_EXPIRE_RESERVE_NOW), - TALER_TESTING_cmd_exec_aggregator ("close-reserves", - CONFIG_FILE_EXPIRE_RESERVE_NOW), - /** - * Fill reserve with EUR:2.02, as withdraw fee is 1 ct per - * config, then withdraw two coin, partially spend one, and - * then have the rest paid back. Check deposit of other coin - * fails. (Do not use EUR:5 here as the EUR:5 coin was - * revoked and we did not bother to create a new one...) - */CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2", - "EUR:2.02"), - /** - * Make previous command effective. - */ - CMD_EXEC_WIREWATCH ("wirewatch-5"), - /** - * Withdraw a 1 EUR coin, at fee of 1 ct - */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a", - "recoup-create-reserve-2", - "EUR:1", - MHD_HTTP_OK), - /** - * Withdraw a 1 EUR coin, at fee of 1 ct - */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b", - "recoup-create-reserve-2", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit ("recoup-deposit-partial", - "recoup-withdraw-coin-2a", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:0.5", - MHD_HTTP_OK), - TALER_TESTING_cmd_revoke ("revoke-2", - MHD_HTTP_OK, - "recoup-withdraw-coin-2a", - CONFIG_FILE), - TALER_TESTING_cmd_recoup ("recoup-2", - MHD_HTTP_OK, - "recoup-withdraw-coin-2a", - "EUR:0.5", - NULL), - TALER_TESTING_cmd_end () - }; - - - struct TALER_TESTING_Command massive_deposit_confirms[] = { - - /** - * Move money to the exchange's bank account. - */ - CMD_TRANSFER_TO_EXCHANGE ("massive-reserve", - "EUR:10.10"), - TALER_TESTING_cmd_check_bank_admin_transfer - ("check-massive-transfer", - "EUR:10.10", - bc.user42_payto, bc.exchange_payto, - "massive-reserve"), - CMD_EXEC_WIREWATCH ("massive-wirewatch"), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-2", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-3", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-4", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-5", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-6", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-7", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-8", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-9", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-10", - "massive-reserve", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-1", - "massive-withdraw-1", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-2", - "massive-withdraw-2", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-3", - "massive-withdraw-3", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-4", - "massive-withdraw-4", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-5", - "massive-withdraw-5", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-6", - "massive-withdraw-6", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-7", - "massive-withdraw-7", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-8", - "massive-withdraw-8", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-9", - "massive-withdraw-9", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("massive-deposit-10", - "massive-withdraw-10", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit_confirmation ("deposit-confirmation", - is->auditor, - "massive-deposit-10", - 0, - "EUR:0.99", - MHD_HTTP_OK), - CMD_RUN_AUDITOR ("massive-auditor"), - - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command commands[] = { - CMD_RUN_AUDITOR ("virgin-auditor"), - CMD_RUN_WIRE_AUDITOR ("virgin-wire-auditor"), - TALER_TESTING_cmd_exchanges_with_url ("check-exchange", - MHD_HTTP_OK, - "http://localhost:8081/"), - TALER_TESTING_cmd_batch ("massive-deposit-confirms", - massive_deposit_confirms), - TALER_TESTING_cmd_batch ("withdraw", - withdraw), - TALER_TESTING_cmd_batch ("spend", - spend), - TALER_TESTING_cmd_batch ("refresh", - refresh), - TALER_TESTING_cmd_batch ("track", - track), - TALER_TESTING_cmd_batch ("unaggregation", - unaggregation), - TALER_TESTING_cmd_batch ("refund", - refund), - TALER_TESTING_cmd_batch ("recoup", - recoup), - CMD_RUN_AUDITOR ("normal-auditor"), - CMD_RUN_WIRE_AUDITOR ("normal-wire-auditor"), - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); -} - - -int -main (int argc, - char *const *argv) -{ - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-auditor-api", - "INFO", - NULL); - /* Check fakebank port is available and get configuration data. */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (CONFIG_FILE, - "account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (CONFIG_FILE); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - &ec)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_auditor_setup (&run, - NULL, - CONFIG_FILE)) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; -} - - -/* end of test_auditor_api.c */ diff --git a/src/lib/test_auditor_api.conf b/src/lib/test_auditor_api.conf deleted file mode 100644 index 7bb57c3a9..000000000 --- a/src/lib/test_auditor_api.conf +++ /dev/null @@ -1,210 +0,0 @@ - -# This file is in the public domain. -# -[PATHS] -# Persistant data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - -TINY_AMOUNT = EUR:0.01 - -[exchange] - -# how long is one signkey valid? -signkey_duration = 4 weeks - -# how long are the signatures with the signkey valid? -legal_duration = 2 years - -# how long do we provide to clients denomination and signing keys -# ahead of time? -lookahead_provide = 4 weeks 1 day - -# 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/" - -# Keep it short so the test runs fast. -LOOKAHEAD_SIGN = 12 h - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -# Sections starting with "account-" configure the bank accounts -# of the exchange. The "URL" specifies the account in -# payto://-format, while the WIRE_JSON specifies the -# (possibly offline) signed version to be returned in /wire. -# WIRE_JSON is optional, as not all accounts must be -# advertised in /wire. -[account-1] -# What is the URL of our account? -URL = "payto://x-taler-bank/localhost/42" -WIRE_GATEWAY_URL = "http://localhost:8082/42/" -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json - -# Which wire plugin should we used to access the account? -METHOD = x-taler-bank - -[bank] -HTTP_PORT = 8082 - -# ENABLE_CREDIT = YES - -[account-2] -# What is the bank account (with the "Taler Bank" demo system)? -WIRE_GATEWAY_URL = "http://localhost:8082/2/" -URL = "payto://x-taler-bank/localhost/2" - -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json - -# Which wire plugin should we used to access the account? -METHOD = x-taler-bank - -# Authentication information for basic authentication -WIRE_GATEWAY_AUTH_METHOD = "basic" -USERNAME = user -PASSWORD = pass - -ENABLE_DEBIT = YES - -ENABLE_CREDIT = YES - - -# Sections starting with "fee-" configure the wire fee for the -# respective wire method. -[fees-iban] -# Fees for the forseeable future... -# If you see this after 2017, update to match the next 10 years... -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 - -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 - -[fees-x-taler-bank] -# Fees for the forseeable future... -# If you see this after 2017, update to match the next 10 years... -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 - -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 - -# 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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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/lib/test_auditor_api_expire_reserve_now.conf b/src/lib/test_auditor_api_expire_reserve_now.conf deleted file mode 100644 index c2bf8f479..000000000 --- a/src/lib/test_auditor_api_expire_reserve_now.conf +++ /dev/null @@ -1,4 +0,0 @@ -@INLINE@ test_auditor_api.conf - -[exchangedb] -IDLE_RESERVE_EXPIRATION_TIME = 0 s diff --git a/src/lib/test_auditor_api_version.c b/src/lib/test_auditor_api_version.c deleted file mode 100644 index be85455d7..000000000 --- a/src/lib/test_auditor_api_version.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/test_auditor_api_version.c - * @brief testcase to test auditor's HTTP API interface to fetch /version - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_auditor_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_auditor_api.conf" - -static struct TALER_AUDITOR_Handle *ah; - -static struct GNUNET_CURL_Context *ctx; - -static struct GNUNET_CURL_RescheduleContext *rc; - -static int global_ret; - -static struct GNUNET_SCHEDULER_Task *tt; - -static void -do_shutdown (void *cls) -{ - (void) cls; - - if (NULL != tt) - { - GNUNET_SCHEDULER_cancel (tt); - tt = NULL; - } - TALER_AUDITOR_disconnect (ah); - GNUNET_CURL_fini (ctx); - GNUNET_CURL_gnunet_rc_destroy (rc); -} - - -static void -do_timeout (void *cls) -{ - (void) cls; - tt = NULL; - global_ret = 3; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Function called with information about the auditor. - * - * @param cls closure - * @param vi basic information about the auditor - * @param compat protocol compatibility information - */ -static void -version_cb (void *cls, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat) -{ - if ( (NULL != vi) && - (TALER_AUDITOR_VC_MATCH == compat) ) - global_ret = 0; - else - global_ret = 2; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls) -{ - const char *auditor_url = "http://localhost:8083/"; - - (void) cls; - ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, - &rc); - rc = GNUNET_CURL_gnunet_rc_create (ctx); - ah = TALER_AUDITOR_connect (ctx, - auditor_url, - &version_cb, - NULL); - GNUNET_SCHEDULER_add_shutdown (&do_shutdown, - NULL); - tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &do_timeout, - NULL); -} - - -int -main (int argc, - char *const *argv) -{ - struct GNUNET_OS_Process *proc; - - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-auditor-api-version", - "INFO", - NULL); - proc = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-httpd", - "taler-auditor-httpd", - "-c", CONFIG_FILE, - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-httpd`," - " is your PATH correct?\n"); - return 77; - } - GNUNET_SCHEDULER_run (&run, - NULL); - GNUNET_OS_process_kill (proc, SIGTERM); - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_destroy (proc); - return global_ret; -} - - -/* end of test_auditor_api_version.c */ diff --git a/src/lib/test_bank_api.c b/src/lib/test_bank_api.c deleted file mode 100644 index 4377c4fba..000000000 --- a/src/lib/test_bank_api.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2016-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, - or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ -/** - * @file bank/test_bank_api.c - * @brief testcase to test bank's HTTP API - * interface against the fakebank - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_bank_service.h" -#include "taler_exchange_service.h" -#include -#include -#include -#include "taler_testing_lib.h" - -#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank.conf" -#define CONFIG_FILE_PYBANK "test_bank_api_pybank.conf" - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Handle to the Py-bank daemon. - */ -static struct GNUNET_OS_Process *bankd; - -/** - * Flag indicating whether the test is running against the - * Fakebank. Set up at runtime. - */ -static int with_fakebank; - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct TALER_WireTransferIdentifierRawP wtid; - - memset (&wtid, 42, sizeof (wtid)); - - { - struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_bank_credits ("history-0", - &bc.exchange_auth, - NULL, - 1), - TALER_TESTING_cmd_admin_add_incoming ("credit-1", - "KUDOS:5.01", - &bc.exchange_auth, - bc.user42_payto), - TALER_TESTING_cmd_bank_credits ("history-1c", - &bc.exchange_auth, - NULL, - 5), - TALER_TESTING_cmd_bank_debits ("history-1d", - &bc.exchange_auth, - NULL, - 5), - TALER_TESTING_cmd_admin_add_incoming ("credit-2", - "KUDOS:3.21", - &bc.exchange_auth, - bc.user42_payto), - TALER_TESTING_cmd_transfer ("debit-1", - "KUDOS:3.22", - &bc.exchange_auth, - bc.exchange_payto, - bc.user42_payto, - &wtid, - "http://exchange.example.com/"), - TALER_TESTING_cmd_bank_debits ("history-2b", - &bc.exchange_auth, - NULL, - 5), - TALER_TESTING_cmd_end () - }; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Bank serves at `%s'\n", - bc.exchange_auth.wire_gateway_url); - if (GNUNET_YES == with_fakebank) - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); - else - TALER_TESTING_run (is, - commands); - } -} - - -int -main (int argc, - char *const *argv) -{ - int rv; - const char *cfgfilename; - - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-bank-api", - "DEBUG", - NULL); - with_fakebank = TALER_TESTING_has_in_name (argv[0], - "_with_fakebank"); - if (GNUNET_YES == with_fakebank) - { - TALER_LOG_DEBUG ("Running against the Fakebank.\n"); - cfgfilename = CONFIG_FILE_FAKEBANK; - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (CONFIG_FILE_FAKEBANK, - "account-2", - &bc)) - { - GNUNET_break (0); - return 77; - } - } - else - { - TALER_LOG_DEBUG ("Running against the Pybank.\n"); - cfgfilename = CONFIG_FILE_PYBANK; - if (GNUNET_OK != - TALER_TESTING_prepare_bank (CONFIG_FILE_PYBANK, - "account-2", - &bc)) - { - GNUNET_break (0); - return 77; - } - - if (NULL == (bankd = TALER_TESTING_run_bank (CONFIG_FILE_PYBANK, - bc.exchange_auth. - wire_gateway_url))) - { - GNUNET_break (0); - return 77; - } - } - - rv = (GNUNET_OK == TALER_TESTING_setup (&run, - NULL, - cfgfilename, - NULL, - GNUNET_NO)) ? 0 : 1; - if (GNUNET_NO == with_fakebank) - { - - GNUNET_OS_process_kill (bankd, - SIGKILL); - GNUNET_OS_process_wait (bankd); - GNUNET_OS_process_destroy (bankd); - } - return rv; -} - - -/* end of test_bank_api.c */ diff --git a/src/lib/test_bank_api_fakebank.conf b/src/lib/test_bank_api_fakebank.conf deleted file mode 100644 index 5c9e5e3a5..000000000 --- a/src/lib/test_bank_api_fakebank.conf +++ /dev/null @@ -1,17 +0,0 @@ -# This file is in the public domain. - -[taler] -currency = KUDOS - -[account-2] -URL = payto://x-taler-bank/localhost/2 -METHOD = x-taler-bank -WIRE_GATEWAY_URL = "http://localhost:8081/2/" -WIRE_GATEWAY_AUTH_METHOD = basic -USERNAME = Exchange -PASSWORD = x - -[bank] -SERVE = http -HTTP_PORT = 8081 -DATABASE = postgres:///talercheck diff --git a/src/lib/test_bank_api_fakebank_twisted.conf b/src/lib/test_bank_api_fakebank_twisted.conf deleted file mode 100644 index 4455ac743..000000000 --- a/src/lib/test_bank_api_fakebank_twisted.conf +++ /dev/null @@ -1,34 +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 - -[taler] -currency = KUDOS - -[bank] -serve = http -http_port = 8081 -database = postgres:///talercheck - -[account-1] -URL = payto://x-taler-bank/localhost:8081/1 - -[account-2] -URL = payto://x-taler-bank/localhost:8081/2 diff --git a/src/lib/test_bank_api_pybank.conf b/src/lib/test_bank_api_pybank.conf deleted file mode 100644 index 1d5f4a2d1..000000000 --- a/src/lib/test_bank_api_pybank.conf +++ /dev/null @@ -1,17 +0,0 @@ -# This file is in the public domain. - -[taler] -currency = KUDOS - -[account-2] -URL = payto://x-taler-bank/localhost/Exchange -METHOD = x-taler-bank -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 diff --git a/src/lib/test_bank_api_pybank_twisted.conf b/src/lib/test_bank_api_pybank_twisted.conf deleted file mode 100644 index a2085c38e..000000000 --- a/src/lib/test_bank_api_pybank_twisted.conf +++ /dev/null @@ -1,46 +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 - - -[taler] -currency = KUDOS - - -[bank] -serve = http -http_port = 8081 -database = postgres:///talercheck - - -[account-1] -URL = payto://x-taler-bank/localhost/1 - - -[account-2] -URL = payto://x-taler-bank/localhost/Exchange -METHOD = x-taler-bank -WIRE_GATEWAY_URL = "http://localhost:8888/taler-wire-gateway/Exchange/" -WIRE_GATEWAY_AUTH_METHOD = basic -USERNAME = Exchange -PASSWORD = x - - -[bank] -HTTP_PORT = 8081 diff --git a/src/lib/test_bank_api_twisted.c b/src/lib/test_bank_api_twisted.c deleted file mode 100644 index 2ec95ec03..000000000 --- a/src/lib/test_bank_api_twisted.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/test_bank_api_with_fakebank_twisted.c - * @author Marcello Stanisci - * @author Sree Harsha Totakura - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" -#include -#include - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank_twisted.conf" - -/** - * Separate config file for running with the pybank. - */ -#define CONFIG_FILE_PYBANK "test_bank_api_pybank_twisted.conf" - -/** - * True when the test runs against Fakebank. - */ -static int with_fakebank; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * (real) Twister URL. Used at startup time to check if it runs. - */ -static char *twister_url; - -/** - * Twister process. - */ -static struct GNUNET_OS_Process *twisterd; - -/** - * Python bank process handle. - */ -static struct GNUNET_OS_Process *bankd; - - -/** - * Main function that will tell - * the interpreter what commands to run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - - struct TALER_TESTING_Command commands[] = { - /** - * Can't use the "wait service" CMD here because the - * fakebank runs inside the same process of the test. - */ - TALER_TESTING_cmd_wait_service ("wait-service", - twister_url), - TALER_TESTING_cmd_bank_credits ("history-0", - &bc.exchange_auth, - NULL, - 5), - TALER_TESTING_cmd_end () - }; - - if (GNUNET_YES == with_fakebank) - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); - else - TALER_TESTING_run (is, - commands); -} - - -/** - * Kill, wait, and destroy convenience function. - * - * @param process process to purge. - */ -static void -purge_process (struct GNUNET_OS_Process *process) -{ - GNUNET_OS_process_kill (process, SIGINT); - GNUNET_OS_process_wait (process); - GNUNET_OS_process_destroy (process); -} - - -int -main (int argc, - char *const *argv) -{ - unsigned int ret; - const char *cfgfilename; - - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-bank-api-with-(fake)bank-twisted", - "DEBUG", - NULL); - - with_fakebank = TALER_TESTING_has_in_name (argv[0], - "_with_fakebank"); - - if (with_fakebank) - cfgfilename = CONFIG_FILE_FAKEBANK; - else - cfgfilename = CONFIG_FILE_PYBANK; - - if (NULL == (twister_url = TALER_TESTING_prepare_twister - (cfgfilename))) - { - GNUNET_break (0); - return 77; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "twister_url is %s\n", - twister_url); - if (NULL == (twisterd = TALER_TESTING_run_twister (cfgfilename))) - { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } - - if (GNUNET_YES == with_fakebank) - { - TALER_LOG_DEBUG ("Running against the Fakebank.\n"); - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (cfgfilename, - "account-2", - &bc)) - { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } - } - else - { - TALER_LOG_DEBUG ("Running against the Pybank.\n"); - if (GNUNET_OK != - TALER_TESTING_prepare_bank (cfgfilename, - "account-2", - &bc)) - { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } - - if (NULL == (bankd = TALER_TESTING_run_bank (cfgfilename, - bc.exchange_auth. - wire_gateway_url))) - { - GNUNET_break (0); - GNUNET_free (twister_url); - return 77; - } - } - - ret = TALER_TESTING_setup (&run, - NULL, - cfgfilename, - NULL, - GNUNET_NO); - purge_process (twisterd); - - if (GNUNET_NO == with_fakebank) - { - GNUNET_OS_process_kill (bankd, - SIGKILL); - GNUNET_OS_process_wait (bankd); - GNUNET_OS_process_destroy (bankd); - } - - GNUNET_free (twister_url); - if (GNUNET_OK == ret) - return 0; - - return 1; -} - - -/* end of test_bank_api_twisted.c */ diff --git a/src/lib/test_exchange_api.c b/src/lib/test_exchange_api.c deleted file mode 100644 index 67aeebccd..000000000 --- a/src/lib/test_exchange_api.c +++ /dev/null @@ -1,832 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014--2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/test_exchange_api.c - * @brief testcase to test exchange's HTTP API interface - * @author Sree Harsha Totakura - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_exchange_api.conf" - -#define CONFIG_FILE_EXPIRE_RESERVE_NOW \ - "test_exchange_api_expire_reserve_now.conf" - - -/** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - - -/** - * Execute the taler-exchange-wirewatch command with - * our configuration file. - * - * @param label label to use for the command. - */ -#define CMD_EXEC_WIREWATCH(label) \ - TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE) - -/** - * Execute the taler-exchange-aggregator command with - * our configuration file. - * - * @param label label to use for the command. - */ -#define CMD_EXEC_AGGREGATOR(label) \ - TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE) - -/** - * Run wire transfer of funds from some user's account to the - * exchange. - * - * @param label label to use for the command. - * @param amount amount to transfer, i.e. "EUR:1" - */ -#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ - TALER_TESTING_cmd_admin_add_incoming (label, amount, \ - &bc.exchange_auth, \ - bc.user42_payto) - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - * @param is interpreter we use to run commands - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - /** - * Checks made against /wire response. - */ - struct TALER_TESTING_Command wire[] = { - /** - * Check if 'x-taler-bank' wire method is offered - * by the exchange. - */ - TALER_TESTING_cmd_wire ("wire-taler-bank-1", - "x-taler-bank", - NULL, - MHD_HTTP_OK), - TALER_TESTING_cmd_end () - }; - - /** - * Test withdrawal plus spending. - */ - struct TALER_TESTING_Command withdraw[] = { - /** - * Move money to the exchange's bank account. - */ - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "create-reserve-1"), - /** - * Make a reserve exist, according to the previous - * transfer. - */ - CMD_EXEC_WIREWATCH ("wirewatch-1"), - /** - * Withdraw EUR:5. - */ - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1", - "create-reserve-1", - "EUR:5", - MHD_HTTP_OK), - /** - * Check the reserve is depleted. - */ - TALER_TESTING_cmd_status ("status-1", - "create-reserve-1", - "EUR:0", - MHD_HTTP_OK), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command spend[] = { - /** - * Spend the coin. - */ - TALER_TESTING_cmd_deposit ("deposit-simple", - "withdraw-coin-1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:5", - MHD_HTTP_OK), - /** - * Try to overdraw. - */ - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2", - "create-reserve-1", - "EUR:5", - MHD_HTTP_CONFLICT), - /** - * Try to double spend using different wire details. - */ - TALER_TESTING_cmd_deposit ("deposit-double-1", - "withdraw-coin-1", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:5", - MHD_HTTP_CONFLICT), - /* Try to double spend using a different transaction id. - * The test needs the contract terms to differ. This - * is currently the case because of the "timestamp" field, - * which is set automatically by #TALER_TESTING_cmd_deposit(). - * This could theoretically fail if at some point a deposit - * command executs in less than 1 ms. */// - TALER_TESTING_cmd_deposit ("deposit-double-1", - "withdraw-coin-1", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:5", - MHD_HTTP_CONFLICT), - /** - * Try to double spend with different proposal. - */ - TALER_TESTING_cmd_deposit ("deposit-double-2", - "withdraw-coin-1", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:5", - MHD_HTTP_CONFLICT), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command refresh[] = { - /* Fill reserve with EUR:5, 1ct is for fees. */ - CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer ("ck-refresh-create-reserve-1", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "refresh-create-reserve-1"), - /** - * Make previous command effective. - */ - CMD_EXEC_WIREWATCH ("wirewatch-2"), - /** - * Withdraw EUR:5. - */ - TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1", - "refresh-create-reserve-1", - "EUR:5", - MHD_HTTP_OK), - /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin - * (in full) (merchant would receive EUR:0.99 due to 1 ct - * deposit fee) */// - TALER_TESTING_cmd_deposit ("refresh-deposit-partial", - "refresh-withdraw-coin-1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - /** - * Melt the rest of the coin's value - * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ - TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1", - "refresh-withdraw-coin-1", - MHD_HTTP_OK, - NULL), - /** - * Complete (successful) melt operation, and - * withdraw the coins - */ - TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1", - "refresh-melt-1", - MHD_HTTP_OK), - /** - * Do it again to check idempotency - */ - TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1-idempotency", - "refresh-melt-1", - MHD_HTTP_OK), - /** - * Test that /refresh/link works - */ - TALER_TESTING_cmd_refresh_link ("refresh-link-1", - "refresh-reveal-1", - MHD_HTTP_OK), - /** - * Try to spend a refreshed EUR:1 coin - */ - TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1a", - "refresh-reveal-1-idempotency", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - /** - * Try to spend a refreshed EUR:0.1 coin - */ - TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b", - "refresh-reveal-1", - 3, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:0.1", - MHD_HTTP_OK), - /* Test running a failing melt operation (same operation - * again must fail) */ - TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing", - "refresh-withdraw-coin-1", - MHD_HTTP_CONFLICT, - NULL), - /* Test running a failing melt operation (on a coin that - was itself revealed and subsequently deposited) */ - TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing-2", - "refresh-reveal-1", - MHD_HTTP_CONFLICT, - NULL), - - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command track[] = { - /* Try resolving a deposit's WTID, as we never triggered - * execution of transactions, the answer should be that - * the exchange knows about the deposit, but has no WTID yet. - */// - TALER_TESTING_cmd_track_transaction ("deposit-wtid-found", - "deposit-simple", - 0, - MHD_HTTP_ACCEPTED, - NULL), - /* Try resolving a deposit's WTID for a failed deposit. - * As the deposit failed, the answer should be that the - * exchange does NOT know about the deposit. - */// - TALER_TESTING_cmd_track_transaction ("deposit-wtid-failing", - "deposit-double-2", - 0, - MHD_HTTP_NOT_FOUND, - NULL), - /* Try resolving an undefined (all zeros) WTID; this - * should fail as obviously the exchange didn't use that - * WTID value for any transaction. - */// - TALER_TESTING_cmd_track_transfer_empty ("wire-deposit-failing", - NULL, - 0, - MHD_HTTP_NOT_FOUND), - /* Run transfers. Note that _actual_ aggregation will NOT - * happen here, as each deposit operation is run with a - * fresh merchant public key, so the aggregator will treat - * them as "different" merchants and do the wire transfers - * individually. */// - CMD_EXEC_AGGREGATOR ("run-aggregator"), - /** - * Check all the transfers took place. - */ - TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c", - ec.exchange_url, - "EUR:4.98", - bc.exchange_payto, - bc.user42_payto), - TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, - bc.user42_payto), - TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c2", - ec.exchange_url, - "EUR:0.98", - bc.exchange_payto, - bc.user42_payto), - TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c", - ec.exchange_url, - "EUR:0.08", - bc.exchange_payto, - bc.user43_payto), - TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"), - TALER_TESTING_cmd_track_transaction ("deposit-wtid-ok", - "deposit-simple", - 0, - MHD_HTTP_OK, - "check_bank_transfer-499c"), - TALER_TESTING_cmd_track_transfer ("wire-deposit-success-bank", - "check_bank_transfer-99c1", - 0, - MHD_HTTP_OK, - "EUR:0.98", - "EUR:0.01"), - TALER_TESTING_cmd_track_transfer ("wire-deposits-success-wtid", - "deposit-wtid-ok", - 0, - MHD_HTTP_OK, - "EUR:4.98", - "EUR:0.01"), - TALER_TESTING_cmd_end () - }; - - - /** - * This block checks whether a wire deadline - * very far in the future does NOT get aggregated now. - */ - struct TALER_TESTING_Command unaggregation[] = { - TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"), - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated", - "EUR:5.01"), - /* "consume" reserve creation transfer. */ - TALER_TESTING_cmd_check_bank_admin_transfer ( - "check-create-reserve-unaggregated", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "create-reserve-unaggregated"), - CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"), - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", - "create-reserve-unaggregated", - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit ("deposit-unaggregated", - "withdraw-coin-unaggregated", - 0, - bc.user43_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_relative_multiply ( - GNUNET_TIME_UNIT_YEARS, - 3000), - "EUR:5", - MHD_HTTP_OK), - CMD_EXEC_AGGREGATOR ("aggregation-attempt"), - - TALER_TESTING_cmd_check_bank_empty - ("far-future-aggregation-b"), - - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command refund[] = { - /** - * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per - * config. - */ - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-r1", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "create-reserve-r1"), - /** - * Run wire-watch to trigger the reserve creation. - */ - CMD_EXEC_WIREWATCH ("wirewatch-3"), - /* Withdraw a 5 EUR coin, at fee of 1 ct */ - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1", - "create-reserve-r1", - "EUR:5", - MHD_HTTP_OK), - /** - * Spend 5 EUR of the 5 EUR coin (in full) (merchant would - * receive EUR:4.99 due to 1 ct deposit fee) - */ - TALER_TESTING_cmd_deposit ("deposit-refund-1", - "withdraw-coin-r1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_MINUTES, - "EUR:5", - MHD_HTTP_OK), - /** - * Run transfers. Should do nothing as refund deadline blocks it - */ - CMD_EXEC_AGGREGATOR ("run-aggregator-refund"), - /* Check that aggregator didn't do anything, as expected. - * Note, this operation takes two commands: one to "flush" - * the preliminary transfer (used to withdraw) from the - * fakebank and the second to actually check there are not - * other transfers around. */// - TALER_TESTING_cmd_check_bank_empty ("check_bank_transfer-pre-refund"), - TALER_TESTING_cmd_refund ("refund-ok", - MHD_HTTP_OK, - "EUR:5", - "EUR:0.01", - "deposit-refund-1"), - TALER_TESTING_cmd_refund ("refund-ok-double", - MHD_HTTP_OK, - "EUR:5", - "EUR:0.01", - "deposit-refund-1"), - /* Previous /refund(s) had id == 0. */ - TALER_TESTING_cmd_refund_with_id ("refund-conflicting", - MHD_HTTP_CONFLICT, - "EUR:5", - "EUR:0.01", - "deposit-refund-1", - 1), - /** - * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone - * due to refund) (merchant would receive EUR:4.98 due to - * 1 ct deposit fee) */ - TALER_TESTING_cmd_deposit ("deposit-refund-2", - "withdraw-coin-r1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"more ice cream\",\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:4.99", - MHD_HTTP_OK), - /** - * Run transfers. This will do the transfer as refund deadline - * was 0 - */ - CMD_EXEC_AGGREGATOR ("run-aggregator-3"), - /** - * Check that deposit did run. - */ - TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-pre-refund", - ec.exchange_url, - "EUR:4.97", - bc.exchange_payto, - bc.user42_payto), - /** - * Run failing refund, as past deadline & aggregation. - */ - TALER_TESTING_cmd_refund ("refund-fail", - MHD_HTTP_GONE, - "EUR:4.99", - "EUR:0.01", - "deposit-refund-2"), - TALER_TESTING_cmd_check_bank_empty ("check-empty-after-refund"), - /** - * Test refunded coins are never executed, even past - * refund deadline - */ - CMD_TRANSFER_TO_EXCHANGE ("create-reserve-rb", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-rb", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "create-reserve-rb"), - CMD_EXEC_WIREWATCH ("wirewatch-rb"), - TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb", - "create-reserve-rb", - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit ("deposit-refund-1b", - "withdraw-coin-rb", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:5", - MHD_HTTP_OK), - /** - * Trigger refund (before aggregator had a chance to execute - * deposit, even though refund deadline was zero). - */ - TALER_TESTING_cmd_refund ("refund-ok-fast", - MHD_HTTP_OK, - "EUR:5", - "EUR:0.01", - "deposit-refund-1b"), - /** - * Run transfers. This will do the transfer as refund deadline - * was 0, except of course because the refund succeeded, the - * transfer should no longer be done. - */CMD_EXEC_AGGREGATOR ("run-aggregator-3b"), - /* check that aggregator didn't do anything, as expected */ - TALER_TESTING_cmd_check_bank_empty ("check-refund-fast-not-run"), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command recoup[] = { - /** - * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per - * config. - */ - CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer ("recoup-create-reserve-1", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "recoup-create-reserve-1"), - /** - * Run wire-watch to trigger the reserve creation. - */ - CMD_EXEC_WIREWATCH ("wirewatch-4"), - /* Withdraw a 5 EUR coin, at fee of 1 ct */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1", - "recoup-create-reserve-1", - "EUR:5", - MHD_HTTP_OK), - /* Make coin invalid */ - TALER_TESTING_cmd_revoke ("revoke-0-EUR:5", - MHD_HTTP_OK, - "recoup-withdraw-coin-1", - CONFIG_FILE), - /* Refund coin to bank account */ - TALER_TESTING_cmd_recoup ("recoup-1", - MHD_HTTP_OK, - "recoup-withdraw-coin-1", - "EUR:5", - NULL), - /* Check the money is back with the reserve */ - TALER_TESTING_cmd_status ("recoup-reserve-status-1", - "recoup-create-reserve-1", - "EUR:5.0", - MHD_HTTP_OK), - /* Re-withdraw from this reserve */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2", - "recoup-create-reserve-1", - "EUR:1", - MHD_HTTP_OK), - /** - * This withdrawal will test the logic to create a "recoup" - * element to insert into the reserve's history. - */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2-over", - "recoup-create-reserve-1", - "EUR:10", - MHD_HTTP_CONFLICT), - TALER_TESTING_cmd_status ("recoup-reserve-status-2", - "recoup-create-reserve-1", - "EUR:3.99", - MHD_HTTP_OK), - - /* These commands should close the reserve because - * the aggregator is given a config file that ovverrides - * the reserve expiration time (making it now-ish) */ - CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve", - "EUR:5.01"), - TALER_TESTING_cmd_check_bank_admin_transfer ("check-short-lived-reserve", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "short-lived-reserve"), - TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation", - CONFIG_FILE_EXPIRE_RESERVE_NOW), - - TALER_TESTING_cmd_exec_aggregator ("close-reserves", - CONFIG_FILE_EXPIRE_RESERVE_NOW), - - TALER_TESTING_cmd_status ("short-lived-status", - "short-lived-reserve", - "EUR:0", - MHD_HTTP_OK), - TALER_TESTING_cmd_withdraw_amount ("expired-withdraw", - "short-lived-reserve", - "EUR:1", - MHD_HTTP_CONFLICT), - TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse", - ec.exchange_url, - "EUR:5", - bc.exchange_payto, - bc.user42_payto), - /* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per - * config, then withdraw two coin, partially spend one, and - * then have the rest paid back. Check deposit of other coin - * fails. Do not use EUR:5 here as the EUR:5 coin was - * revoked and we did not bother to create a new one... */// - CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2", - "EUR:2.02"), - TALER_TESTING_cmd_check_bank_admin_transfer ("ck-recoup-create-reserve-2", - "EUR:2.02", - bc.user42_payto, - bc.exchange_payto, - "recoup-create-reserve-2"), - /* Make previous command effective. */ - CMD_EXEC_WIREWATCH ("wirewatch-5"), - /* Withdraw a 1 EUR coin, at fee of 1 ct */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a", - "recoup-create-reserve-2", - "EUR:1", - MHD_HTTP_OK), - /* Withdraw a 1 EUR coin, at fee of 1 ct */ - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b", - "recoup-create-reserve-2", - "EUR:1", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit ("recoup-deposit-partial", - "recoup-withdraw-coin-2a", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:0.5", - MHD_HTTP_OK), - TALER_TESTING_cmd_revoke ("revoke-1-EUR:1", - MHD_HTTP_OK, - "recoup-withdraw-coin-2a", - CONFIG_FILE), - TALER_TESTING_cmd_recoup ("recoup-2", - MHD_HTTP_OK, - "recoup-withdraw-coin-2a", - "EUR:0.5", - NULL), - TALER_TESTING_cmd_recoup ("recoup-2b", - MHD_HTTP_CONFLICT, - "recoup-withdraw-coin-2a", - "EUR:0.5", - NULL), - TALER_TESTING_cmd_deposit ("recoup-deposit-revoked", - "recoup-withdraw-coin-2b", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_NOT_FOUND), - /* Test deposit fails after recoup, with proof in recoup */ - - /* Note that, the exchange will never return the coin's transaction - * history with recoup data, as we get a 404 on the DK! */ - TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup", - "recoup-withdraw-coin-2a", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:0.5", - MHD_HTTP_NOT_FOUND), - /* Test that revoked coins cannot be withdrawn */ - CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-3", - "EUR:1.01"), - TALER_TESTING_cmd_check_bank_admin_transfer ( - "check-recoup-create-reserve-3", - "EUR:1.01", - bc.user42_payto, - bc.exchange_payto, - "recoup-create-reserve-3"), - CMD_EXEC_WIREWATCH ("wirewatch-6"), - TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked", - "recoup-create-reserve-3", - "EUR:1", - MHD_HTTP_NOT_FOUND), - /* check that we are empty before the rejection test */ - TALER_TESTING_cmd_check_bank_empty ("check-empty-again"), - - TALER_TESTING_cmd_end () - }; - -#define RESERVE_OPEN_CLOSE_CHUNK 4 -#define RESERVE_OPEN_CLOSE_ITERATIONS 3 - - struct TALER_TESTING_Command reserve_open_close[(RESERVE_OPEN_CLOSE_ITERATIONS - * RESERVE_OPEN_CLOSE_CHUNK) - + 1]; - for (unsigned int i = 0; - i < RESERVE_OPEN_CLOSE_ITERATIONS; - i++) - { - reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 0] - = CMD_TRANSFER_TO_EXCHANGE ("reserve-open-close-key", - "EUR:20"); - reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1] - = TALER_TESTING_cmd_exec_wirewatch ("reserve-open-close-wirewatch", - CONFIG_FILE_EXPIRE_RESERVE_NOW); - reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2] - = TALER_TESTING_cmd_exec_aggregator ("reserve-open-close-aggregation", - CONFIG_FILE_EXPIRE_RESERVE_NOW); - reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 3] - = TALER_TESTING_cmd_status ("reserve-open-close-status", - "reserve-open-close-key", - "EUR:0", - MHD_HTTP_OK); - } - reserve_open_close[RESERVE_OPEN_CLOSE_ITERATIONS * RESERVE_OPEN_CLOSE_CHUNK] - = TALER_TESTING_cmd_end (); - - { - struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_batch ("wire", - wire), - TALER_TESTING_cmd_batch ("withdraw", - withdraw), - TALER_TESTING_cmd_batch ("spend", - spend), - TALER_TESTING_cmd_batch ("refresh", - refresh), - TALER_TESTING_cmd_batch ("track", - track), - TALER_TESTING_cmd_batch ("unaggregation", - unaggregation), - TALER_TESTING_cmd_batch ("refund", - refund), - TALER_TESTING_cmd_batch ("recoup", - recoup), - TALER_TESTING_cmd_batch ("reserve-open-close", - reserve_open_close), - /* End the suite. */ - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); - } -} - - -int -main (int argc, - char *const *argv) -{ - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-exchange-api", - "INFO", - NULL); - /* Check fakebank port is available and get config */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (CONFIG_FILE, - "account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (CONFIG_FILE); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - &ec)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - CONFIG_FILE)) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; -} - - -/* end of test_exchange_api.c */ diff --git a/src/lib/test_exchange_api.conf b/src/lib/test_exchange_api.conf deleted file mode 100644 index 291e0a0e0..000000000 --- a/src/lib/test_exchange_api.conf +++ /dev/null @@ -1,210 +0,0 @@ -# This file is in the public domain. -# - -[PATHS] -# Persistant data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ - - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - - -[exchange] -# how long is one signkey valid? -signkey_duration = 4 weeks - -# how long are the signatures with the signkey valid? -legal_duration = 2 years - -# how long do we provide to clients denomination and signing keys -# ahead of time? -lookahead_provide = 4 weeks 1 day - -# 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/" - -# Keep it short so the test runs fast. -LOOKAHEAD_SIGN = 12 h - - -[exchangedb-postgres] -CONFIG = "postgres:///talercheck" - - -[auditordb-postgres] -CONFIG = "postgres:///talercheck" - -# Sections starting with "account-" configure the bank accounts -# of the exchange. The "URL" specifies the account in -# payto://-format, while the WIRE_JSON specifies the -# (possibly offline) signed version to be returned in /wire. -# WIRE_JSON is optional, as not all accounts must be -# advertised in /wire. -[account-1] -# What is the URL of our account? -URL = "payto://x-taler-bank/localhost/42" -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json -# Which wire plugin should we used to access the account? -METHOD = x-taler-bank - -WIRE_GATEWAY_URL = "http://localhost:9081/42/" - -# ENABLE_CREDIT = YES - - -[account-2] -# What is the bank account (with the "Taler Bank" demo system)? -URL = "payto://x-taler-bank/localhost/2" - -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json - -WIRE_GATEWAY_AUTH_METHOD = basic -USERNAME = Exchange -PASSWORD = x - -METHOD = x-taler-bank - -WIRE_GATEWAY_URL = "http://localhost:9081/2/" - -ENABLE_DEBIT = YES - -ENABLE_CREDIT = YES - -[bank] -HTTP_PORT = 9081 - -# Sections starting with "fee-" configure the wire fee for the -# respective wire method. -[fees-iban] -# Fees for the forseeable future... -# If you see this after 2017, update to match the next 10 years... -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 - -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 - -[fees-x-taler-bank] -# Fees for the forseeable future... -# If you see this after 2017, update to match the next 10 years... -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 - -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 - -# 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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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/lib/test_exchange_api_expire_reserve_now.conf b/src/lib/test_exchange_api_expire_reserve_now.conf deleted file mode 100644 index 05bca956b..000000000 --- a/src/lib/test_exchange_api_expire_reserve_now.conf +++ /dev/null @@ -1,4 +0,0 @@ -@INLINE@ test_exchange_api.conf - -[exchangedb] -IDLE_RESERVE_EXPIRATION_TIME = 0 s diff --git a/src/lib/test_exchange_api_home/.config/taler/account-1.json b/src/lib/test_exchange_api_home/.config/taler/account-1.json deleted file mode 100644 index 48093f2aa..000000000 --- a/src/lib/test_exchange_api_home/.config/taler/account-1.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "url": "payto://sepa/CH9300762011623852957", - "salt": "N83T9J9202WCC8TQFDMJDWEGZNBEKA33C1ZM241VNYH88RZNTHPW509Y1M2YF7Y098R8VRESWQ05H03BK1SPAZCWE54KARDCKT5N8AG", - "master_sig": "D4V5GJ998YK7D6N0N56AD0J6MZNFEW6MRZT2CFPVQ5ME3NMQ59AA2007CXYESSFGRN70CNCFM06858QSSENCWTZM8VHEJ93YQ20ZJ1R" -} \ No newline at end of file diff --git a/src/lib/test_exchange_api_home/.config/taler/account-2.json b/src/lib/test_exchange_api_home/.config/taler/account-2.json deleted file mode 100644 index f39677eff..000000000 --- a/src/lib/test_exchange_api_home/.config/taler/account-2.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "url": "payto://x-taler-bank/localhost/2", - "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R" -} \ No newline at end of file diff --git a/src/lib/test_exchange_api_home/.config/taler/sepa.json b/src/lib/test_exchange_api_home/.config/taler/sepa.json deleted file mode 100644 index b435ce86b..000000000 --- a/src/lib/test_exchange_api_home/.config/taler/sepa.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "Max Musterman", - "bic": "COBADEFF370", - "type": "sepa", - "sig": "4EVRC2MCJPXQC8MC00831DNWEXMZAP4JQDDE1A7R6KR3MANG24RC1VQ55AX5A2E35S58VW1VSTENFTPHG5MWG9BSN8B8WXSV21KKW20", - "address": "Musterstadt", - "salt": "3KTM1ZRMWGEQPQ254S4R5R4Q8XM0ZYWTCTE01TZ76MVBSQ6RX7A5DR08WXVH1DCHR1R7ACRB7X0EVC2XDW1CBZM9WFSD9TRMZ90BR98", - "iban": "DE89370400440532013000" -} \ No newline at end of file diff --git a/src/lib/test_exchange_api_home/.config/taler/test.json b/src/lib/test_exchange_api_home/.config/taler/test.json deleted file mode 100644 index eca394241..000000000 --- a/src/lib/test_exchange_api_home/.config/taler/test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "salt": "AZPRFVJ58NM6M7J5CZQPJAH3EW5DYM52AEZ9Y1C1ER3W94QV8D8TQKF6CK8MYQRA9QMSKDQTGZ306ZS9GQ0M6R01CJ20KPP49WFDZK8", - "name": "The exchange", - "account_number": 3, - "bank_url": "http://localhost:8082/", - "type": "test", - "sig": "RPQXP9S4P8PQP7HEZQNRSZCT0ATNEP8GW0P5TPM34V5RX86FCD670V44R9NETSYDDKB8SZV7TKY9PAJYTY51D3VDWY9XXQ5BPFRXR28" -} diff --git a/src/lib/test_exchange_api_home/.config/taler/x-taler-bank.json b/src/lib/test_exchange_api_home/.config/taler/x-taler-bank.json deleted file mode 100644 index a6dc167e4..000000000 --- a/src/lib/test_exchange_api_home/.config/taler/x-taler-bank.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "url": "payto://x-taler-bank/http://localhost:8082/2", - "master_sig": "KQ0BWSCNVR7HGGSAMCYK8ZM30RBS1MHMXT3QBN01PZWC9TV72FEE5RJ7T84C8134EPV6WEBXXY2MTFNE8ZXST6JEJQKR8HX6FQPVY10", - "master_pub": "98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG" -} diff --git a/src/lib/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv b/src/lib/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/lib/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/lib/test_exchange_api_interpreter_on-off.c b/src/lib/test_exchange_api_interpreter_on-off.c deleted file mode 100644 index 95eb74da9..000000000 --- a/src/lib/test_exchange_api_interpreter_on-off.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/test_exchange_api_keys_cherry_picking_new.c - * @brief testcase to test exchange's /keys cherry picking ability - * @author Marcello Stanisci - * @author Christian Grothoff - */ - -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - -/** - * XXX: - * - * This test helps in finding a way to use/modify the "normal" - * cert_cb to handle reconnections from serialized states as well. - * - * 1st step: simply turn the interpreter off and on again. - * 2nd step: turn the interpreter off and give a serial state - * to reconnect. - */ - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf" - -/** - * Exchange base URL; mainly purpose is to make the compiler happy. - */ -static char *exchange_url; - -/** - * Auditor base URL; mainly purpose is to make the compiler happy. - */ -static char *auditor_url; - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - - struct TALER_TESTING_Command commands[] = { - - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run (is, - commands); -} - - -int -main (int argc, - char *const *argv) -{ - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-exchange-api-cherry-picking-new", - "DEBUG", NULL); - TALER_TESTING_cleanup_files (CONFIG_FILE); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - &auditor_url, - &exchange_url)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - CONFIG_FILE)) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; -} - - -/* end of test_exchange_api_keys_cherry_picking_new.c */ diff --git a/src/lib/test_exchange_api_keys_cherry_picking.c b/src/lib/test_exchange_api_keys_cherry_picking.c deleted file mode 100644 index 12ee26e60..000000000 --- a/src/lib/test_exchange_api_keys_cherry_picking.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/test_exchange_api_keys_cherry_picking.c - * @brief testcase to test exchange's /keys cherry picking ability - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf" - -/** - * Used to increase the number of denomination keys. - */ -#define CONFIG_FILE_EXTENDED \ - "test_exchange_api_keys_cherry_picking_extended.conf" - -/** - * Used to increase the number of denomination keys. - */ -#define CONFIG_FILE_EXTENDED_2 \ - "test_exchange_api_keys_cherry_picking_extended_2.conf" - - -#define NDKS_RIGHT_BEFORE_SERIALIZATION 46 - -/** - * Add seconds. - * - * @param base absolute time to add seconds to. - * @param relative number of seconds to add. - * @return a new absolute time, modified according to @e relative. - */ -#define ADDSECS(base, secs) \ - GNUNET_TIME_absolute_add \ - (base, \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \ - secs)) - -/** - * Subtract seconds. - * - * @param base absolute time to subtract seconds to. - * @param secs relative number of _seconds_ to subtract. - * @return a new absolute time, modified according to @e relative. - */ -#define SUBSECS(base, secs) \ - GNUNET_TIME_absolute_subtract \ - (base, \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \ - secs)) -#define JAN1971 "1971-01-01" -#define JAN2030 "2030-01-01" - -/** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - - -/** - * Wrapper around the time parser. - * - * @param str human-readable time string. - * @return the parsed time from @a str. - */ -static struct GNUNET_TIME_Absolute -TTH_parse_time (const char *str) -{ - struct GNUNET_TIME_Absolute ret; - - GNUNET_assert - (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_absolute (str, - &ret)); - return ret; -} - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - * @param is[in,out] interpreter state - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct TALER_TESTING_Command keys_serialization[] = { - TALER_TESTING_cmd_serialize_keys - ("serialize-keys"), - TALER_TESTING_cmd_connect_with_state - ("reconnect-with-state", - "serialize-keys"), - /** - * Make sure we have the same keys situation as - * it was before the serialization. - */ - TALER_TESTING_cmd_check_keys_with_now - ("check-keys-after-deserialization", - 4, - NDKS_RIGHT_BEFORE_SERIALIZATION, - /** - * Pretend 5 seconds passed. - */ - ADDSECS (TTH_parse_time (JAN2030), - 5)), - /** - * Use one of the deserialized keys. - */ - TALER_TESTING_cmd_wire - ("verify-/wire-with-serialized-keys", - "x-taler-bank", - NULL, - MHD_HTTP_OK), - TALER_TESTING_cmd_end (), - }; - - struct TALER_TESTING_Command ordinary_cherry_pick[] = { - /** - * 1 DK with 80s withdraw duration, lookahead_sign is 60s - * => expect 1 DK. - */ - TALER_TESTING_cmd_check_keys ("check-keys-1", - 1, /* generation */ - 1), - /** - * The far-future now will cause "keyup" to start a fresh - * key set. The new KS will have only one key, because the - * current lookahead_sign == 60 seconds and the key's withdraw - * duration is 80 seconds. - */TALER_TESTING_cmd_exec_keyup_with_now - ("keyup-1", - CONFIG_FILE, - TTH_parse_time (JAN2030)), - /** - * Should return 1 new key, + the original one. NOTE: the - * original DK will never be 'cancelled' as for the current - * libtalerexchange logic, so it must always be counted. - */TALER_TESTING_cmd_check_keys_with_now - ("check-keys-2", - 2, /* generation */ - 2, - TTH_parse_time (JAN2030)), - TALER_TESTING_cmd_exec_keyup_with_now - ("keyup-3", - CONFIG_FILE_EXTENDED_2, - /* Taking care of not using a 'now' that equals the - * last DK timestamp, otherwise it would get silently - * overridden. */ - ADDSECS (TTH_parse_time (JAN2030), - 10)), - - /** - * Expected number of DK: - * - * 3500 (the lookahead_sign time frame, in seconds) - * - 69 (how many seconds are covered by the latest DK) - * ---- - * 3431 - * / 79 (how many seconds each DK will cover) - * ---- - * 44 (rounded up) - * + 2 (old DKs already stored locally: 1 from the - * very initial setup, and 1 from the 'keyup-1' CMD) - * ---- - * 46 - */TALER_TESTING_cmd_check_keys_with_now - ("check-keys-3", - 3, - NDKS_RIGHT_BEFORE_SERIALIZATION, - TTH_parse_time (JAN2030)), - - TALER_TESTING_cmd_end () - }; - struct TALER_TESTING_Command commands[] = { - - TALER_TESTING_cmd_batch ("ordinary-cherry-pick", - ordinary_cherry_pick), - TALER_TESTING_cmd_batch ("keys-serialization", - keys_serialization), - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run (is, - commands); -} - - -int -main (int argc, - char *const *argv) -{ - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-exchange-api-cherry-picking", - "DEBUG", - NULL); - TALER_TESTING_cleanup_files (CONFIG_FILE); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - &ec)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - CONFIG_FILE)) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; -} - - -/* end of test_exchange_api_keys_cherry_picking.c */ diff --git a/src/lib/test_exchange_api_keys_cherry_picking.conf b/src/lib/test_exchange_api_keys_cherry_picking.conf deleted file mode 100644 index c5a69df3b..000000000 --- a/src/lib/test_exchange_api_keys_cherry_picking.conf +++ /dev/null @@ -1,184 +0,0 @@ -# This file is in the public domain. -# -[PATHS] -# Persistent data storage for the testcase -TALER_TEST_HOME = test_exchange_api_keys_cherry_picking_home/ - -# Persistant 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 - -[auditor] -BASE_URL = "http://localhost:8083/" - -# HTTP port the auditor listens to -PORT = 8083 - -[exchange] - -KEYDIR = ${TALER_TEST_HOME}/.local/share/taler/exchange/live-keys/ - -# how long is one signkey valid? -signkey_duration = 5 seconds - -# how long are the signatures with the signkey valid? -legal_duration = 2 years - -# This vaule causes keys to be *RETURNED* in a /keys response. -# It's a relative time that materializes always in now+itsvalue. -# We keep it very high, so as to not introduce divergencies between -# keys that have been created and keys that are returned along /keys. -lookahead_provide = 10000 seconds - -# This value causes keys to be *CREATED*. The rule is that -# at any given time there are always N keys whose all the withdraw -# durations sum up to a time window as big as lookahead_sign. -lookahead_sign = 60 s - -# 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" - - -[account-1] -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/iban.json - -# What is the URL of our bank account? Must match WIRE_RESPONSE above! -URL = payto://x-taler-bank/localhost/42 - -METHOD = "x-taler-bank" - -WIRE_GATEWAY_URL = "http://localhost:9082/42/" - - -[account-2] -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/x-taler-bank.json - -# What is the URL of our bank account? Must match WIRE_RESPONSE above! -URL = payto://x-taler-bank/localhost/2 - -WIRE_GATEWAY_URL = "http://localhost:9082/2/" - -METHOD = "x-taler-bank" - -# Authentication information for basic authentication -TALER_BANK_AUTH_METHOD = "basic" -USERNAME = user -PASSWORD = pass - -ENABLE_DEBIT = YES - -ENABLE_CREDIT = YES - -[bank] -HTTP_PORT=8082 - -[fees-x-taler-bank] -# Fees for the forseeable future... -# If you see this after 2017, update to match the next 10 years... -WIRE-FEE-2017 = EUR:0.01 -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 -WIRE-FEE-2028 = EUR:0.01 -WIRE-FEE-2029 = EUR:0.01 -WIRE-FEE-2030 = EUR:0.01 -WIRE-FEE-2031 = EUR:0.01 -WIRE-FEE-2032 = EUR:0.01 -WIRE-FEE-2033 = EUR:0.01 -WIRE-FEE-2034 = EUR:0.01 -WIRE-FEE-2035 = EUR:0.01 - -CLOSING-FEE-2017 = EUR:0.01 -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 -CLOSING-FEE-2028 = EUR:0.01 -CLOSING-FEE-2029 = EUR:0.01 -CLOSING-FEE-2030 = EUR:0.01 -CLOSING-FEE-2031 = EUR:0.01 -CLOSING-FEE-2032 = EUR:0.01 -CLOSING-FEE-2033 = EUR:0.01 -CLOSING-FEE-2034 = EUR:0.01 -CLOSING-FEE-2035 = EUR:0.01 - - -[fees-iban] -# Fees for the forseeable future... -# If you see this after 2017, update to match the next 10 years... -WIRE-FEE-2017 = EUR:0.01 -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 - -CLOSING-FEE-2017 = EUR:0.01 -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 - -[coin_eur_1] -value = EUR:1 -duration_overlap = 1 s -duration_withdraw = 80 s -duration_spend = 80 s -duration_legal = 60 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/lib/test_exchange_api_keys_cherry_picking_extended.conf b/src/lib/test_exchange_api_keys_cherry_picking_extended.conf deleted file mode 100644 index c49f1edd4..000000000 --- a/src/lib/test_exchange_api_keys_cherry_picking_extended.conf +++ /dev/null @@ -1,5 +0,0 @@ -@INLINE@ test_exchange_api_keys_cherry_picking.conf - -[exchange] -# Lengthen over original value (60 s) -LOOKAHEAD_SIGN = 90 s diff --git a/src/lib/test_exchange_api_keys_cherry_picking_extended_2.conf b/src/lib/test_exchange_api_keys_cherry_picking_extended_2.conf deleted file mode 100644 index 8097a6cda..000000000 --- a/src/lib/test_exchange_api_keys_cherry_picking_extended_2.conf +++ /dev/null @@ -1,5 +0,0 @@ -@INLINE@ test_exchange_api_keys_cherry_picking_extended.conf - -[exchange] -# Lengthen over firstly extended value (100 s) -LOOKAHEAD_SIGN = 3500 s diff --git a/src/lib/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json b/src/lib/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json deleted file mode 100644 index f39677eff..000000000 --- a/src/lib/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "url": "payto://x-taler-bank/localhost/2", - "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R" -} \ No newline at end of file diff --git a/src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv b/src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/lib/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/lib/test_exchange_api_overlapping_keys_bug.c b/src/lib/test_exchange_api_overlapping_keys_bug.c deleted file mode 100644 index a6fc018ab..000000000 --- a/src/lib/test_exchange_api_overlapping_keys_bug.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018, 2019 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/test_exchange_api_overlapping_keys_bug.c - * @brief testcase to test exchange's /keys cherry picking ability and - * other /keys related operations - * @author Marcello Stanisci - * @author Christian Grothoff - */ - -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf" - -/** - * Used to increase the number of denomination keys. - */ -#define CONFIG_FILE_EXTENDED \ - "test_exchange_api_keys_cherry_picking_extended.conf" - -/** - * Used to increase the number of denomination keys. - */ -#define CONFIG_FILE_EXTENDED_2 \ - "test_exchange_api_keys_cherry_picking_extended_2.conf" - -/** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_check_keys ("first-download", - 1, - 1), - /* Causes GET /keys?last_denom_issue=0 */ - TALER_TESTING_cmd_check_keys_with_last_denom ("second-download", - 3, - 1, - GNUNET_TIME_UNIT_ZERO_ABS), - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run (is, - commands); -} - - -int -main (int argc, - char *const *argv) -{ - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-exchange-api-overlapping-keys-bug", - "DEBUG", NULL); - TALER_TESTING_cleanup_files (CONFIG_FILE); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - &ec)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - CONFIG_FILE)) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; -} - - -/* end of test_exchange_api_overlapping_keys_bug.c */ diff --git a/src/lib/test_exchange_api_revocation.c b/src/lib/test_exchange_api_revocation.c deleted file mode 100644 index 1c06340e8..000000000 --- a/src/lib/test_exchange_api_revocation.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014--2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/test_exchange_api_revocation.c - * @brief testcase to test key revocation handling via the exchange's HTTP API interface - * @author Sree Harsha Totakura - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_exchange_api.conf" - -/** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct TALER_TESTING_Command revocation[] = { - /** - * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per - * config. - */ - TALER_TESTING_cmd_admin_add_incoming ("create-reserve-1", - "EUR:5.01", - &bc.exchange_auth, - bc.user42_payto), - TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", - "EUR:5.01", - bc.user42_payto, - bc.exchange_payto, - "create-reserve-1"), - /** - * Run wire-watch to trigger the reserve creation. - */ - TALER_TESTING_cmd_exec_wirewatch ("wirewatch-4", - CONFIG_FILE), - /* Withdraw a 5 EUR coin, at fee of 1 ct */ - TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1", - "create-reserve-1", - "EUR:5", - MHD_HTTP_OK), - /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full) - * (merchant would receive EUR:0.99 due to 1 ct deposit fee) */// - TALER_TESTING_cmd_deposit ("deposit-partial", - "withdraw-revocation-coin-1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - /** - * Melt SOME of the rest of the coin's value - * (EUR:3.17 = 3x EUR:1.03 + 7x EUR:0.13) */ - TALER_TESTING_cmd_refresh_melt ("refresh-melt-1", - "withdraw-revocation-coin-1", - MHD_HTTP_OK, - NULL), - /** - * Complete (successful) melt operation, and withdraw the coins - */ - TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1", - "refresh-melt-1", - MHD_HTTP_OK), - /* Make refreshed coin invalid */ - TALER_TESTING_cmd_revoke ("revoke-2-EUR:5", - MHD_HTTP_OK, - "refresh-melt-1", - CONFIG_FILE), - /* Refund coin to original coin */ - TALER_TESTING_cmd_recoup ("recoup-1a", - MHD_HTTP_OK, - "refresh-reveal-1#0", - "EUR:1", - "refresh-melt-1"), - TALER_TESTING_cmd_recoup ("recoup-1b", - MHD_HTTP_OK, - "refresh-reveal-1#1", - "EUR:1", - "refresh-melt-1"), - TALER_TESTING_cmd_recoup ("recoup-1c", - MHD_HTTP_OK, - "refresh-reveal-1#2", - "EUR:1", - "refresh-melt-1"), - /* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */ - /* Melt original coin AGAIN, but only create one 0.1 EUR coin; - This costs EUR:0.03 in refresh and EUR:01 in withdraw fees, - leaving EUR:3.69. */ - TALER_TESTING_cmd_refresh_melt ("refresh-melt-2", - "withdraw-revocation-coin-1", - MHD_HTTP_OK, - "EUR:0.1", - NULL), - /** - * Complete (successful) melt operation, and withdraw the coins - */ - TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-2", - "refresh-melt-2", - MHD_HTTP_OK), - /* Revokes refreshed EUR:0.1 coin */ - TALER_TESTING_cmd_revoke ("revoke-3-EUR:0.1", - MHD_HTTP_OK, - "refresh-reveal-2", - CONFIG_FILE), - /* Revoke also original coin denomination */ - TALER_TESTING_cmd_revoke ("revoke-4-EUR:5", - MHD_HTTP_OK, - "withdraw-revocation-coin-1", - CONFIG_FILE), - /* Refund coin EUR:0.1 to original coin, creating zombie! */ - TALER_TESTING_cmd_recoup ("recoup-2", - MHD_HTTP_OK, - "refresh-reveal-2", - "EUR:0.1", - "refresh-melt-2"), - /* Due to recoup, original coin is now at EUR:3.79 */ - /* Refund original (now zombie) coin to reserve */ - TALER_TESTING_cmd_recoup ("recoup-3", - MHD_HTTP_OK, - "withdraw-revocation-coin-1", - "EUR:3.79", - NULL), - /* Check the money is back with the reserve */ - TALER_TESTING_cmd_status ("recoup-reserve-status-1", - "create-reserve-1", - "EUR:3.79", - MHD_HTTP_OK), - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run_with_fakebank (is, - revocation, - bc.exchange_auth.wire_gateway_url); -} - - -int -main (int argc, - char *const *argv) -{ - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-exchange-api-revocation", - "INFO", - NULL); - /* Check fakebank port is available and get config */ - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (CONFIG_FILE, - "account-2", - &bc)) - return 77; - TALER_TESTING_cleanup_files (CONFIG_FILE); - /* @helpers. Run keyup, create tables, ... Note: it - * fetches the port number from config in order to see - * if it's available. */ - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - &ec)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - case GNUNET_OK: - if (GNUNET_OK != - /* Set up event loop and reschedule context, plus - * start/stop the exchange. It calls TALER_TESTING_setup - * which creates the 'is' object. - */ - TALER_TESTING_setup_with_exchange (&run, - NULL, - CONFIG_FILE)) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; -} - - -/* end of test_exchange_api_revocation.c */ diff --git a/src/lib/test_exchange_api_twisted.c b/src/lib/test_exchange_api_twisted.c deleted file mode 100644 index 5ae71128b..000000000 --- a/src/lib/test_exchange_api_twisted.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/test_exchange_api_twisted.c - * @brief testcase to test exchange's HTTP API interface - * @author Marcello Stanisci - * @author Sree Harsha Totakura - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_signatures.h" -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" -#include -#include - -/** - * Configuration file we use. One (big) configuration is used - * for the various components for this test. - */ -#define CONFIG_FILE "test_exchange_api_twisted.conf" - -/** - * (real) Twister URL. Used at startup time to check if it runs. - */ -static char *twister_url; - -/** - * Exchange configuration data. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Twister process. - */ -static struct GNUNET_OS_Process *twisterd; - - -/** - * Execute the taler-exchange-wirewatch command with - * our configuration file. - * - * @param label label to use for the command. - */ -static struct TALER_TESTING_Command -CMD_EXEC_WIREWATCH (char *label) -{ - return TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE); -} - - -/** - * Run wire transfer of funds from some user's account to the - * exchange. - * - * @param label label to use for the command. - * @param amount amount to transfer, i.e. "EUR:1" - * @param url exchange_url - */ -static struct TALER_TESTING_Command -CMD_TRANSFER_TO_EXCHANGE (char *label, char *amount) -{ - return TALER_TESTING_cmd_admin_add_incoming (label, - amount, - &bc.exchange_auth, - bc.user42_payto); -} - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - /** - * This batch aims to trigger the 409 Conflict - * response from a refresh-reveal operation. - */ - struct TALER_TESTING_Command refresh_409_conflict[] = { - CMD_TRANSFER_TO_EXCHANGE - ("refresh-create-reserve", - "EUR:5.01"), - /** - * Make previous command effective. - */ - CMD_EXEC_WIREWATCH - ("wirewatch"), - /** - * Withdraw EUR:5. - */ - TALER_TESTING_cmd_withdraw_amount - ("refresh-withdraw-coin", - "refresh-create-reserve", - "EUR:5", - MHD_HTTP_OK), - - TALER_TESTING_cmd_deposit - ("refresh-deposit-partial", - "refresh-withdraw-coin", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\",\ - \"value\":\"EUR:1\"}]}", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - MHD_HTTP_OK), - - /** - * Melt the rest of the coin's value - * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ - TALER_TESTING_cmd_refresh_melt - ("refresh-melt", - "refresh-withdraw-coin", - MHD_HTTP_OK, - NULL), - /* Trigger 409 Conflict. */ - TALER_TESTING_cmd_flip_upload - ("flip-upload", - CONFIG_FILE, - "transfer_privs.0"), - TALER_TESTING_cmd_refresh_reveal - ("refresh-(flipped-)reveal", - "refresh-melt", - MHD_HTTP_CONFLICT), - - TALER_TESTING_cmd_end () - - }; - - - /** - * NOTE: not all CMDs actually need the twister, - * so it may be better to move those into the "main" - * lib test suite. - */struct TALER_TESTING_Command refund[] = { - - CMD_TRANSFER_TO_EXCHANGE - ("create-reserve-r1", - "EUR:5.01"), - CMD_EXEC_WIREWATCH - ("wirewatch-r1"), - TALER_TESTING_cmd_withdraw_amount - ("withdraw-coin-r1", - "create-reserve-r1", - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_deposit - ("deposit-refund-1", - "withdraw-coin-r1", - 0, - bc.user42_payto, - "{\"items\":[{\"name\":\"ice cream\"," - "\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_MINUTES, - "EUR:5", - MHD_HTTP_OK), - TALER_TESTING_cmd_refund - ("refund-currency-missmatch", - MHD_HTTP_PRECONDITION_FAILED, - "USD:5", - "USD:0.01", - "deposit-refund-1"), - TALER_TESTING_cmd_refund - ("refund-fee-above-amount", - MHD_HTTP_BAD_REQUEST, - "EUR:5", - "EUR:10", - "deposit-refund-1"), - TALER_TESTING_cmd_flip_upload - ("flip-upload", - CONFIG_FILE, - "merchant_sig"), - TALER_TESTING_cmd_refund - ("refund-bad-sig", - MHD_HTTP_FORBIDDEN, - "EUR:5", - "EUR:0.01", - "deposit-refund-1"), - - /* This next deposit CMD is only used to provide a - * good merchant signature to the next (failing) refund - * operations. */ - - TALER_TESTING_cmd_deposit - ("deposit-refund-to-fail", - "withdraw-coin-r1", - 0, /* coin index. */ - bc.user42_payto, - /* This parameter will make any comparison about - h_contract_terms fail, when /refund will be handled. - So in other words, this is h_contract missmatch. */ - "{\"items\":[{\"name\":\"ice skate\"," - "\"value\":\"EUR:5\"}]}", - GNUNET_TIME_UNIT_MINUTES, - "EUR:5", - MHD_HTTP_CONFLICT), - TALER_TESTING_cmd_refund - ("refund-deposit-not-found", - MHD_HTTP_NOT_FOUND, - "EUR:5", - "EUR:0.01", - "deposit-refund-to-fail"), - TALER_TESTING_cmd_refund - ("refund-insufficient-funds", - MHD_HTTP_PRECONDITION_FAILED, - "EUR:50", - "EUR:0.01", - "deposit-refund-1"), - TALER_TESTING_cmd_refund - ("refund-fee-too-low", - MHD_HTTP_BAD_REQUEST, - "EUR:5", - "EUR:0.000001", - "deposit-refund-1"), - TALER_TESTING_cmd_end () - }; - - struct TALER_TESTING_Command commands[] = { - TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict", - refresh_409_conflict), - TALER_TESTING_cmd_batch ("refund", - refund), - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run_with_fakebank (is, - commands, - bc.exchange_auth.wire_gateway_url); -} - - -/** - * Kill, wait, and destroy convenience function. - * - * @param process process to purge. - */ -static void -purge_process (struct GNUNET_OS_Process *process) -{ - GNUNET_OS_process_kill (process, SIGINT); - GNUNET_OS_process_wait (process); - GNUNET_OS_process_destroy (process); -} - - -int -main (int argc, - char *const *argv) -{ - unsigned int ret; - /* These environment variables get in the way... */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-exchange-api-twisted", - "DEBUG", NULL); - - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (CONFIG_FILE, - "account-2", - &bc)) - return 77; - - if (NULL == (twister_url = TALER_TESTING_prepare_twister - (CONFIG_FILE))) - return 77; - - TALER_TESTING_cleanup_files (CONFIG_FILE); - - switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, - &ec)) - { - case GNUNET_SYSERR: - GNUNET_break (0); - return 1; - case GNUNET_NO: - return 77; - - case GNUNET_OK: - - if (NULL == (twisterd = TALER_TESTING_run_twister (CONFIG_FILE))) - return 77; - - ret = TALER_TESTING_setup_with_exchange (&run, - NULL, - CONFIG_FILE); - purge_process (twisterd); - GNUNET_free (twister_url); - - if (GNUNET_OK != ret) - return 1; - break; - default: - GNUNET_break (0); - return 1; - } - return 0; -} - - -/* end of test_exchange_api_twisted.c */ diff --git a/src/lib/test_exchange_api_twisted.conf b/src/lib/test_exchange_api_twisted.conf deleted file mode 100644 index 28b254e67..000000000 --- a/src/lib/test_exchange_api_twisted.conf +++ /dev/null @@ -1,196 +0,0 @@ -# This file is in the public domain. -# - -[PATHS] -# Persistant data storage for the testcase -TALER_TEST_HOME = test_exchange_api_home/ - - -[taler] -# Currency supported by the exchange (can only be one) -CURRENCY = EUR - - -[exchange] - -# how long is one signkey valid? -SIGNKEY_DURATION = 4 weeks - -# how long are the signatures with the signkey valid? -LEGAL_DURATION = 2 years - -# how long do we provide to clients denomination and signing keys -# ahead of time? -LOOKAHEAD_PROVIDE = 4 weeks 1 day - -# Keep it short so the test runs fast. -LOOKAHEAD_SIGN = 12 h - -# 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" - -[account-1] -# What is the URL of our account? -URL = "payto://x-taler-bank/localhost/42" -# This is the response we give out for the /wire request. It provides -# wallets with the bank information for transfers to the exchange. -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json -# Which wire plugin should we used to access the account? -METHOD = x-taler-bank -WIRE_GATEWAY_URL = "http://localhost:9081/42/" -WIRE_GATEWAY_AUTH_METHOD = NONE - - -[account-2] -URL = payto://x-taler-bank/localhost/2 -WIRE_GATEWAY_URL = "http://localhost:8082/2/" -WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json -WIRE_GATEWAY_AUTH_METHOD = BASIC -USERNAME = user -PASSWORD = pass -ENABLE_DEBIT = YES -ENABLE_CREDIT = YES -METHOD = x-taler-bank - - -[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 - - -[fees-x-taler-bank] -# Fees for the forseeable future... -# If you see this after 2017, update to match the next 10 years... -WIRE-FEE-2018 = EUR:0.01 -WIRE-FEE-2019 = EUR:0.01 -WIRE-FEE-2020 = EUR:0.01 -WIRE-FEE-2021 = EUR:0.01 -WIRE-FEE-2022 = EUR:0.01 -WIRE-FEE-2023 = EUR:0.01 -WIRE-FEE-2024 = EUR:0.01 -WIRE-FEE-2025 = EUR:0.01 -WIRE-FEE-2026 = EUR:0.01 -WIRE-FEE-2027 = EUR:0.01 - -CLOSING-FEE-2018 = EUR:0.01 -CLOSING-FEE-2019 = EUR:0.01 -CLOSING-FEE-2020 = EUR:0.01 -CLOSING-FEE-2021 = EUR:0.01 -CLOSING-FEE-2022 = EUR:0.01 -CLOSING-FEE-2023 = EUR:0.01 -CLOSING-FEE-2024 = EUR:0.01 -CLOSING-FEE-2025 = EUR:0.01 -CLOSING-FEE-2026 = EUR:0.01 -CLOSING-FEE-2027 = EUR:0.01 - -[coin_eur_ct_1] -value = EUR:0.01 -duration_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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_overlap = 5 minutes -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/lib/test_taler_exchange_aggregator.c b/src/lib/test_taler_exchange_aggregator.c deleted file mode 100644 index 347aeb464..000000000 --- a/src/lib/test_taler_exchange_aggregator.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - This file is part of TALER - (C) 2016-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see -*/ - -/** - * @file lib/test_taler_exchange_aggregator.c - * @brief Tests for taler-exchange-aggregator logic - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_util.h" -#include -#include "taler_json_lib.h" -#include "taler_exchangedb_lib.h" -#include -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - - -/** - * Helper structure to keep exchange configuration values. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Contains plugin and session. - */ -static struct TALER_TESTING_DatabaseConnection dbc; - -/** - * Return value from main(). - */ -static int result; - -/** - * Name of the configuration file to use. - */ -static char *config_filename; - -#define USER42_ACCOUNT "42" - -/** - * @return GNUNET_NO if database could not be prepared, - * otherwise GNUNET_OK - */ -static int -prepare_database (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - dbc.plugin = TALER_EXCHANGEDB_plugin_load (cfg); - if (NULL == dbc.plugin) - { - GNUNET_break (0); - result = 77; - return GNUNET_NO; - } - if (GNUNET_OK != - dbc.plugin->create_tables (dbc.plugin->cls)) - { - GNUNET_break (0); - TALER_EXCHANGEDB_plugin_unload (dbc.plugin); - dbc.plugin = NULL; - result = 77; - return GNUNET_NO; - } - dbc.session = dbc.plugin->get_session (dbc.plugin->cls); - GNUNET_assert (NULL != dbc.session); - - return GNUNET_OK; -} - - -/** - * Collects all the tests. - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct TALER_TESTING_Command all[] = { - - // check no aggregation happens on a empty database - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty-db", - config_filename), - TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), - - /* check aggregation happens on the simplest case: - one deposit into the database. */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-1", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-deposit-1", - config_filename), - - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1", - ec.exchange_url, - "EUR:0.89", - bc.exchange_payto, - bc.user42_payto), - TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-1"), - - /* check aggregation accumulates well. */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-2a", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - "EUR:0.1"), - - TALER_TESTING_cmd_insert_deposit ("do-deposit-2b", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - "EUR:0.1"), - - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-2", - config_filename), - - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-2", - ec.exchange_url, - "EUR:1.79", - bc.exchange_payto, - bc.user42_payto), - TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-2"), - - /* check that different merchants stem different aggregations. */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-3a", - &dbc, - "bob", - "4", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - "EUR:0.1"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-3b", - &dbc, - "bob", - "5", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - "EUR:0.1"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-3c", - &dbc, - "alice", - "4", - GNUNET_TIME_UNIT_ZERO, - "EUR:1", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-3", - config_filename), - - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3a", - ec.exchange_url, - "EUR:0.89", - bc.exchange_payto, - "payto://x-taler-bank/localhost/4"), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3b", - ec.exchange_url, - "EUR:0.89", - bc.exchange_payto, - "payto://x-taler-bank/localhost/4"), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3c", - ec.exchange_url, - "EUR:0.89", - bc.exchange_payto, - "payto://x-taler-bank/localhost/5"), - TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-3"), - - /* checking that aggregator waits for the deadline. */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-4a", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 5), - "EUR:0.2", - "EUR:0.1"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-4b", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 5), - "EUR:0.2", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-early", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-4-fast"), - - TALER_TESTING_cmd_sleep ("wait (5s)", 5), - - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-delayed", - config_filename), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-4", - ec.exchange_url, - "EUR:0.19", - bc.exchange_payto, - bc.user42_payto), - - // test picking all deposits at earliest deadline - TALER_TESTING_cmd_insert_deposit ("do-deposit-5a", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 10), - "EUR:0.2", - "EUR:0.1"), - - TALER_TESTING_cmd_insert_deposit ("do-deposit-5b", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 5), - "EUR:0.2", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-early", - config_filename), - - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-5-early"), - TALER_TESTING_cmd_sleep ("wait (5s)", 5), - - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-delayed", - config_filename), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-5", - ec.exchange_url, - "EUR:0.19", - bc.exchange_payto, - bc.user42_payto), - /* Test NEVER running 'tiny' unless they make up minimum unit */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-6a", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.102", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6a-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-6a-tiny"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-6b", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.102", - "EUR:0.1"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-6c", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.102", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6c-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-6c-tiny"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-6d", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.102", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6d-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-6d-tiny"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-6e", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.112", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6e", - config_filename), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-6", - ec.exchange_url, - "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), - - /* Test profiteering if wire deadline is short */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-7a", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.109", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7a-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-7a-tiny"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-7b", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.119", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-profit", - config_filename), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7", - ec.exchange_url, - "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), - - /* Now check profit was actually taken */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-7c", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.122", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-loss", - config_filename), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7", - ec.exchange_url, - "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), - - /* Test that aggregation would happen fully if wire deadline is long */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-8a", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 5), - "EUR:0.109", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8a-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-8a-tiny"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-8b", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 5), - "EUR:0.109", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8b-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-8b-tiny"), - - /* now trigger aggregate with large transaction and short deadline */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-8c", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.122", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8", - config_filename), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-8", - ec.exchange_url, - "EUR:0.03", - bc.exchange_payto, - bc.user42_payto), - - /* Test aggregation with fees and rounding profits. */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-9a", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 5), - "EUR:0.104", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9a-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-9a-tiny"), - TALER_TESTING_cmd_insert_deposit ("do-deposit-9b", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, - 5), - "EUR:0.105", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9b-tiny", - config_filename), - TALER_TESTING_cmd_check_bank_empty ( - "expect-empty-transactions-after-9b-tiny"), - - /* now trigger aggregate with large transaction and short deadline */ - TALER_TESTING_cmd_insert_deposit ("do-deposit-9c", - &dbc, - "bob", - USER42_ACCOUNT, - GNUNET_TIME_UNIT_ZERO, - "EUR:0.112", - "EUR:0.1"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9", - config_filename), - /* 0.009 + 0.009 + 0.022 - 0.001 - 0.002 - 0.008 = 0.029 => 0.02 */ - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-9", - ec.exchange_url, - "EUR:0.01", - bc.exchange_payto, - bc.user42_payto), - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run_with_fakebank (is, - all, - bc.exchange_auth.wire_gateway_url); -} - - -int -main (int argc, - char *const argv[]) -{ - const char *plugin_name; - char *testname; - - if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) - { - GNUNET_break (0); - return -1; - } - plugin_name++; - (void) GNUNET_asprintf (&testname, - "test-taler-exchange-aggregator-%s", - plugin_name); - (void) GNUNET_asprintf (&config_filename, - "%s.conf", - testname); - - GNUNET_log_setup ("test_taler_exchange_aggregator", - "DEBUG", - NULL); - - /* these might get in the way */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - - TALER_TESTING_cleanup_files (config_filename); - - if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename, - &ec)) - { - TALER_LOG_WARNING ("Could not prepare the exchange.\n"); - return 77; - } - - if (GNUNET_OK != TALER_TESTING_prepare_fakebank (config_filename, - "account-1", - &bc)) - { - TALER_LOG_WARNING ("Could not prepare the fakebank\n"); - return 77; - } - - if (GNUNET_OK != GNUNET_CONFIGURATION_parse_and_run (config_filename, - &prepare_database, - NULL)) - { - TALER_LOG_WARNING ("Could not prepare database for tests.\n"); - return result; - } - - result = TALER_TESTING_setup (&run, - NULL, - config_filename, - NULL, // no exchange process handle. - GNUNET_NO); // do not try to connect to the exchange - - GNUNET_free (config_filename); - GNUNET_free (testname); - dbc.plugin->drop_tables (dbc.plugin->cls); - TALER_EXCHANGEDB_plugin_unload (dbc.plugin); - return GNUNET_OK == result ? 0 : 1; -} - - -/* end of test_taler_exchange_aggregator.c */ diff --git a/src/lib/test_taler_exchange_httpd_home/.config/taler/account-1.json b/src/lib/test_taler_exchange_httpd_home/.config/taler/account-1.json deleted file mode 100644 index f39677eff..000000000 --- a/src/lib/test_taler_exchange_httpd_home/.config/taler/account-1.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "url": "payto://x-taler-bank/localhost/2", - "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R" -} \ No newline at end of file diff --git a/src/lib/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv b/src/lib/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv deleted file mode 100644 index 394926938..000000000 --- a/src/lib/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/lib/test_taler_exchange_wirewatch.c b/src/lib/test_taler_exchange_wirewatch.c deleted file mode 100644 index 9760223d0..000000000 --- a/src/lib/test_taler_exchange_wirewatch.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of TALER - (C) 2016, 2017, 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see -*/ - -/** - * @file lib/test_taler_exchange_wirewatch.c - * @brief Tests for taler-exchange-wirewatch and taler-exchange-aggregator logic; - * Performs an invalid wire transfer to the exchange, and then checks that - * wirewatch immediately sends the money back. - * Then performs a valid wire transfer, waits for the reserve to expire, - * and then checks that the aggregator sends the money back. - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include -#include -#include "taler_json_lib.h" -#include -#include "taler_fakebank_lib.h" -#include "taler_testing_lib.h" - - -/** - * Bank configuration data. - */ -static struct TALER_TESTING_BankConfiguration bc; - -/** - * Helper structure to keep exchange configuration values. - */ -static struct TALER_TESTING_ExchangeConfiguration ec; - -/** - * Name of the configuration file to use. - */ -static char *config_filename; - -static struct TALER_TESTING_Command -transfer_to_exchange (const char *label, - const char *amount) -{ - return TALER_TESTING_cmd_admin_add_incoming (label, - amount, - &bc.exchange_auth, - bc.user42_payto); -} - - -/** - * Main function that will tell the interpreter what commands to - * run. - * - * @param cls closure - */ -static void -run (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct TALER_TESTING_Command all[] = { - TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty", - config_filename), - TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty", - config_filename), - TALER_TESTING_cmd_check_bank_empty ("expect-transfers-empty-after-dry-run"), - - transfer_to_exchange ("run-transfer-good-to-exchange", - "EUR:5"), - TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-good-transfer", - config_filename), - - TALER_TESTING_cmd_check_bank_admin_transfer ( - "clear-good-transfer-to-the-exchange", - "EUR:5", - bc.user42_payto, // debit - bc.exchange_payto, // credit - "run-transfer-good-to-exchange"), - - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-non-expired-reserve", - config_filename), - - TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-1"), - TALER_TESTING_cmd_sleep ("wait (5s)", - 5), - TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-expired-reserve", - config_filename), - TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1", - ec.exchange_url, - "EUR:4.99", - bc.exchange_payto, - bc.user42_payto), - TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-2"), - TALER_TESTING_cmd_end () - }; - - TALER_TESTING_run_with_fakebank (is, - all, - bc.exchange_auth.wire_gateway_url); -} - - -int -main (int argc, - char *const argv[]) -{ - const char *plugin_name; - - /* these might get in the way */ - unsetenv ("XDG_DATA_HOME"); - unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test_taler_exchange_wirewatch", - "DEBUG", - NULL); - - if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) - { - GNUNET_break (0); - return -1; - } - plugin_name++; - { - char *testname; - - GNUNET_asprintf (&testname, - "test-taler-exchange-wirewatch-%s", - plugin_name); - GNUNET_asprintf (&config_filename, - "%s.conf", - testname); - GNUNET_free (testname); - } - /* check database is working */ - { - struct GNUNET_PQ_Context *conn; - struct GNUNET_PQ_ExecuteStatement es[] = { - GNUNET_PQ_EXECUTE_STATEMENT_END - }; - - conn = GNUNET_PQ_connect ("postgres:///talercheck", - NULL, - es, - NULL); - if (NULL == conn) - return 77; - GNUNET_PQ_disconnect (conn); - } - - TALER_TESTING_cleanup_files (config_filename); - if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename, - &ec)) - { - TALER_LOG_INFO ("Could not prepare the exchange\n"); - return 77; - } - - if (GNUNET_OK != - TALER_TESTING_prepare_fakebank (config_filename, - "account-1", - &bc)) - return 77; - - return - (GNUNET_OK == TALER_TESTING_setup_with_exchange (&run, - NULL, - config_filename)) ? 0 : 1; -} - - -/* end of test_taler_exchange_wirewatch.c */ diff --git a/src/lib/testing_api_cmd_auditor_deposit_confirmation.c b/src/lib/testing_api_cmd_auditor_deposit_confirmation.c deleted file mode 100644 index df80fef73..000000000 --- a/src/lib/testing_api_cmd_auditor_deposit_confirmation.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_auditor_deposit_confirmation.c - * @brief command for testing /deposit_confirmation. - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_auditor_service.h" -#include "taler_testing_lib.h" -#include "taler_signatures.h" -#include "backoff.h" - - -/** - * State for a "deposit confirmation" CMD. - */ -struct DepositConfirmationState -{ - - /** - * Reference to any command that is able to provide a deposit. - */ - const char *deposit_reference; - - /** - * What is the deposited amount without the fee (i.e. the - * amount we expect in the deposit confirmation)? - */ - const char *amount_without_fee; - - /** - * Which coin of the @e deposit_reference should we confirm. - */ - unsigned int coin_index; - - /** - * DepositConfirmation handle while operation is running. - */ - struct TALER_AUDITOR_DepositConfirmationHandle *dc; - - /** - * Auditor connection. - */ - struct TALER_AUDITOR_Handle *auditor; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Should we retry on (transient) failures? - */ - int do_retry; - -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -deposit_confirmation_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #deposit_confirmation_run. - * - * @param cls a `struct DepositConfirmationState` - */ -static void -do_retry (void *cls) -{ - struct DepositConfirmationState *dcs = cls; - - dcs->retry_task = NULL; - deposit_confirmation_run (dcs, - NULL, - dcs->is); -} - - -/** - * Callback to analyze the /deposit-confirmation response, just used - * to check if the response code is acceptable. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param obj raw response from the auditor. - */ -static void -deposit_confirmation_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const json_t *obj) -{ - struct DepositConfirmationState *dcs = cls; - - dcs->dc = NULL; - if (dcs->expected_response_code != http_status) - { - if (GNUNET_YES == dcs->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying deposit confirmation failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - dcs->backoff = GNUNET_TIME_UNIT_ZERO; - else - dcs->backoff = EXCHANGE_LIB_BACKOFF (dcs->backoff); - dcs->retry_task = GNUNET_SCHEDULER_add_delayed (dcs->backoff, - &do_retry, - dcs); - return; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - http_status, - dcs->is->commands[dcs->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (obj, stderr, 0); - TALER_TESTING_interpreter_fail (dcs->is); - return; - } - TALER_TESTING_interpreter_next (dcs->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -deposit_confirmation_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct DepositConfirmationState *dcs = cls; - const struct TALER_TESTING_Command *deposit_cmd; - struct GNUNET_HashCode h_wire; - struct GNUNET_HashCode h_contract_terms; - struct GNUNET_TIME_Absolute timestamp; - struct GNUNET_TIME_Absolute refund_deadline; - struct TALER_Amount amount_without_fee; - struct TALER_CoinSpendPublicKeyP coin_pub; - const struct TALER_MerchantPrivateKeyP *merchant_priv; - struct TALER_MerchantPublicKeyP merchant_pub; - const struct TALER_ExchangePublicKeyP *exchange_pub; - const struct TALER_ExchangeSignatureP *exchange_sig; - const json_t *wire_details; - const json_t *contract_terms; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - const struct TALER_EXCHANGE_Keys *keys; - const struct TALER_EXCHANGE_SigningPublicKey *spk; - - dcs->is = is; - GNUNET_assert (NULL != dcs->deposit_reference); - deposit_cmd - = TALER_TESTING_interpreter_lookup_command (is, - dcs->deposit_reference); - if (NULL == deposit_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_exchange_pub (deposit_cmd, - dcs->coin_index, - &exchange_pub)); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_exchange_sig (deposit_cmd, - dcs->coin_index, - &exchange_sig)); - keys = TALER_EXCHANGE_get_keys (dcs->is->exchange); - GNUNET_assert (NULL != keys); - spk = TALER_EXCHANGE_get_exchange_signing_key_info (keys, - exchange_pub); - - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_contract_terms (deposit_cmd, - dcs->coin_index, - &contract_terms)); - /* Very unlikely to fail */ - GNUNET_assert (NULL != contract_terms); - GNUNET_assert (GNUNET_OK == - TALER_JSON_hash (contract_terms, - &h_contract_terms)); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_wire_details (deposit_cmd, - dcs->coin_index, - &wire_details)); - GNUNET_assert (GNUNET_OK == - TALER_JSON_merchant_wire_signature_hash (wire_details, - &h_wire)); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_coin_priv (deposit_cmd, - dcs->coin_index, - &coin_priv)); - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_merchant_priv (deposit_cmd, - dcs->coin_index, - &merchant_priv)); - GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv, - &merchant_pub.eddsa_pub); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (dcs->amount_without_fee, - &amount_without_fee)); - /* timestamp is mandatory */ - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_absolute_time ("timestamp", ×tamp), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (contract_terms, - spec, - NULL, NULL)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - } - /* refund deadline is optional, defaults to zero */ - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_absolute_time ("refund_deadline", &refund_deadline), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (contract_terms, - spec, - NULL, NULL)) - { - refund_deadline = timestamp; - } - } - dcs->dc = TALER_AUDITOR_deposit_confirmation - (dcs->auditor, - &h_wire, - &h_contract_terms, - timestamp, - refund_deadline, - &amount_without_fee, - &coin_pub, - &merchant_pub, - exchange_pub, - exchange_sig, - &keys->master_pub, - spk->valid_from, - spk->valid_until, - spk->valid_legal, - &spk->master_sig, - &deposit_confirmation_cb, - dcs); - - if (NULL == dcs->dc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - return; -} - - -/** - * Free the state of a "deposit_confirmation" CMD, and possibly cancel a - * pending operation thereof. - * - * @param cls closure, a `struct DepositConfirmationState` - * @param cmd the command which is being cleaned up. - */ -static void -deposit_confirmation_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct DepositConfirmationState *dcs = cls; - - if (NULL != dcs->dc) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - dcs->is->ip, - cmd->label); - TALER_AUDITOR_deposit_confirmation_cancel (dcs->dc); - dcs->dc = NULL; - } - if (NULL != dcs->retry_task) - { - GNUNET_SCHEDULER_cancel (dcs->retry_task); - dcs->retry_task = NULL; - } - GNUNET_free (dcs); -} - - -/** - * Offer internal data to other commands. - * - * @param cls closure. - * @param[out] ret set to the wanted data. - * @param trait name of the trait. - * @param index index number of the traits to be returned. - * - * @return #GNUNET_OK on success - */ -static int -deposit_confirmation_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - /* Must define this function because some callbacks - * look for certain traits on _all_ the commands. */ - return GNUNET_SYSERR; -} - - -/** - * Create a "deposit-confirmation" command. - * - * @param label command label. - * @param auditor auditor connection. - * @param deposit_reference reference to any operation that can - * provide a coin. - * @param coin_index if @a deposit_reference offers an array of - * coins, this parameter selects which one in that array. - * This value is currently ignored, as only one-coin - * deposits are implemented. - * @param amount_without_fee deposited amount without the fee - * @param expected_response_code expected HTTP response code. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_deposit_confirmation (const char *label, - struct TALER_AUDITOR_Handle *auditor, - const char *deposit_reference, - unsigned int coin_index, - const char *amount_without_fee, - unsigned int expected_response_code) -{ - struct DepositConfirmationState *dcs; - - dcs = GNUNET_new (struct DepositConfirmationState); - dcs->auditor = auditor; - dcs->deposit_reference = deposit_reference; - dcs->coin_index = coin_index; - dcs->amount_without_fee = amount_without_fee; - dcs->expected_response_code = expected_response_code; - - { - struct TALER_TESTING_Command cmd = { - .cls = dcs, - .label = label, - .run = &deposit_confirmation_run, - .cleanup = &deposit_confirmation_cleanup, - .traits = &deposit_confirmation_traits - }; - - return cmd; - } -} - - -/** - * Modify a deposit confirmation command to enable retries when we get - * transient errors from the auditor. - * - * @param cmd a deposit confirmation command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_deposit_confirmation_with_retry (struct TALER_TESTING_Command - cmd) -{ - struct DepositConfirmationState *dcs; - - GNUNET_assert (&deposit_confirmation_run == cmd.run); - dcs = cmd.cls; - dcs->do_retry = GNUNET_YES; - return cmd; -} - - -/* end of testing_auditor_api_cmd_deposit_confirmation.c */ diff --git a/src/lib/testing_api_cmd_auditor_exchanges.c b/src/lib/testing_api_cmd_auditor_exchanges.c deleted file mode 100644 index d021b0d34..000000000 --- a/src/lib/testing_api_cmd_auditor_exchanges.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_auditor_exchanges.c - * @brief command for testing /exchanges of the auditor - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_auditor_service.h" -#include "taler_testing_lib.h" -#include "taler_signatures.h" -#include "backoff.h" - - -/** - * State for a "deposit confirmation" CMD. - */ -struct ExchangesState -{ - - /** - * Exchanges handle while operation is running. - */ - struct TALER_AUDITOR_ListExchangesHandle *leh; - - /** - * Auditor connection. - */ - struct TALER_AUDITOR_Handle *auditor; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * URL of the exchange expected to be included in the response. - */ - const char *exchange_url; - - /** - * Should we retry on (transient) failures? - */ - int do_retry; - -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -exchanges_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #exchanges_run. - * - * @param cls a `struct ExchangesState` - */ -static void -do_retry (void *cls) -{ - struct ExchangesState *es = cls; - - es->retry_task = NULL; - exchanges_run (es, - NULL, - es->is); -} - - -/** - * Callback to analyze the /exchanges response. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param num_exchanges length of the @a ei array - * @param ei array with information about the exchanges - * @param raw_response raw response from the auditor. - */ -static void -exchanges_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - unsigned int num_exchanges, - const struct TALER_AUDITOR_ExchangeInfo *ei, - const json_t *raw_response) -{ - struct ExchangesState *es = cls; - - es->leh = NULL; - if (es->expected_response_code != http_status) - { - if (GNUNET_YES == es->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying list exchanges failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - es->backoff = GNUNET_TIME_UNIT_ZERO; - else - es->backoff = EXCHANGE_LIB_BACKOFF (es->backoff); - es->retry_task = GNUNET_SCHEDULER_add_delayed (es->backoff, - &do_retry, - es); - return; - } - } - GNUNET_log - (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - http_status, - es->is->commands[es->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (raw_response, stderr, 0); - TALER_TESTING_interpreter_fail (es->is); - return; - } - if (NULL != es->exchange_url) - { - unsigned int found = GNUNET_NO; - - for (unsigned int i = 0; - iexchange_url, - ei[i].exchange_url)) - found = GNUNET_YES; - if (GNUNET_NO == found) - { - TALER_LOG_ERROR - ("Exchange '%s' doesn't exist at this auditor\n", - es->exchange_url); - TALER_TESTING_interpreter_fail (es->is); - return; - } - - TALER_LOG_DEBUG ("Exchange '%s' exists at this auditor!\n", - es->exchange_url); - } - TALER_TESTING_interpreter_next (es->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -exchanges_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct ExchangesState *es = cls; - - es->is = is; - es->leh = TALER_AUDITOR_list_exchanges - (is->auditor, - &exchanges_cb, - es); - - if (NULL == es->leh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - return; -} - - -/** - * Free the state of a "exchanges" CMD, and possibly cancel a - * pending operation thereof. - * - * @param cls closure, a `struct ExchangesState` - * @param cmd the command which is being cleaned up. - */ -static void -exchanges_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct ExchangesState *es = cls; - - if (NULL != es->leh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - es->is->ip, - cmd->label); - TALER_AUDITOR_list_exchanges_cancel (es->leh); - es->leh = NULL; - } - if (NULL != es->retry_task) - { - GNUNET_SCHEDULER_cancel (es->retry_task); - es->retry_task = NULL; - } - GNUNET_free (es); -} - - -/** - * Offer internal data to other commands. - * - * @param cls closure. - * @param[out] ret set to the wanted data. - * @param trait name of the trait. - * @param index index number of the traits to be returned. - * @return #GNUNET_OK on success - */ -static int -exchanges_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - /* Must define this function because some callbacks - * look for certain traits on _all_ the commands. */ - return GNUNET_SYSERR; -} - - -/** - * Create a "list exchanges" command. - * - * @param label command label. - * @param auditor auditor connection. - * @param expected_response_code expected HTTP response code. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exchanges (const char *label, - struct TALER_AUDITOR_Handle *auditor, - unsigned int expected_response_code) -{ - struct ExchangesState *es; - - es = GNUNET_new (struct ExchangesState); - es->auditor = auditor; - es->expected_response_code = expected_response_code; - - { - struct TALER_TESTING_Command cmd = { - .cls = es, - .label = label, - .run = &exchanges_run, - .cleanup = &exchanges_cleanup, - .traits = &exchanges_traits - }; - - return cmd; - } -} - - -/** - * Create a "list exchanges" command and check whether - * a particular exchange belongs to the returned bundle. - * - * @param label command label. - * @param expected_response_code expected HTTP response code. - * @param exchange_url URL of the exchange supposed to - * be included in the response. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exchanges_with_url (const char *label, - unsigned int expected_response_code, - const char *exchange_url) -{ - struct ExchangesState *es; - - es = GNUNET_new (struct ExchangesState); - es->expected_response_code = expected_response_code; - es->exchange_url = exchange_url; - { - struct TALER_TESTING_Command cmd = { - .cls = es, - .label = label, - .run = &exchanges_run, - .cleanup = &exchanges_cleanup, - .traits = &exchanges_traits - }; - - return cmd; - } -} - - -/** - * Modify an exchanges command to enable retries when we get - * transient errors from the auditor. - * - * @param cmd a deposit confirmation command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exchanges_with_retry (struct TALER_TESTING_Command cmd) -{ - struct ExchangesState *es; - - GNUNET_assert (&exchanges_run == cmd.run); - es = cmd.cls; - es->do_retry = GNUNET_YES; - return cmd; -} - - -/* end of testing_auditor_api_cmd_exchanges.c */ diff --git a/src/lib/testing_api_cmd_auditor_exec_auditor.c b/src/lib/testing_api_cmd_auditor_exec_auditor.c deleted file mode 100644 index f56038e78..000000000 --- a/src/lib/testing_api_cmd_auditor_exec_auditor.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ -/** - * @file lib/testing_api_cmd_auditor_exec_auditor.c - * @brief run the taler-auditor command - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "auditor_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "auditor" CMD. - */ -struct AuditorState -{ - - /** - * Process for the "auditor" command. - */ - struct GNUNET_OS_Process *auditor_proc; - - /** - * Configuration file used by the command. - */ - const char *config_filename; -}; - - -/** - * Run the command; calls the `taler-auditor' program. - * - * @param cls closure. - * @param cmd the commaind being run. - * @param is interpreter state. - */ -static void -auditor_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct AuditorState *ks = cls; - - ks->auditor_proc - = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor", - "taler-auditor", - "-c", ks->config_filename, - NULL); - if (NULL == ks->auditor_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Free the state of a "auditor" CMD, and possibly kills its - * process if it did not terminate correctly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -auditor_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct AuditorState *ks = cls; - - if (NULL != ks->auditor_proc) - { - GNUNET_break (0 == - GNUNET_OS_process_kill (ks->auditor_proc, - SIGKILL)); - GNUNET_OS_process_wait (ks->auditor_proc); - GNUNET_OS_process_destroy (ks->auditor_proc); - ks->auditor_proc = NULL; - } - GNUNET_free (ks); -} - - -/** - * Offer "auditor" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -auditor_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct AuditorState *ks = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_process (0, &ks->auditor_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make the "exec-auditor" CMD. - * - * @param label command label. - * @param config_filename configuration filename. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_auditor (const char *label, - const char *config_filename) -{ - struct AuditorState *ks; - - ks = GNUNET_new (struct AuditorState); - ks->config_filename = config_filename; - { - struct TALER_TESTING_Command cmd = { - .cls = ks, - .label = label, - .run = &auditor_run, - .cleanup = &auditor_cleanup, - .traits = &auditor_traits - }; - - return cmd; - } -} - - -/* end of testing_auditor_api_cmd_exec_auditor.c */ diff --git a/src/lib/testing_api_cmd_auditor_exec_auditor_dbinit.c b/src/lib/testing_api_cmd_auditor_exec_auditor_dbinit.c deleted file mode 100644 index 2cbe5197e..000000000 --- a/src/lib/testing_api_cmd_auditor_exec_auditor_dbinit.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ -/** - * @file lib/testing_api_cmd_auditor_exec_auditor_dbinit.c - * @brief run the taler-auditor-dbinit "-r" command - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "auditor_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "auditor-dbinit" CMD. - */ -struct AuditorDbinitState -{ - - /** - * Process for the "auditor-dbinit" command. - */ - struct GNUNET_OS_Process *auditor_dbinit_proc; - - /** - * Configuration file used by the command. - */ - const char *config_filename; -}; - - -/** - * Run the command; calls the `taler-auditor-dbinit' program. - * - * @param cls closure. - * @param cmd the commaind being run. - * @param is interpreter state. - */ -static void -auditor_dbinit_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct AuditorDbinitState *ks = cls; - - ks->auditor_dbinit_proc - = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-dbinit", - "taler-auditor-dbinit", - "-c", ks->config_filename, - "-r", - NULL); - if (NULL == ks->auditor_dbinit_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Free the state of a "auditor-dbinit" CMD, and possibly kills its - * process if it did not terminate correctly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -auditor_dbinit_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct AuditorDbinitState *ks = cls; - - if (NULL != ks->auditor_dbinit_proc) - { - GNUNET_break (0 == - GNUNET_OS_process_kill (ks->auditor_dbinit_proc, - SIGKILL)); - GNUNET_OS_process_wait (ks->auditor_dbinit_proc); - GNUNET_OS_process_destroy (ks->auditor_dbinit_proc); - ks->auditor_dbinit_proc = NULL; - } - GNUNET_free (ks); -} - - -/** - * Offer "auditor-dbinit" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -auditor_dbinit_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct AuditorDbinitState *ks = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_process (0, &ks->auditor_dbinit_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make the "exec-auditor-dbinit" CMD. - * - * @param label command label. - * @param config_filename configuration filename. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_auditor_dbinit (const char *label, - const char *config_filename) -{ - struct AuditorDbinitState *ks; - - ks = GNUNET_new (struct AuditorDbinitState); - ks->config_filename = config_filename; - { - struct TALER_TESTING_Command cmd = { - .cls = ks, - .label = label, - .run = &auditor_dbinit_run, - .cleanup = &auditor_dbinit_cleanup, - .traits = &auditor_dbinit_traits - }; - - return cmd; - } -} - - -/* end of testing_auditor_api_cmd_exec_auditor_dbinit.c */ diff --git a/src/lib/testing_api_cmd_auditor_exec_wire_auditor.c b/src/lib/testing_api_cmd_auditor_exec_wire_auditor.c deleted file mode 100644 index 458a0b349..000000000 --- a/src/lib/testing_api_cmd_auditor_exec_wire_auditor.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ -/** - * @file lib/testing_api_cmd_auditor_exec_wire_auditor.c - * @brief run the taler-wire-auditor command - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "auditor_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "wire-auditor" CMD. - */ -struct WireAuditorState -{ - - /** - * Process for the "wire-auditor" command. - */ - struct GNUNET_OS_Process *wire_auditor_proc; - - /** - * Configuration file used by the command. - */ - const char *config_filename; -}; - - -/** - * Run the command; calls the `taler-wire-auditor' program. - * - * @param cls closure. - * @param cmd the commaind being run. - * @param is interpreter state. - */ -static void -wire_auditor_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct WireAuditorState *ks = cls; - - ks->wire_auditor_proc - = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-wire-auditor", - "taler-wire-auditor", - "-c", ks->config_filename, - NULL); - if (NULL == ks->wire_auditor_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Free the state of a "wire-auditor" CMD, and possibly kills its - * process if it did not terminate correctly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -wire_auditor_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct WireAuditorState *ks = cls; - - if (NULL != ks->wire_auditor_proc) - { - GNUNET_break (0 == - GNUNET_OS_process_kill (ks->wire_auditor_proc, - SIGKILL)); - GNUNET_OS_process_wait (ks->wire_auditor_proc); - GNUNET_OS_process_destroy (ks->wire_auditor_proc); - ks->wire_auditor_proc = NULL; - } - GNUNET_free (ks); -} - - -/** - * Offer "wire-auditor" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -wire_auditor_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct WireAuditorState *ks = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_process (0, &ks->wire_auditor_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make the "exec wire-auditor" CMD. - * - * @param label command label. - * @param config_filename configuration filename. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_wire_auditor (const char *label, - const char *config_filename) -{ - struct WireAuditorState *ks; - - ks = GNUNET_new (struct WireAuditorState); - ks->config_filename = config_filename; - { - struct TALER_TESTING_Command cmd = { - .cls = ks, - .label = label, - .run = &wire_auditor_run, - .cleanup = &wire_auditor_cleanup, - .traits = &wire_auditor_traits - }; - - return cmd; - } -} - - -/* end of testing_auditor_api_cmd_exec_wire_auditor.c */ diff --git a/src/lib/testing_api_cmd_bank_admin_add_incoming.c b/src/lib/testing_api_cmd_bank_admin_add_incoming.c deleted file mode 100644 index 4dea3d4df..000000000 --- a/src/lib/testing_api_cmd_bank_admin_add_incoming.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_bank_admin_add_incoming.c - * @brief implementation of a bank /admin/add-incoming command - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "backoff.h" -#include "taler_json_lib.h" -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "fakebank transfer" CMD. - */ -struct AdminAddIncomingState -{ - - /** - * Label of any command that can trait-offer a reserve priv. - */ - const char *reserve_reference; - - /** - * Wire transfer amount. - */ - struct TALER_Amount amount; - - /** - * Base URL of the credited account. - */ - const char *exchange_credit_url; - - /** - * Money sender payto URL. - */ - const char *payto_debit_account; - - /** - * Username to use for authentication. - */ - struct TALER_BANK_AuthenticationData auth; - - /** - * Set (by the interpreter) to the reserve's private key - * we used to make a wire transfer subject line with. - */ - struct TALER_ReservePrivateKeyP reserve_priv; - - /** - * Reserve public key matching @e reserve_priv. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Handle to the pending request at the fakebank. - */ - struct TALER_BANK_AdminAddIncomingHandle *aih; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Set to the wire transfer's unique ID. - */ - uint64_t serial_id; - - /** - * Timestamp of the transaction (as returned from the bank). - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * Merchant instance. Sometimes used to get the tip reserve - * private key by reading the appropriate config section. - */ - const char *instance; - - /** - * Configuration filename. Used to get the tip reserve key - * filename (used to obtain a public key to write in the - * transfer subject). - */ - const char *config_filename; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Was this command modified via - * #TALER_TESTING_cmd_admin_add_incoming_with_retry to - * enable retries? - */ - int do_retry; -}; - - -/** - * Run the "fakebank transfer" CMD. - * - * @param cls closure. - * @param cmd CMD being run. - * @param is interpreter state. - */ -static void -admin_add_incoming_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #admin_add_incoming_run. - * - * @param cls a `struct AdminAddIncomingState` - */ -static void -do_retry (void *cls) -{ - struct AdminAddIncomingState *fts = cls; - - fts->retry_task = NULL; - admin_add_incoming_run (fts, - NULL, - fts->is); -} - - -/** - * This callback will process the fakebank response to the wire - * transfer. It just checks whether the HTTP response code is - * acceptable. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for - * successful status request; 0 if the exchange's reply is - * bogus (fails to follow the protocol) - * @param ec taler-specific error code, #TALER_EC_NONE on success - * @param serial_id unique ID of the wire transfer - * @param timestamp time stamp of the transaction made. - * @param json raw response - */ -static void -confirmation_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - struct GNUNET_TIME_Absolute timestamp, - const json_t *json) -{ - struct AdminAddIncomingState *fts = cls; - struct TALER_TESTING_Interpreter *is = fts->is; - - fts->aih = NULL; - if (MHD_HTTP_OK != http_status) - { - if (GNUNET_YES == fts->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log - (GNUNET_ERROR_TYPE_INFO, - "Retrying fakebank transfer failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - fts->backoff = GNUNET_TIME_UNIT_ZERO; - else - fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); - fts->retry_task = GNUNET_SCHEDULER_add_delayed - (fts->backoff, - &do_retry, - fts); - return; - } - } - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Fakebank returned HTTP status %u/%d\n", - http_status, - (int) ec); - TALER_TESTING_interpreter_fail (is); - return; - } - - fts->serial_id = serial_id; - fts->timestamp = timestamp; - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the "fakebank transfer" CMD. - * - * @param cls closure. - * @param cmd CMD being run. - * @param is interpreter state. - */ -static void -admin_add_incoming_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct AdminAddIncomingState *fts = cls; - - /* Use reserve public key as subject */ - if (NULL != fts->reserve_reference) - { - const struct TALER_TESTING_Command *ref; - const struct TALER_ReservePrivateKeyP *reserve_priv; - - ref = TALER_TESTING_interpreter_lookup_command - (is, fts->reserve_reference); - if (NULL == ref) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_priv (ref, - 0, - &reserve_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv; - } - else - { - if (NULL != fts->instance) - { - char *section; - char *keys; - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - struct GNUNET_CONFIGURATION_Handle *cfg; - - GNUNET_assert (NULL != fts->config_filename); - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != - GNUNET_CONFIGURATION_load (cfg, - fts->config_filename)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_asprintf (§ion, - "instance-%s", - fts->instance); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename - (cfg, - section, - "TIP_RESERVE_PRIV_FILENAME", - &keys)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Configuration fails to specify reserve" - " private key filename in section %s\n", - section); - GNUNET_free (section); - TALER_TESTING_interpreter_fail (is); - return; - } - priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys); - GNUNET_free (keys); - if (NULL == priv) - { - GNUNET_log_config_invalid - (GNUNET_ERROR_TYPE_ERROR, - section, - "TIP_RESERVE_PRIV_FILENAME", - "Failed to read private key"); - GNUNET_free (section); - TALER_TESTING_interpreter_fail (is); - return; - } - fts->reserve_priv.eddsa_priv = *priv; - GNUNET_free (section); - GNUNET_free (priv); - GNUNET_CONFIGURATION_destroy (cfg); - } - else - { - /* No referenced reserve, no instance to take priv - * from, no explicit subject given: create new key! */ - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - - priv = GNUNET_CRYPTO_eddsa_key_create (); - fts->reserve_priv.eddsa_priv = *priv; - GNUNET_free (priv); - } - } - GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv, - &fts->reserve_pub.eddsa_pub); - fts->is = is; - fts->aih - = TALER_BANK_admin_add_incoming - (TALER_TESTING_interpreter_get_context (is), - &fts->auth, - &fts->reserve_pub, - &fts->amount, - fts->payto_debit_account, - &confirmation_cb, - fts); - if (NULL == fts->aih) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } -} - - -/** - * Free the state of a "/admin/add-incoming" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure - * @param cmd current CMD being cleaned up. - */ -static void -admin_add_incoming_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct AdminAddIncomingState *fts = cls; - - if (NULL != fts->aih) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); - TALER_BANK_admin_add_incoming_cancel (fts->aih); - fts->aih = NULL; - } - if (NULL != fts->retry_task) - { - GNUNET_SCHEDULER_cancel (fts->retry_task); - fts->retry_task = NULL; - } - GNUNET_free (fts); -} - - -/** - * Offer internal data from a "/admin/add-incoming" CMD to other - * commands. - * - * @param cls closure. - * @param[out] ret result - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -admin_add_incoming_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct AdminAddIncomingState *fts = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_bank_row (&fts->serial_id), - TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT, - fts->payto_debit_account), - /* Used as a marker, content does not matter */ - TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT, - "payto://void/the-exchange"), - TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL, - fts->exchange_credit_url), - TALER_TESTING_make_trait_amount_obj (0, &fts->amount), - TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), - TALER_TESTING_make_trait_reserve_priv (0, - &fts->reserve_priv), - TALER_TESTING_make_trait_reserve_pub (0, - &fts->reserve_pub), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Create internal state for "/admin/add-incoming" CMD. - * - * @param amount the amount to transfer. - * @param payto_debit_account which account sends money - * @param auth authentication data - * @return the internal state - */ -static struct AdminAddIncomingState * -make_fts (const char *amount, - const struct TALER_BANK_AuthenticationData *auth, - const char *payto_debit_account) -{ - struct AdminAddIncomingState *fts; - - fts = GNUNET_new (struct AdminAddIncomingState); - fts->exchange_credit_url = auth->wire_gateway_url; - fts->payto_debit_account = payto_debit_account; - fts->auth = *auth; - if (GNUNET_OK != - TALER_string_to_amount (amount, - &fts->amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s'\n", - amount); - GNUNET_assert (0); - } - return fts; -} - - -/** - * Helper function to create admin/add-incoming command. - * - * @param label command label. - * @param fts internal state to use - * @return the command. - */ -static struct TALER_TESTING_Command -make_command (const char *label, - struct AdminAddIncomingState *fts) -{ - struct TALER_TESTING_Command cmd = { - .cls = fts, - .label = label, - .run = &admin_add_incoming_run, - .cleanup = &admin_add_incoming_cleanup, - .traits = &admin_add_incoming_traits - }; - - return cmd; -} - - -/** - * Create admin/add-incoming command. - * - * @param label command label. - * @param amount amount to transfer. - * @param payto_debit_account which account sends money. - * @param auth authentication data - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_admin_add_incoming (const char *label, - const char *amount, - const struct - TALER_BANK_AuthenticationData *auth, - const char *payto_debit_account) -{ - return make_command (label, - make_fts (amount, - auth, - payto_debit_account)); -} - - -/** - * Create "/admin/add-incoming" CMD, letting the caller specify - * a reference to a command that can offer a reserve private key. - * This private key will then be used to construct the subject line - * of the wire transfer. - * - * @param label command label. - * @param amount the amount to transfer. - * @param payto_debit_account which account sends money - * @param auth authentication data - * @param ref reference to a command that can offer a reserve - * private key. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_admin_add_incoming_with_ref - (const char *label, - const char *amount, - const struct TALER_BANK_AuthenticationData *auth, - const char *payto_debit_account, - const char *ref) -{ - struct AdminAddIncomingState *fts; - - fts = make_fts (amount, - auth, - payto_debit_account); - fts->reserve_reference = ref; - return make_command (label, - fts); -} - - -/** - * Create "/admin/add-incoming" CMD, letting the caller specifying - * the merchant instance. This version is useful when a tip - * reserve should be topped up, in fact the interpreter will need - * the "tipping instance" in order to get the instance public key - * and make a wire transfer subject out of it. - * - * @param label command label. - * @param amount amount to transfer. - * @param payto_debit_account which account (expressed as a number) - * gives money - * @param auth authentication data - * @param instance the instance that runs the tipping. Under this - * instance, the configuration file will provide the private - * key of the tipping reserve. This data will then used to - * construct the wire transfer subject line. - * @param config_filename configuration file to use. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_admin_add_incoming_with_instance - (const char *label, - const char *amount, - const struct TALER_BANK_AuthenticationData *auth, - const char *payto_debit_account, - const char *instance, - const char *config_filename) -{ - struct AdminAddIncomingState *fts; - - fts = make_fts (amount, - auth, - payto_debit_account); - fts->instance = instance; - fts->config_filename = config_filename; - - return make_command (label, - fts); -} - - -/** - * Modify a fakebank transfer command to enable retries when the - * reserve is not yet full or we get other transient errors from the - * fakebank. - * - * @param cmd a fakebank transfer command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_admin_add_incoming_retry (struct TALER_TESTING_Command cmd) -{ - struct AdminAddIncomingState *fts; - - GNUNET_assert (&admin_add_incoming_run == cmd.run); - fts = cmd.cls; - fts->do_retry = GNUNET_YES; - return cmd; -} - - -/* end of testing_api_cmd_bank_admin_add_incoming.c */ diff --git a/src/lib/testing_api_cmd_bank_admin_check.c b/src/lib/testing_api_cmd_bank_admin_check.c deleted file mode 100644 index 97e2eade2..000000000 --- a/src/lib/testing_api_cmd_bank_admin_check.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_bank_admin_check.c - * @brief command to check if a particular admin/add-incoming transfer took - * place. - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" - - -/** - * State for a "bank check" CMD. - */ -struct BankAdminCheckState -{ - - /** - * Expected transferred amount. - */ - const char *amount; - - /** - * Expected debit bank account. - */ - const char *debit_payto; - - /** - * Expected credit bank account. - */ - const char *credit_payto; - - /** - * Command providing the reserve public key trait to use. - */ - const char *reserve_pub_ref; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - -}; - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -check_bank_admin_transfer_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct BankAdminCheckState *bcs = cls; - struct TALER_Amount amount; - char *debit_account; - char *credit_account; - const char *debit_payto; - const char *credit_payto; - const struct TALER_ReservePublicKeyP *reserve_pub; - const struct TALER_TESTING_Command *cmd_ref; - - cmd_ref - = TALER_TESTING_interpreter_lookup_command (is, - bcs->reserve_pub_ref); - if (NULL == cmd_ref) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_pub (cmd_ref, - 0, - &reserve_pub)) - { - GNUNET_break (0); - TALER_LOG_ERROR ("Command reference fails to provide reserve public key\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_LOG_INFO ("Deposit reference NOT given\n"); - debit_payto = bcs->debit_payto; - credit_payto = bcs->credit_payto; - if (GNUNET_OK != - TALER_string_to_amount (bcs->amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - bcs->amount, - is->ip); - TALER_TESTING_interpreter_fail (is); - return; - } - debit_account = TALER_xtalerbank_account_from_payto (debit_payto); - credit_account = TALER_xtalerbank_account_from_payto (credit_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "converted debit_payto (%s) to debit_account (%s)\n", - debit_payto, - debit_account); - if (GNUNET_OK != - TALER_FAKEBANK_check_credit (is->fakebank, - &amount, - debit_account, - credit_account, - reserve_pub)) - { - GNUNET_break (0); - GNUNET_free (credit_account); - GNUNET_free (debit_account); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_free (credit_account); - GNUNET_free (debit_account); - TALER_TESTING_interpreter_next (is); -} - - -/** - * Free the state of a "bank check" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -check_bank_admin_transfer_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct BankAdminCheckState *bcs = cls; - - GNUNET_free (bcs); -} - - -/** - * Offer internal data from a "bank admin check" CMD state. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -check_bank_admin_transfer_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_trait_end () - }; - - (void) cls; - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make a "bank check" CMD. It checks whether a particular wire transfer to - * the exchange (credit) has been made or not. - * - * @param label the command label. - * @param amount the amount expected to be transferred. - * @param debit_payto the account that gave money. - * @param credit_payto the account that received money. - * @param reserve_pub_ref command that provides the reserve public key to expect - * @return the command - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_bank_admin_transfer - (const char *label, - const char *amount, - const char *debit_payto, - const char *credit_payto, - const char *reserve_pub_ref) -{ - struct BankAdminCheckState *bcs; - - bcs = GNUNET_new (struct BankAdminCheckState); - bcs->amount = amount; - bcs->debit_payto = debit_payto; - bcs->credit_payto = credit_payto; - bcs->reserve_pub_ref = reserve_pub_ref; - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = bcs, - .run = &check_bank_admin_transfer_run, - .cleanup = &check_bank_admin_transfer_cleanup, - .traits = &check_bank_admin_transfer_traits - }; - - return cmd; - } -} diff --git a/src/lib/testing_api_cmd_bank_check.c b/src/lib/testing_api_cmd_bank_check.c deleted file mode 100644 index e8bd415b3..000000000 --- a/src/lib/testing_api_cmd_bank_check.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_bank_check.c - * @brief command to check if a particular wire transfer took - * place. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" - - -/** - * State for a "bank check" CMD. - */ -struct BankCheckState -{ - - /** - * Base URL of the exchange supposed to be - * involved in the bank transaction. - */ - const char *exchange_base_url; - - /** - * Expected transferred amount. - */ - const char *amount; - - /** - * Expected debit bank account. - */ - const char *debit_payto; - - /** - * Expected credit bank account. - */ - const char *credit_payto; - - /** - * Binary form of the wire transfer subject. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Reference to a CMD that provides all the data - * needed to issue the bank check. If NULL, that data - * must exist here in the state. - */ - const char *deposit_reference; -}; - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -check_bank_transfer_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct BankCheckState *bcs = cls; - struct TALER_Amount amount; - char *debit_account; - char *credit_account; - const char *exchange_base_url; - const char *debit_payto; - const char *credit_payto; - - if (NULL == bcs->deposit_reference) - { - TALER_LOG_INFO ("Deposit reference NOT given\n"); - debit_payto = bcs->debit_payto; - credit_payto = bcs->credit_payto; - exchange_base_url = bcs->exchange_base_url; - - if (GNUNET_OK != - TALER_string_to_amount (bcs->amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - bcs->amount, - is->ip); - TALER_TESTING_interpreter_fail (is); - return; - } - } - else - { - const struct TALER_TESTING_Command *deposit_cmd; - const struct TALER_Amount *amount_ptr; - - TALER_LOG_INFO ("`%s' uses reference (%s/%p)\n", - TALER_TESTING_interpreter_get_current_label - (is), - bcs->deposit_reference, - bcs->deposit_reference); - deposit_cmd - = TALER_TESTING_interpreter_lookup_command (is, - bcs->deposit_reference); - if (NULL == deposit_cmd) - TALER_TESTING_FAIL (is); - if ( (GNUNET_OK != - TALER_TESTING_get_trait_amount_obj (deposit_cmd, - 0, - &amount_ptr)) || - (GNUNET_OK != - TALER_TESTING_get_trait_payto (deposit_cmd, - TALER_TESTING_PT_DEBIT, - &debit_payto)) || - (GNUNET_OK != - TALER_TESTING_get_trait_payto (deposit_cmd, - TALER_TESTING_PT_CREDIT, - &credit_payto)) || - (GNUNET_OK != - TALER_TESTING_get_trait_url (deposit_cmd, - TALER_TESTING_UT_EXCHANGE_BASE_URL, - &exchange_base_url)) ) - TALER_TESTING_FAIL (is); - amount = *amount_ptr; - } - - - debit_account = TALER_xtalerbank_account_from_payto (debit_payto); - credit_account = TALER_xtalerbank_account_from_payto (credit_payto); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "converted debit_payto (%s) to debit_account (%s)\n", - debit_payto, - debit_account); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "converted credit_payto (%s) to credit_account (%s)\n", - credit_payto, - credit_account); - - if (GNUNET_OK != - TALER_FAKEBANK_check_debit (is->fakebank, - &amount, - debit_account, - credit_account, - exchange_base_url, - &bcs->wtid)) - { - GNUNET_break (0); - GNUNET_free (credit_account); - GNUNET_free (debit_account); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_free (credit_account); - GNUNET_free (debit_account); - TALER_TESTING_interpreter_next (is); -} - - -/** - * Free the state of a "bank check" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -check_bank_transfer_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct BankCheckState *bcs = cls; - - GNUNET_free (bcs); -} - - -/** - * Offer internal data from a "bank check" CMD state. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -check_bank_transfer_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct BankCheckState *bcs = cls; - struct TALER_WireTransferIdentifierRawP *wtid_ptr = &bcs->wtid; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_wtid (0, - wtid_ptr), - TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, - bcs->exchange_base_url), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make a "bank check" CMD. It checks whether a - * particular wire transfer has been made or not. - * - * @param label the command label. - * @param exchange_base_url base url of the exchange involved in - * the wire transfer. - * @param amount the amount expected to be transferred. - * @param debit_payto the account that gave money. - * @param credit_payto the account that received money. - * - * @return the command - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_bank_transfer (const char *label, - const char *exchange_base_url, - const char *amount, - const char *debit_payto, - const char *credit_payto) -{ - struct BankCheckState *bcs; - - bcs = GNUNET_new (struct BankCheckState); - bcs->exchange_base_url = exchange_base_url; - bcs->amount = amount; - bcs->debit_payto = debit_payto; - bcs->credit_payto = credit_payto; - bcs->deposit_reference = NULL; - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = bcs, - .run = &check_bank_transfer_run, - .cleanup = &check_bank_transfer_cleanup, - .traits = &check_bank_transfer_traits - }; - - return cmd; - } -} - - -/** - * Define a "bank check" CMD that takes the input - * data from another CMD that offers it. - * - * @param label command label. - * @param deposit_reference reference to a CMD that is - * able to provide the "check bank transfer" operation - * input data. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_bank_transfer_with_ref - (const char *label, - const char *deposit_reference) -{ - struct BankCheckState *bcs; - - bcs = GNUNET_new (struct BankCheckState); - bcs->deposit_reference = deposit_reference; - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = bcs, - .run = &check_bank_transfer_run, - .cleanup = &check_bank_transfer_cleanup, - .traits = &check_bank_transfer_traits - }; - - return cmd; - } -} diff --git a/src/lib/testing_api_cmd_bank_check_empty.c b/src/lib/testing_api_cmd_bank_check_empty.c deleted file mode 100644 index f099afcb1..000000000 --- a/src/lib/testing_api_cmd_bank_check_empty.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_bank_check_empty.c - * @brief command to check if a particular wire transfer took - * place. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" - - -/** - * Cleanup the state, only defined to respect the API. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -check_bank_empty_cleanup - (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - return; -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -check_bank_empty_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Some commands (notably "bank history") could randomly - * look for traits; this way makes sure we don't segfault. - */ -static int -check_bank_empty_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - return GNUNET_SYSERR; -} - - -/** - * Checks wheter all the wire transfers got "checked" - * by the "bank check" CMD. - * - * @param label command label. - * - * @return the command - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_bank_empty (const char *label) -{ - struct TALER_TESTING_Command cmd = { - .label = label, - .run = &check_bank_empty_run, - .cleanup = &check_bank_empty_cleanup, - .traits = &check_bank_empty_traits - }; - - return cmd; -} diff --git a/src/lib/testing_api_cmd_bank_history_credit.c b/src/lib/testing_api_cmd_bank_history_credit.c deleted file mode 100644 index 49317162e..000000000 --- a/src/lib/testing_api_cmd_bank_history_credit.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_bank_history_credit.c - * @brief command to check the /history/incoming API from the bank. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_exchange_service.h" -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" - - -/** - * Item in the transaction history, as reconstructed from the - * command history. - */ -struct History -{ - - /** - * Wire details. - */ - struct TALER_BANK_CreditDetails details; - - /** - * Serial ID of the wire transfer. - */ - uint64_t row_id; - - /** - * URL to free. - */ - char *url; -}; - - -/** - * State for a "history" CMD. - */ -struct HistoryState -{ - /** - * Base URL of the account offering the "history" operation. - */ - char *account_url; - - /** - * Reference to command defining the - * first row number we want in the result. - */ - const char *start_row_reference; - - /** - * How many rows we want in the result, _at most_, - * and ascending/descending. - */ - long long num_results; - - /** - * Handle to a pending "history" operation. - */ - struct TALER_BANK_CreditHistoryHandle *hh; - - /** - * Authentication data for the operation. - */ - struct TALER_BANK_AuthenticationData auth; - - /** - * Expected number of results (= rows). - */ - uint64_t results_obtained; - - /** - * Set to GNUNET_YES if the callback detects something - * unexpected. - */ - int failed; - - /** - * Expected history. - */ - struct History *h; - - /** - * Length of @e h - */ - unsigned int total; - -}; - - -/** - * Offer internal data to other commands. - * - * @param cls closure. - * @param[out] ret set to the wanted data. - * @param trait name of the trait. - * @param index index number of the traits to be returned. - * - * @return #GNUNET_OK on success - */ -static int -history_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - (void) cls; - (void) ret; - (void) trait; - (void) index; - /* Must define this function because some callbacks - * look for certain traits on _all_ the commands. */ - return GNUNET_SYSERR; -} - - -/** - * Log which history we expected. Called when an error occurs. - * - * @param h what we expected. - * @param h_len number of entries in @a h. - * @param off position of the missmatch. - */ -static void -print_expected (struct History *h, - unsigned int h_len, - unsigned int off) -{ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Transaction history (credit) mismatch at position %u/%u\n", - off, - h_len); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected history:\n"); - for (unsigned int i = 0; icommands[is->ip].cls; - unsigned int total; - unsigned int pos; - struct History *h; - const struct TALER_TESTING_Command *add_incoming_cmd; - int inc; - unsigned int start; - unsigned int end; - - /* @var turns GNUNET_YES whenever either no 'start' value was - * given for the history query, or the given value is found - * in the list of all the CMDs. */// - int ok; - const uint64_t *row_id_start = NULL; - - if (NULL != hs->start_row_reference) - { - TALER_LOG_INFO ("`%s': start row given via reference `%s'\n", - TALER_TESTING_interpreter_get_current_label (is), - hs->start_row_reference); - add_incoming_cmd - = TALER_TESTING_interpreter_lookup_command (is, - hs->start_row_reference); - GNUNET_assert (NULL != add_incoming_cmd); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_uint64 (add_incoming_cmd, - 0, - &row_id_start)); - } - - GNUNET_assert (0 != hs->num_results); - if (0 == is->ip) - { - TALER_LOG_DEBUG ("Checking history at FIRST transaction (EMPTY)\n"); - *rh = NULL; - return 0; - } - - if (hs->num_results > 0) - { - inc = 1; /* _inc_rement */ - start = 0; - end = is->ip - 1; - } - else - { - inc = -1; - start = is->ip - 1; - end = 0; - } - - ok = GNUNET_NO; - if (NULL == row_id_start) - ok = GNUNET_YES; - h = NULL; - total = 0; - GNUNET_array_grow (h, - total, - 4); - pos = 0; - for (unsigned int off = start; off != end + inc; off += inc) - { - const struct TALER_TESTING_Command *cmd = &is->commands[off]; - const uint64_t *row_id; - const char *credit_account; - const char *debit_account; - const struct TALER_Amount *amount; - const struct TALER_ReservePublicKeyP *reserve_pub; - const char *exchange_credit_url; - - /* The following command allows us to skip over those CMDs - * that do not offer a "row_id" trait. Such skipped CMDs are - * not interesting for building a history. */// - if ( (GNUNET_OK != - TALER_TESTING_get_trait_bank_row (cmd, - &row_id)) || - (GNUNET_OK != - TALER_TESTING_get_trait_payto (cmd, - TALER_TESTING_PT_CREDIT, - &credit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_payto (cmd, - TALER_TESTING_PT_DEBIT, - &debit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_amount_obj (cmd, - 0, - &amount)) || - (GNUNET_OK != - TALER_TESTING_get_trait_reserve_pub (cmd, - 0, - &reserve_pub)) || - (GNUNET_OK != - TALER_TESTING_get_trait_url (cmd, - TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL, - &exchange_credit_url)) ) - continue; /* not an interesting event */ - /* Seek "/history/incoming" starting row. */ - if ( (NULL != row_id_start) && - (*row_id_start == *row_id) && - (GNUNET_NO == ok) ) - { - /* Until here, nothing counted. */ - ok = GNUNET_YES; - continue; - } - /* when 'start' was _not_ given, then ok == GNUNET_YES */ - if (GNUNET_NO == ok) - continue; /* skip until we find the marker */ - if (0 != strcasecmp (hs->account_url, - exchange_credit_url)) - continue; /* account missmatch */ - if (total >= GNUNET_MAX (hs->num_results, - -hs->num_results) ) - { - TALER_LOG_DEBUG ("Hit history limit\n"); - break; - } - TALER_LOG_INFO ("Found history: %s->%s for account %s\n", - debit_account, - credit_account, - hs->account_url); - /* found matching record, make sure we have room */ - if (pos == total) - GNUNET_array_grow (h, - total, - pos * 2); - h[pos].url = GNUNET_strdup (debit_account); - h[pos].details.debit_account_url = h[pos].url; - h[pos].details.amount = *amount; - h[pos].row_id = *row_id; - h[pos].details.reserve_pub = *reserve_pub; - h[pos].details.credit_account_url = exchange_credit_url; - pos++; - } - GNUNET_assert (GNUNET_YES == ok); - GNUNET_array_grow (h, - total, - pos); - if (0 == pos) - TALER_LOG_DEBUG ("Empty credit history computed\n"); - *rh = h; - return total; -} - - -/** - * Check that the "/history/incoming" response matches the - * CMD whose offset in the list of CMDs is @a off. - * - * @param is the interpreter state. - * @param h expected history (array) - * @param total length of @a h - * @param off the offset (of the CMD list) where the command - * to check is. - * @param details the expected transaction details. - * @return #GNUNET_OK if the transaction is what we expect. - */ -static int -check_result (struct TALER_TESTING_Interpreter *is, - struct History *h, - unsigned int total, - unsigned int off, - const struct TALER_BANK_CreditDetails *details) -{ - if (off >= total) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test says history has at most %u" - " results, but got result #%u to check\n", - total, - off); - print_expected (h, - total, - off); - return GNUNET_SYSERR; - } - if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub, - &details->reserve_pub)) || - (0 != TALER_amount_cmp (&h[off].details.amount, - &details->amount)) || - (0 != strcasecmp (h[off].details.debit_account_url, - details->debit_account_url)) ) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "expected debit_account_url: %s\n", - details->debit_account_url); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "actual debit_account_url: %s\n", - h[off].details.debit_account_url); - print_expected (h, - total, - off); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * This callback will (1) check that the HTTP response code - * is acceptable and (2) that the history is consistent. The - * consistency is checked by going through all the past CMDs, - * reconstructing then the expected history as of those, and - * finally check it against what the bank returned. - * - * @param cls closure. - * @param http_status HTTP response code, #MHD_HTTP_OK (200) - * for successful status request 0 if the bank's reply is - * bogus (fails to follow the protocol), - * #MHD_HTTP_NO_CONTENT if there are no more results; on - * success the last callback is always of this status - * (even if `abs(num_results)` were already returned). - * @param ec taler status code. - * @param row_id monotonically increasing counter corresponding to - * the transaction. - * @param details details about the wire transfer. - * @param json detailed response from the HTTPD, or NULL if - * reply was not in JSON. - * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration - */ -static int -history_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t row_id, - const struct TALER_BANK_CreditDetails *details, - const json_t *json) -{ - struct TALER_TESTING_Interpreter *is = cls; - struct HistoryState *hs = is->commands[is->ip].cls; - - (void) row_id; - if (NULL == details) - { - hs->hh = NULL; - if ( (hs->results_obtained != hs->total) || - (GNUNET_YES == hs->failed) || - (MHD_HTTP_NO_CONTENT != http_status) ) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected history of length %u, got %llu;" - " HTTP status code: %u/%d, failed: %d\n", - hs->total, - (unsigned long long) hs->results_obtained, - http_status, - (int) ec, - hs->failed); - print_expected (hs->h, - hs->total, - UINT_MAX); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; - } - TALER_TESTING_interpreter_next (is); - return GNUNET_OK; - } - if (MHD_HTTP_OK != http_status) - { - hs->hh = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unwanted response code from /history/incoming: %u\n", - http_status); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; - } - - /* check current element */ - if (GNUNET_OK != check_result (is, - hs->h, - hs->total, - hs->results_obtained, - details)) - { - char *acc; - - GNUNET_break (0); - acc = json_dumps (json, - JSON_COMPACT); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Result %u was `%s'\n", - (unsigned int) hs->results_obtained++, - acc); - if (NULL != acc) - free (acc); - hs->failed = GNUNET_YES; - return GNUNET_SYSERR; - } - hs->results_obtained++; - return GNUNET_OK; -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -history_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct HistoryState *hs = cls; - uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX; - const uint64_t *row_ptr; - - (void) cmd; - /* Get row_id from trait. */ - if (NULL != hs->start_row_reference) - { - const struct TALER_TESTING_Command *history_cmd; - - history_cmd = TALER_TESTING_interpreter_lookup_command - (is, hs->start_row_reference); - - if (NULL == history_cmd) - TALER_TESTING_FAIL (is); - - if (GNUNET_OK != - TALER_TESTING_get_trait_uint64 (history_cmd, - 0, - &row_ptr)) - TALER_TESTING_FAIL (is); - else - row_id = *row_ptr; - TALER_LOG_DEBUG ("row id (from trait) is %llu\n", - (unsigned long long) row_id); - } - hs->total = build_history (is, - &hs->h); - hs->hh = TALER_BANK_credit_history (is->ctx, - &hs->auth, - row_id, - hs->num_results, - &history_cb, - is); - GNUNET_assert (NULL != hs->hh); -} - - -/** - * Free the state from a "history" CMD, and possibly cancel - * a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -history_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct HistoryState *hs = cls; - - (void) cmd; - if (NULL != hs->hh) - { - TALER_LOG_WARNING ("/history/incoming did not complete\n"); - TALER_BANK_credit_history_cancel (hs->hh); - } - GNUNET_free (hs->account_url); - for (unsigned int off = 0; offtotal; off++) - GNUNET_free (hs->h[off].url); - GNUNET_free_non_null (hs->h); - GNUNET_free (hs); -} - - -/** - * Make a "history" CMD. - * - * @param label command label. - * @param auth authentication data to talk with the wire gateway - * @param start_row_reference reference to a command that can - * offer a row identifier, to be used as the starting row - * to accept in the result. - * @param num_results how many rows we want in the result. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_bank_credits (const char *label, - const struct - TALER_BANK_AuthenticationData *auth, - const char *start_row_reference, - long long num_results) -{ - struct HistoryState *hs; - - hs = GNUNET_new (struct HistoryState); - hs->account_url = GNUNET_strdup (auth->wire_gateway_url); - hs->start_row_reference = start_row_reference; - hs->num_results = num_results; - hs->auth = *auth; - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = hs, - .run = &history_run, - .cleanup = &history_cleanup, - .traits = &history_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_credit_history.c */ diff --git a/src/lib/testing_api_cmd_bank_history_debit.c b/src/lib/testing_api_cmd_bank_history_debit.c deleted file mode 100644 index e1d47b01c..000000000 --- a/src/lib/testing_api_cmd_bank_history_debit.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_bank_history_debit.c - * @brief command to check the /history/outgoing API from the bank. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_exchange_service.h" -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" - -/** - * Item in the transaction history, as reconstructed from the - * command history. - */ -struct History -{ - - /** - * Wire details. - */ - struct TALER_BANK_DebitDetails details; - - /** - * Serial ID of the wire transfer. - */ - uint64_t row_id; - - /** - * URL to free. - */ - char *c_url; - - /** - * URL to free. - */ - char *d_url; -}; - - -/** - * State for a "history" CMD. - */ -struct HistoryState -{ - /** - * Base URL of the account offering the "history" operation. - */ - const char *account_url; - - /** - * Reference to command defining the - * first row number we want in the result. - */ - const char *start_row_reference; - - /** - * How many rows we want in the result, _at most_, - * and ascending/descending. - */ - long long num_results; - - /** - * Login data to use to authenticate. - */ - struct TALER_BANK_AuthenticationData auth; - - /** - * Handle to a pending "history" operation. - */ - struct TALER_BANK_DebitHistoryHandle *hh; - - /** - * Expected number of results (= rows). - */ - uint64_t results_obtained; - - /** - * Set to #GNUNET_YES if the callback detects something - * unexpected. - */ - int failed; - - /** - * Expected history. - */ - struct History *h; - - /** - * Length of @e h - */ - unsigned int total; - -}; - - -/** - * Offer internal data to other commands. - * - * @param cls closure. - * @param[out] ret set to the wanted data. - * @param trait name of the trait. - * @param index index number of the traits to be returned. - * - * @return #GNUNET_OK on success - */ -static int -history_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - (void) cls; - (void) ret; - (void) trait; - (void) index; - /* Must define this function because some callbacks - * look for certain traits on _all_ the commands. */ - return GNUNET_SYSERR; -} - - -/** - * Log which history we expected. Called when an error occurs. - * - * @param h what we expected. - * @param h_len number of entries in @a h. - * @param off position of the missmatch. - */ -static void -print_expected (struct History *h, - unsigned int h_len, - unsigned int off) -{ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Transaction history (debit) mismatch at position %u/%u\n", - off, - h_len); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected history:\n"); - for (unsigned int i = 0; icommands[is->ip].cls; - unsigned int total; - unsigned int pos; - struct History *h; - const struct TALER_TESTING_Command *add_incoming_cmd; - int inc; - int start; - int end; - /* #GNUNET_YES whenever either no 'start' value was given for the history - * query, or the given value is found in the list of all the CMDs. */ - int ok; - const uint64_t *row_id_start = NULL; - - if (NULL != hs->start_row_reference) - { - TALER_LOG_INFO - ("`%s': start row given via reference `%s'\n", - TALER_TESTING_interpreter_get_current_label (is), - hs->start_row_reference); - add_incoming_cmd = TALER_TESTING_interpreter_lookup_command - (is, hs->start_row_reference); - GNUNET_assert (NULL != add_incoming_cmd); - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_uint64 (add_incoming_cmd, - 0, - &row_id_start)); - } - - GNUNET_assert (0 != hs->num_results); - if (0 == is->ip) - { - TALER_LOG_DEBUG ("Checking history at first CMD..\n"); - *rh = NULL; - return 0; - } - - /* AKA 'delta' */ - if (hs->num_results > 0) - { - inc = 1; /* _inc_rement: go forwards */ - start = 0; - end = is->ip; - } - else - { - inc = -1; /* decrement: we go backwards */ - start = is->ip - 1; - end = -1; /* range is exclusive, do look at 0! */ - } - - ok = GNUNET_NO; - if (NULL == row_id_start) - ok = GNUNET_YES; - h = NULL; - total = 0; - GNUNET_array_grow (h, - total, - 4); - pos = 0; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Checking commands %u to %u for debit history\n", - start, - end); - for (int off = start; off != end; off += inc) - { - const struct TALER_TESTING_Command *cmd = &is->commands[off]; - const uint64_t *row_id; - const char *debit_account; - const char *credit_account; - const struct TALER_Amount *amount; - const struct TALER_WireTransferIdentifierRawP *wtid; - const char *exchange_base_url; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Checking if command %s is relevant for debit history\n", - cmd->label); - if ( (GNUNET_OK != - TALER_TESTING_get_trait_bank_row (cmd, - &row_id)) || - (GNUNET_OK != - TALER_TESTING_get_trait_payto (cmd, - TALER_TESTING_PT_DEBIT, - &debit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_payto (cmd, - TALER_TESTING_PT_CREDIT, - &credit_account)) || - (GNUNET_OK != - TALER_TESTING_get_trait_amount_obj (cmd, - 0, - &amount)) || - (GNUNET_OK != - TALER_TESTING_get_trait_wtid (cmd, - 0, - &wtid)) || - (GNUNET_OK != - TALER_TESTING_get_trait_url (cmd, - TALER_TESTING_UT_EXCHANGE_BASE_URL, - &exchange_base_url)) ) - continue; /* not an event we care about */ - /* Seek "/history/outgoing" starting row. */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Command %s is relevant for debit history!\n", - cmd->label); - if ( (NULL != row_id_start) && - (*row_id_start == *row_id) && - (GNUNET_NO == ok) ) - { - /* Until here, nothing counted. */ - ok = GNUNET_YES; - continue; - } - /* when 'start' was _not_ given, then ok == GNUNET_YES */ - if (GNUNET_NO == ok) - continue; /* skip until we find the marker */ - if (total >= GNUNET_MAX (hs->num_results, - -hs->num_results) ) - { - TALER_LOG_DEBUG ("Hit history limit\n"); - break; - } - TALER_LOG_INFO ("Found history: %s->%s for account %s\n", - debit_account, - credit_account, - hs->account_url); - /* found matching record, make sure we have room */ - if (pos == total) - GNUNET_array_grow (h, - total, - pos * 2); - h[pos].c_url = GNUNET_strdup (credit_account); - h[pos].d_url = GNUNET_strdup (debit_account); - h[pos].details.credit_account_url = h[pos].c_url; - h[pos].details.debit_account_url = h[pos].d_url; - h[pos].details.amount = *amount; - h[pos].row_id = *row_id; - h[pos].details.wtid = *wtid; - h[pos].details.exchange_base_url = exchange_base_url; - pos++; - } - GNUNET_assert (GNUNET_YES == ok); - GNUNET_array_grow (h, - total, - pos); - if (0 == pos) - TALER_LOG_DEBUG ("Empty debit history computed\n"); - *rh = h; - return total; -} - - -/** - * Check that the "/history/outgoing" response matches the - * CMD whose offset in the list of CMDs is @a off. - * - * @param is the interpreter state. - * @param h expected history - * @param total number of entries in @a h - * @param off the offset (of the CMD list) where the command - * to check is. - * @param details the expected transaction details. - * @return #GNUNET_OK if the transaction is what we expect. - */ -static int -check_result (struct TALER_TESTING_Interpreter *is, - struct History *h, - uint64_t total, - unsigned int off, - const struct TALER_BANK_DebitDetails *details) -{ - if (off >= total) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Test says history has at most %u" - " results, but got result #%u to check\n", - (unsigned int) total, - off); - print_expected (h, - total, - off); - return GNUNET_SYSERR; - } - if ( (0 != GNUNET_memcmp (&h[off].details.wtid, - &details->wtid)) || - (0 != TALER_amount_cmp (&h[off].details.amount, - &details->amount)) || - (0 != strcasecmp (h[off].details.credit_account_url, - details->credit_account_url)) ) - { - GNUNET_break (0); - print_expected (h, - total, - off); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * This callback will (1) check that the HTTP response code - * is acceptable and (2) that the history is consistent. The - * consistency is checked by going through all the past CMDs, - * reconstructing then the expected history as of those, and - * finally check it against what the bank returned. - * - * @param cls closure. - * @param http_status HTTP response code, #MHD_HTTP_OK (200) - * for successful status request 0 if the bank's reply is - * bogus (fails to follow the protocol), - * #MHD_HTTP_NO_CONTENT if there are no more results; on - * success the last callback is always of this status - * (even if `abs(num_results)` were already returned). - * @param ec taler status code. - * @param row_id monotonically increasing counter corresponding to - * the transaction. - * @param details details about the wire transfer. - * @param json detailed response from the HTTPD, or NULL if - * reply was not in JSON. - * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration - */ -static int -history_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t row_id, - const struct TALER_BANK_DebitDetails *details, - const json_t *json) -{ - struct TALER_TESTING_Interpreter *is = cls; - struct HistoryState *hs = is->commands[is->ip].cls; - - (void) row_id; - if (NULL == details) - { - hs->hh = NULL; - if ( (hs->results_obtained != hs->total) || - (GNUNET_YES == hs->failed) || - (MHD_HTTP_NO_CONTENT != http_status) ) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected history of length %u, got %llu;" - " HTTP status code: %u/%d, failed: %d\n", - hs->total, - (unsigned long long) hs->results_obtained, - http_status, - (int) ec, - hs->failed); - print_expected (hs->h, - hs->total, - UINT_MAX); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; - } - TALER_TESTING_interpreter_next (is); - return GNUNET_OK; - } - if (MHD_HTTP_OK != http_status) - { - hs->hh = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unwanted response code from /history/outgoing: %u\n", - http_status); - TALER_TESTING_interpreter_fail (is); - return GNUNET_SYSERR; - } - - /* check current element */ - if (GNUNET_OK != check_result (is, - hs->h, - hs->total, - hs->results_obtained, - details)) - { - char *acc; - - GNUNET_break (0); - acc = json_dumps (json, - JSON_COMPACT); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Result %u was `%s'\n", - (unsigned int) hs->results_obtained++, - acc); - if (NULL != acc) - free (acc); - hs->failed = GNUNET_YES; - return GNUNET_SYSERR; - } - hs->results_obtained++; - return GNUNET_OK; -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -history_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct HistoryState *hs = cls; - uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX; - const uint64_t *row_ptr; - - (void) cmd; - /* Get row_id from trait. */ - if (NULL != hs->start_row_reference) - { - const struct TALER_TESTING_Command *history_cmd; - - history_cmd - = TALER_TESTING_interpreter_lookup_command (is, - hs->start_row_reference); - - if (NULL == history_cmd) - TALER_TESTING_FAIL (is); - if (GNUNET_OK != - TALER_TESTING_get_trait_uint64 (history_cmd, - 0, - &row_ptr)) - TALER_TESTING_FAIL (is); - else - row_id = *row_ptr; - TALER_LOG_DEBUG ("row id (from trait) is %llu\n", - (unsigned long long) row_id); - } - hs->total = build_history (is, &hs->h); - hs->hh = TALER_BANK_debit_history (is->ctx, - &hs->auth, - row_id, - hs->num_results, - &history_cb, - is); - GNUNET_assert (NULL != hs->hh); -} - - -/** - * Free the state from a "history" CMD, and possibly cancel - * a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -history_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct HistoryState *hs = cls; - - (void) cmd; - if (NULL != hs->hh) - { - TALER_LOG_WARNING ("/history/outgoing did not complete\n"); - TALER_BANK_debit_history_cancel (hs->hh); - } - for (unsigned int off = 0; offtotal; off++) - { - GNUNET_free (hs->h[off].c_url); - GNUNET_free (hs->h[off].d_url); - } - GNUNET_free_non_null (hs->h); - GNUNET_free (hs); -} - - -/** - * Make a "history" CMD. - * - * @param label command label. - * @param auth login data to use - * @param start_row_reference reference to a command that can - * offer a row identifier, to be used as the starting row - * to accept in the result. - * @param num_results how many rows we want in the result. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_bank_debits (const char *label, - const struct TALER_BANK_AuthenticationData *auth, - const char *start_row_reference, - long long num_results) -{ - struct HistoryState *hs; - - hs = GNUNET_new (struct HistoryState); - hs->account_url = auth->wire_gateway_url; - hs->start_row_reference = start_row_reference; - hs->num_results = num_results; - hs->auth = *auth; - - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = hs, - .run = &history_run, - .cleanup = &history_cleanup, - .traits = &history_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_bank_history_debit.c */ diff --git a/src/lib/testing_api_cmd_bank_transfer.c b/src/lib/testing_api_cmd_bank_transfer.c deleted file mode 100644 index 11cf5d446..000000000 --- a/src/lib/testing_api_cmd_bank_transfer.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_bank_transfer.c - * @brief implementation of a bank /transfer command - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "backoff.h" -#include "taler_json_lib.h" -#include -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "transfer" CMD. - */ -struct TransferState -{ - - /** - * Wire transfer amount. - */ - struct TALER_Amount amount; - - /** - * Base URL of the debit account. - */ - const char *account_debit_url; - - /** - * Money receiver payto URL. - */ - char *payto_debit_account; - - /** - * Money receiver account URL. - */ - const char *payto_credit_account; - - /** - * Username to use for authentication. - */ - struct TALER_BANK_AuthenticationData auth; - - /** - * Base URL of the exchange. - */ - const char *exchange_base_url; - - /** - * Wire transfer identifier to use. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /** - * Handle to the pending request at the fakebank. - */ - struct TALER_BANK_WireExecuteHandle *weh; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Set to the wire transfer's unique ID. - */ - uint64_t serial_id; - - /** - * Timestamp of the transaction (as returned from the bank). - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * Configuration filename. Used to get the tip reserve key - * filename (used to obtain a public key to write in the - * transfer subject). - */ - const char *config_filename; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Was this command modified via - * #TALER_TESTING_cmd_admin_add_incoming_with_retry to - * enable retries? - */ - int do_retry; -}; - - -/** - * Run the "transfer" CMD. - * - * @param cls closure. - * @param cmd CMD being run. - * @param is interpreter state. - */ -static void -transfer_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #transfer_run. - * - * @param cls a `struct TransferState` - */ -static void -do_retry (void *cls) -{ - struct TransferState *fts = cls; - - fts->retry_task = NULL; - transfer_run (fts, - NULL, - fts->is); -} - - -/** - * This callback will process the fakebank response to the wire - * transfer. It just checks whether the HTTP response code is - * acceptable. - * - * @param cls closure with the interpreter state - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for - * successful status request; 0 if the exchange's reply is - * bogus (fails to follow the protocol) - * @param ec taler-specific error code, #TALER_EC_NONE on success - * @param serial_id unique ID of the wire transfer - * @param timestamp time stamp of the transaction made. - */ -static void -confirmation_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - struct GNUNET_TIME_Absolute timestamp) -{ - struct TransferState *fts = cls; - struct TALER_TESTING_Interpreter *is = fts->is; - - fts->weh = NULL; - if (MHD_HTTP_OK != http_status) - { - if (GNUNET_YES == fts->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying transfer failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - fts->backoff = GNUNET_TIME_UNIT_ZERO; - else - fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); - fts->retry_task = GNUNET_SCHEDULER_add_delayed - (fts->backoff, - &do_retry, - fts); - return; - } - } - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Fakebank returned HTTP status %u/%d\n", - http_status, - (int) ec); - TALER_TESTING_interpreter_fail (is); - return; - } - - fts->serial_id = serial_id; - fts->timestamp = timestamp; - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the "transfer" CMD. - * - * @param cls closure. - * @param cmd CMD being run. - * @param is interpreter state. - */ -static void -transfer_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct TransferState *fts = cls; - void *buf; - size_t buf_size; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Transfer of %s from %s to %s\n", - TALER_amount2s (&fts->amount), - fts->account_debit_url, - fts->payto_credit_account); - TALER_BANK_prepare_wire_transfer (fts->payto_credit_account, - &fts->amount, - fts->exchange_base_url, - &fts->wtid, - &buf, - &buf_size); - fts->is = is; - fts->weh - = TALER_BANK_execute_wire_transfer - (TALER_TESTING_interpreter_get_context (is), - &fts->auth, - buf, - buf_size, - &confirmation_cb, - fts); - GNUNET_free (buf); - if (NULL == fts->weh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } -} - - -/** - * Free the state of a "fakebank transfer" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure - * @param cmd current CMD being cleaned up. - */ -static void -transfer_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct TransferState *fts = cls; - - if (NULL != fts->weh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); - TALER_BANK_execute_wire_transfer_cancel (fts->weh); - fts->weh = NULL; - } - if (NULL != fts->retry_task) - { - GNUNET_SCHEDULER_cancel (fts->retry_task); - fts->retry_task = NULL; - } - GNUNET_free (fts->payto_debit_account); - GNUNET_free (fts); -} - - -/** - * Offer internal data from a "fakebank transfer" CMD to other - * commands. - * - * @param cls closure. - * @param[out] ret result - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -transfer_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct TransferState *fts = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, - fts->exchange_base_url), - TALER_TESTING_make_trait_bank_row (&fts->serial_id), - TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT, - fts->payto_credit_account), - TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT, - fts->payto_debit_account), - TALER_TESTING_make_trait_amount_obj (0, &fts->amount), - TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), - TALER_TESTING_make_trait_wtid (0, - &fts->wtid), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Create transfer command. - * - * @param label command label. - * @param amount amount to transfer. - * @param auth authentication data to use - * @param payto_debit_account which account sends money. - * @param payto_credit_account which account receives money. - * @param wtid wire transfer identifier to use - * @param exchange_base_url exchange URL to use - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_transfer (const char *label, - const char *amount, - const struct TALER_BANK_AuthenticationData *auth, - const char *payto_debit_account, - const char *payto_credit_account, - const struct TALER_WireTransferIdentifierRawP *wtid, - const char *exchange_base_url) -{ - struct TransferState *fts; - - fts = GNUNET_new (struct TransferState); - fts->account_debit_url = auth->wire_gateway_url; - fts->exchange_base_url = exchange_base_url; - fts->payto_debit_account = GNUNET_strdup (payto_debit_account); - fts->payto_credit_account = payto_credit_account; - fts->auth = *auth; - fts->wtid = *wtid; - if (GNUNET_OK != - TALER_string_to_amount (amount, - &fts->amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %s\n", - amount, - label); - GNUNET_assert (0); - } - - { - struct TALER_TESTING_Command cmd = { - .cls = fts, - .label = label, - .run = &transfer_run, - .cleanup = &transfer_cleanup, - .traits = &transfer_traits - }; - - return cmd; - } -} - - -/** - * Modify a transfer command to enable retries when the reserve is not yet - * full or we get other transient errors from the bank. - * - * @param cmd a fakebank transfer command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_transfer_retry (struct TALER_TESTING_Command cmd) -{ - struct TransferState *fts; - - GNUNET_assert (&transfer_run == cmd.run); - fts = cmd.cls; - fts->do_retry = GNUNET_YES; - return cmd; -} - - -/* end of testing_api_cmd_transfer.c */ diff --git a/src/lib/testing_api_cmd_batch.c b/src/lib/testing_api_cmd_batch.c deleted file mode 100644 index 6d3c86ec0..000000000 --- a/src/lib/testing_api_cmd_batch.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_batch.c - * @brief Implement batch-execution of CMDs. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "batch" CMD. - */ -struct BatchState -{ - /** - * CMDs batch. - */ - struct TALER_TESTING_Command *batch; - - /** - * Internal command pointer. - */ - unsigned int batch_ip; -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command being executed. - * @param is the interpreter state. - */ -static void -batch_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct BatchState *bs = cls; - - if (NULL != bs->batch[bs->batch_ip].label) - TALER_LOG_INFO ("Running batched command: %s\n", - bs->batch[bs->batch_ip].label); - - /* hit end command, leap to next top-level command. */ - if (NULL == bs->batch[bs->batch_ip].label) - { - TALER_LOG_INFO ("Exiting from batch: %s\n", - cmd->label); - TALER_TESTING_interpreter_next (is); - return; - } - - bs->batch[bs->batch_ip].run (bs->batch[bs->batch_ip].cls, - &bs->batch[bs->batch_ip], - is); -} - - -/** - * Cleanup the state from a "reserve status" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -batch_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct BatchState *bs = cls; - - for (unsigned int i = 0; - NULL != bs->batch[i].label; - i++) - bs->batch[i].cleanup (bs->batch[i].cls, - &bs->batch[i]); - GNUNET_free_non_null (bs->batch); - GNUNET_free (bs); -} - - -/** - * Offer internal data from a "batch" CMD, to other commands. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -batch_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ -#define CURRENT_CMD_INDEX 0 -#define BATCH_INDEX 1 - - struct BatchState *bs = cls; - - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_cmd - (CURRENT_CMD_INDEX, &bs->batch[bs->batch_ip]), - TALER_TESTING_make_trait_cmd - (BATCH_INDEX, bs->batch), - TALER_TESTING_trait_end () - }; - - /* Always return current command. */ - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Create a "batch" command. Such command takes a - * end_CMD-terminated array of CMDs and executed them. - * Once it hits the end CMD, it passes the control - * to the next top-level CMD, regardless of it being - * another batch or ordinary CMD. - * - * @param label the command label. - * @param batch array of CMDs to execute. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_batch (const char *label, - struct TALER_TESTING_Command *batch) -{ - struct BatchState *bs; - unsigned int i; - - bs = GNUNET_new (struct BatchState); - - /* Get number of commands. */ - for (i = 0; NULL != batch[i].label; i++) - /* noop */ - ; - - bs->batch = GNUNET_new_array (i + 1, - struct TALER_TESTING_Command); - memcpy (bs->batch, - batch, - sizeof (struct TALER_TESTING_Command) * i); - { - struct TALER_TESTING_Command cmd = { - .cls = bs, - .label = label, - .run = &batch_run, - .cleanup = &batch_cleanup, - .traits = &batch_traits - }; - - return cmd; - } -} - - -/** - * Advance internal pointer to next command. - * - * @param is interpreter state. - */ -void -TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is) -{ - struct BatchState *bs = is->commands[is->ip].cls; - - if (NULL == bs->batch[bs->batch_ip].label) - { - is->ip++; - return; - } - - bs->batch_ip++; -} - - -/** - * Test if this command is a batch command. - * - * @return false if not, true if it is a batch command - */ -int -TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd) -{ - return cmd->run == &batch_run; -} - - -/** - * Obtain what command the batch is at. - * - * @return cmd current batch command - */ -struct TALER_TESTING_Command * -TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd) -{ - struct BatchState *bs = cmd->cls; - - return &bs->batch[bs->batch_ip]; -} diff --git a/src/lib/testing_api_cmd_check_keys.c b/src/lib/testing_api_cmd_check_keys.c deleted file mode 100644 index 3488af7ad..000000000 --- a/src/lib/testing_api_cmd_check_keys.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - This file is part of TALER - (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_check_keys.c - * @brief Implementation of "check keys" test command. XXX-NOTE: - * the number of 'expected keys' is NOT the number of the - * downloaded keys, but rather the number of keys that the - * libtalerutil library keeps locally. As for the current - * design, keys are _never_ discarded by the library, - * therefore their (expected) number is monotonically - * ascending. - * - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "check keys" CMD. - */ -struct CheckKeysState -{ - /** - * This number will instruct the CMD interpreter to - * make sure that /keys was downloaded `generation` times - * _before_ running the very CMD logic. - */ - unsigned int generation; - - /** - * How many denomination keys the exchange is - * supposed to have. - */ - unsigned int num_denom_keys; - - /** - * If this value is GNUNET_YES, then the "cherry - * picking" facility is turned off; whole /keys is - * downloaded. - */ - unsigned int pull_all_keys; - - /** - * If GNUNET_YES, then the user must specify the - * last_denom_issue_date manually. This way, it is possible - * to force whatever X value here (including 0): /keys?last_denom_issue=X. - */ - unsigned int set_last_denom; - - /** - * Value X to set as the URL parameter: - * "/keys?last_denom_issue=X" is used only when `set_last_denom' - * equals GNUNET_YES. - */ - struct GNUNET_TIME_Absolute last_denom_date; - - /** - * If GNUNET_YES, then we'll provide the "/keys" request. - * with the "now" argument. - */ - int with_now; - - /** - * Fake now as passed by the user. - */ - struct GNUNET_TIME_Absolute now; - -}; - - -/** - * Run the "check keys" command. - * - * @param cls closure. - * @param cmd the command currently being executed. - * @param is the interpreter state. - */ -static void -check_keys_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct CheckKeysState *cks = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "cmd `%s' (ip: %u), key generation: %d\n", - cmd->label, - is->ip, - is->key_generation); - - if (is->key_generation < cks->generation) - { - is->working = GNUNET_NO; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Triggering GET /keys, cmd `%s'\n", - cmd->label); - - if (GNUNET_YES == cks->set_last_denom) - { - TALER_LOG_DEBUG ("Forcing last_denom_date URL argument\n"); - TALER_EXCHANGE_set_last_denom (is->exchange, - cks->last_denom_date); - } - - if (GNUNET_YES == cks->with_now) - TALER_EXCHANGE_set_now (is->exchange, - cks->now); - /* Redownload /keys. */ - GNUNET_break - (0 == TALER_EXCHANGE_check_keys_current - (is->exchange, - GNUNET_YES, - cks->pull_all_keys).abs_value_us); - return; - } - -#if 0 - /** - * Not sure this check makes sense: GET /keys is performed on - * a "maybe" basis, so it can get quite hard to track /keys - * request. Rather, this CMD should just check if /keys was - * requested AT LEAST n times before going ahead with checks. - */// - if (is->key_generation > cks->generation) - { - /* We got /keys too often, strange. Fatal. May theoretically - happen if somehow we were really unlucky and /keys expired - "naturally", but obviously with a sane configuration this - should also not be. */ - GNUNET_break (0); - TALER_LOG_ERROR ("Acutal- vs expected key" - " generation: %u vs %u\n", - is->key_generation, - cks->generation); - TALER_TESTING_interpreter_fail (is); - return; - } -#endif - /* "/keys" was updated, let's check they were OK! */ - if (cks->num_denom_keys != is->keys->num_denom_keys) - { - /* Did not get the expected number of denomination keys! */ - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Got %u keys in step %s, expected %u\n", - is->keys->num_denom_keys, - cmd->label, - cks->num_denom_keys); - TALER_TESTING_interpreter_fail (is); - return; - } - - /* Let's unset the fake now before moving on. */ - TALER_EXCHANGE_unset_now (is->exchange); - TALER_TESTING_interpreter_next (is); -} - - -/** - * Cleanup the state. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -check_keys_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct CheckKeysState *cks = cls; - - GNUNET_free (cks); -} - - -/** - * Make a "check keys" command. This type of command - * checks whether the number of denomination keys from - * @a exchange matches @a num_denom_keys. Additionally, - * it lets the user set a last denom issue date to be - * used in the request for /keys. - * - * @param label command label - * @param generation when this command is run, exactly @a - * generation /keys downloads took place. If the number - * of downloads is less than @a generation, the logic will - * first make sure that @a generation downloads are done, - * and _then_ execute the rest of the command. - * @param num_denom_keys expected number of denomination keys. - * @param last_denom_date date to be set in the "last_denom_issue" - * URL parameter of /keys. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_with_last_denom (const char *label, - unsigned int generation, - unsigned int num_denom_keys, - struct GNUNET_TIME_Absolute - last_denom_date) -{ - struct CheckKeysState *cks; - - cks = GNUNET_new (struct CheckKeysState); - cks->generation = generation; - cks->num_denom_keys = num_denom_keys; - cks->set_last_denom = GNUNET_YES; - cks->last_denom_date = last_denom_date; - { - struct TALER_TESTING_Command cmd = { - .cls = cks, - .label = label, - .run = &check_keys_run, - .cleanup = &check_keys_cleanup - }; - - return cmd; - } -} - - -/** - * Make a "check keys" command. This type of command - * checks whether the number of denomination keys from - * @a exchange matches @a num_denom_keys. - * - * @param label command label - * @param generation when this command is run, exactly @a - * generation /keys downloads took place. If the number - * of downloads is less than @a generation, the logic will - * first make sure that @a generation downloads are done, - * and _then_ execute the rest of the command. - * @param num_denom_keys expected number of denomination keys. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys (const char *label, - unsigned int generation, - unsigned int num_denom_keys) -{ - struct CheckKeysState *cks; - - cks = GNUNET_new (struct CheckKeysState); - cks->generation = generation; - cks->num_denom_keys = num_denom_keys; - { - struct TALER_TESTING_Command cmd = { - .cls = cks, - .label = label, - .run = &check_keys_run, - .cleanup = &check_keys_cleanup - }; - - return cmd; - } -} - - -/** - * Make a "check keys" command. This type of command - * checks whether the number of denomination keys from - * @a exchange matches @a num_denom_keys. - * - * @param label command label - * @param generation when this command is run, exactly @a - * generation /keys downloads took place. If the number - * of downloads is less than @a generation, the logic will - * first make sure that @a generation downloads are done, - * and _then_ execute the rest of the command. - * @param num_denom_keys expected number of denomination keys. - * @param now timestamp to use when fetching keys - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_with_now (const char *label, - unsigned int generation, - unsigned int num_denom_keys, - struct GNUNET_TIME_Absolute now) -{ - struct CheckKeysState *cks; - - cks = GNUNET_new (struct CheckKeysState); - cks->generation = generation; - cks->num_denom_keys = num_denom_keys; - cks->now = now; - cks->with_now = GNUNET_YES; - - /* Force to NOT cherry pick, otherwise they conflict. */ - cks->pull_all_keys = GNUNET_YES; - { - struct TALER_TESTING_Command cmd = { - .cls = cks, - .label = label, - .run = &check_keys_run, - .cleanup = &check_keys_cleanup - }; - - return cmd; - } -} - - -/** - * Make a "check keys" command that forcedly does NOT cherry pick; - * just redownload the whole /keys. Then checks whether the number - * of denomination keys from @a exchange matches @a num_denom_keys. - * - * @param label command label - * @param generation when this command is run, exactly @a - * generation /keys downloads took place. If the number - * of downloads is less than @a generation, the logic will - * first make sure that @a generation downloads are done, - * and _then_ execute the rest of the command. - * @param num_denom_keys expected number of denomination keys. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label, - unsigned int generation, - unsigned int num_denom_keys) -{ - struct CheckKeysState *cks; - - cks = GNUNET_new (struct CheckKeysState); - cks->generation = generation; - cks->num_denom_keys = num_denom_keys; - cks->pull_all_keys = GNUNET_YES; - { - struct TALER_TESTING_Command cmd = { - .cls = cks, - .label = label, - .run = &check_keys_run, - .cleanup = &check_keys_cleanup - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_check_keys.c */ diff --git a/src/lib/testing_api_cmd_deposit.c b/src/lib/testing_api_cmd_deposit.c deleted file mode 100644 index f25fefc96..000000000 --- a/src/lib/testing_api_cmd_deposit.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_deposit.c - * @brief command for testing /deposit. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" -#include "taler_signatures.h" -#include "backoff.h" - - -/** - * State for a "deposit" CMD. - */ -struct DepositState -{ - - /** - * Amount to deposit. - */ - struct TALER_Amount amount; - - /** - * Reference to any command that is able to provide a coin. - */ - const char *coin_reference; - - /** - * If @e coin_reference refers to an operation that generated - * an array of coins, this value determines which coin to pick. - */ - unsigned int coin_index; - - /** - * Wire details of who is depositing -- this would be merchant - * wire details in a normal scenario. - */ - json_t *wire_details; - - /** - * JSON string describing what a proposal is about. - */ - json_t *contract_terms; - - /** - * Refund deadline. Zero for no refunds. - */ - struct GNUNET_TIME_Absolute refund_deadline; - - /** - * Set (by the interpreter) to a fresh private key. This - * key will be used to sign the deposit request. - */ - struct TALER_MerchantPrivateKeyP merchant_priv; - - /** - * Deposit handle while operation is running. - */ - struct TALER_EXCHANGE_DepositHandle *dh; - - /** - * Timestamp of the /deposit operation. - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Should we retry on (transient) failures? - */ - int do_retry; - - /** - * Set to #GNUNET_YES if the /deposit succeeded - * and we now can provide the resulting traits. - */ - int traits_ready; - - /** - * Signing key used by the exchange to sign the - * deposit confirmation. - */ - struct TALER_ExchangePublicKeyP exchange_pub; - - /** - * Signature from the exchange on the - * deposit confirmation. - */ - struct TALER_ExchangeSignatureP exchange_sig; -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -deposit_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #deposit_run. - * - * @param cls a `struct DepositState` - */ -static void -do_retry (void *cls) -{ - struct DepositState *ds = cls; - - ds->retry_task = NULL; - deposit_run (ds, - NULL, - ds->is); -} - - -/** - * Callback to analyze the /deposit response, just used to - * check if the response code is acceptable. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param exchange_sig signature provided by the exchange - * (NULL on errors) - * @param exchange_pub public key of the exchange, - * used for signing the response. - * @param obj raw response from the exchange. - */ -static void -deposit_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const struct TALER_ExchangeSignatureP *exchange_sig, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const json_t *obj) -{ - struct DepositState *ds = cls; - - ds->dh = NULL; - if (ds->expected_response_code != http_status) - { - if (GNUNET_YES == ds->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying deposit failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - ds->backoff = GNUNET_TIME_UNIT_ZERO; - else - ds->backoff = EXCHANGE_LIB_BACKOFF (ds->backoff); - ds->retry_task - = GNUNET_SCHEDULER_add_delayed (ds->backoff, - &do_retry, - ds); - return; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - http_status, - ds->is->commands[ds->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (obj, stderr, 0); - TALER_TESTING_interpreter_fail (ds->is); - return; - } - if (MHD_HTTP_OK == http_status) - { - ds->traits_ready = GNUNET_YES; - ds->exchange_pub = *exchange_pub; - ds->exchange_sig = *exchange_sig; - } - TALER_TESTING_interpreter_next (ds->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -deposit_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct DepositState *ds = cls; - const struct TALER_TESTING_Command *coin_cmd; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - struct TALER_CoinSpendPublicKeyP coin_pub; - const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; - const struct TALER_DenominationSignature *denom_pub_sig; - struct TALER_CoinSpendSignatureP coin_sig; - struct GNUNET_TIME_Absolute wire_deadline; - struct GNUNET_CRYPTO_EddsaPrivateKey *merchant_priv; - struct TALER_MerchantPublicKeyP merchant_pub; - struct GNUNET_HashCode h_contract_terms; - - ds->is = is; - GNUNET_assert (ds->coin_reference); - coin_cmd = TALER_TESTING_interpreter_lookup_command - (is, - ds->coin_reference); - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if ( (GNUNET_OK != - TALER_TESTING_get_trait_coin_priv (coin_cmd, - ds->coin_index, - &coin_priv)) || - (GNUNET_OK != - TALER_TESTING_get_trait_denom_pub (coin_cmd, - ds->coin_index, - &denom_pub)) || - (GNUNET_OK != - TALER_TESTING_get_trait_denom_sig (coin_cmd, - ds->coin_index, - &denom_pub_sig)) || - (GNUNET_OK != - TALER_JSON_hash (ds->contract_terms, - &h_contract_terms)) ) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - - merchant_priv = GNUNET_CRYPTO_eddsa_key_create (); - ds->merchant_priv.eddsa_priv = *merchant_priv; - GNUNET_free (merchant_priv); - - if (0 != ds->refund_deadline.abs_value_us) - { - struct GNUNET_TIME_Relative refund_deadline; - - refund_deadline = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline); - wire_deadline = GNUNET_TIME_relative_to_absolute - (GNUNET_TIME_relative_multiply (refund_deadline, 2)); - } - else - { - ds->refund_deadline = ds->timestamp; - wire_deadline = GNUNET_TIME_relative_to_absolute - (GNUNET_TIME_UNIT_ZERO); - } - GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv, - &merchant_pub.eddsa_pub); - - (void) GNUNET_TIME_round_abs (&wire_deadline); - - { - struct TALER_DepositRequestPS dr; - - memset (&dr, 0, sizeof (dr)); - dr.purpose.size = htonl - (sizeof (struct TALER_DepositRequestPS)); - dr.purpose.purpose = htonl - (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); - dr.h_contract_terms = h_contract_terms; - GNUNET_assert (GNUNET_OK == - TALER_JSON_merchant_wire_signature_hash (ds->wire_details, - &dr.h_wire)); - dr.timestamp = GNUNET_TIME_absolute_hton (ds->timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton - (ds->refund_deadline); - TALER_amount_hton (&dr.amount_with_fee, - &ds->amount); - TALER_amount_hton (&dr.deposit_fee, - &denom_pub->fee_deposit); - dr.merchant = merchant_pub; - dr.coin_pub = coin_pub; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, - &dr.purpose, - &coin_sig.eddsa_signature)); - } - ds->dh = TALER_EXCHANGE_deposit (is->exchange, - &ds->amount, - wire_deadline, - ds->wire_details, - &h_contract_terms, - &coin_pub, - denom_pub_sig, - &denom_pub->key, - ds->timestamp, - &merchant_pub, - ds->refund_deadline, - &coin_sig, - &deposit_cb, - ds); - - if (NULL == ds->dh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } -} - - -/** - * Free the state of a "deposit" CMD, and possibly cancel a - * pending operation thereof. - * - * @param cls closure, must be a `struct DepositState`. - * @param cmd the command which is being cleaned up. - */ -static void -deposit_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct DepositState *ds = cls; - - if (NULL != ds->dh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ds->is->ip, - cmd->label); - TALER_EXCHANGE_deposit_cancel (ds->dh); - ds->dh = NULL; - } - if (NULL != ds->retry_task) - { - GNUNET_SCHEDULER_cancel (ds->retry_task); - ds->retry_task = NULL; - } - json_decref (ds->wire_details); - json_decref (ds->contract_terms); - GNUNET_free (ds); -} - - -/** - * Offer internal data from a "deposit" CMD, to other commands. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * - * @return #GNUNET_OK on success. - */ -static int -deposit_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct DepositState *ds = cls; - const struct TALER_TESTING_Command *coin_cmd; - /* Will point to coin cmd internals. */ - const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv; - - coin_cmd - = TALER_TESTING_interpreter_lookup_command (ds->is, - ds->coin_reference); - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ds->is); - return GNUNET_NO; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_coin_priv (coin_cmd, - ds->coin_index, - &coin_spent_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ds->is); - return GNUNET_NO; - } - { - struct TALER_TESTING_Trait traits[] = { - /* First two traits are only available if - ds->traits is #GNUNET_YES */ - TALER_TESTING_make_trait_exchange_pub (0, - &ds->exchange_pub), - TALER_TESTING_make_trait_exchange_sig (0, - &ds->exchange_sig), - /* These traits are always available */ - TALER_TESTING_make_trait_coin_priv (0, - coin_spent_priv), - TALER_TESTING_make_trait_wire_details (0, - ds->wire_details), - TALER_TESTING_make_trait_contract_terms (0, - ds->contract_terms), - TALER_TESTING_make_trait_merchant_priv (0, - &ds->merchant_priv), - TALER_TESTING_make_trait_amount_obj (0, - &ds->amount), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait ((ds->traits_ready) - ? traits - : &traits[2], - ret, - trait, - index); - } -} - - -/** - * Create a "deposit" command. - * - * @param label command label. - * @param coin_reference reference to any operation that can - * provide a coin. - * @param coin_index if @a withdraw_reference offers an array of - * coins, this parameter selects which one in that array. - * This value is currently ignored, as only one-coin - * withdrawals are implemented. - * @param target_account_payto target account for the "deposit" - * request. - * @param contract_terms contract terms to be signed over by the - * coin. - * @param refund_deadline refund deadline, zero means 'no refunds'. - * Note, if time were absolute, then it would have come - * one day and disrupt tests meaning. - * @param amount how much is going to be deposited. - * @param expected_response_code expected HTTP response code. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_deposit (const char *label, - const char *coin_reference, - unsigned int coin_index, - const char *target_account_payto, - const char *contract_terms, - struct GNUNET_TIME_Relative refund_deadline, - const char *amount, - unsigned int expected_response_code) -{ - struct DepositState *ds; - json_t *wire_details; - - wire_details = TALER_TESTING_make_wire_details (target_account_payto); - ds = GNUNET_new (struct DepositState); - ds->coin_reference = coin_reference; - ds->coin_index = coin_index; - ds->wire_details = wire_details; - ds->contract_terms = json_loads (contract_terms, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == ds->contract_terms) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse contract terms `%s' for CMD `%s'\n", - contract_terms, - label); - GNUNET_assert (0); - } - ds->timestamp = GNUNET_TIME_absolute_get (); - (void) GNUNET_TIME_round_abs (&ds->timestamp); - - json_object_set_new (ds->contract_terms, - "timestamp", - GNUNET_JSON_from_time_abs (ds->timestamp)); - if (0 != refund_deadline.rel_value_us) - { - ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline); - (void) GNUNET_TIME_round_abs (&ds->refund_deadline); - json_object_set_new (ds->contract_terms, - "refund_deadline", - GNUNET_JSON_from_time_abs (ds->refund_deadline)); - } - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (amount, - &ds->amount)); - ds->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = ds, - .label = label, - .run = &deposit_run, - .cleanup = &deposit_cleanup, - .traits = &deposit_traits - }; - - return cmd; - } -} - - -/** - * Modify a deposit command to enable retries when we get transient - * errors from the exchange. - * - * @param cmd a deposit command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd) -{ - struct DepositState *ds; - - GNUNET_assert (&deposit_run == cmd.run); - ds = cmd.cls; - ds->do_retry = GNUNET_YES; - return cmd; -} - - -/* end of testing_api_cmd_deposit.c */ diff --git a/src/lib/testing_api_cmd_exec_aggregator.c b/src/lib/testing_api_cmd_exec_aggregator.c deleted file mode 100644 index 425b3f23a..000000000 --- a/src/lib/testing_api_cmd_exec_aggregator.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ -/** - * @file lib/testing_api_cmd_exec_aggregator.c - * @brief run the taler-exchange-aggregator command - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "aggregator" CMD. - */ -struct AggregatorState -{ - - /** - * Aggregator process. - */ - struct GNUNET_OS_Process *aggregator_proc; - - /** - * Configuration file used by the aggregator. - */ - const char *config_filename; -}; - - -/** - * Run the command. Use the `taler-exchange-aggregator' program. - * - * @param cls closure. - * @param cmd command being run. - * @param is interpreter state. - */ -static void -aggregator_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct AggregatorState *as = cls; - - as->aggregator_proc - = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-aggregator", - "taler-exchange-aggregator", - "-c", as->config_filename, - "-t", /* exit when done */ - NULL); - if (NULL == as->aggregator_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Free the state of a "aggregator" CMD, and possibly kill its - * process if it did not terminate correctly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -aggregator_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct AggregatorState *as = cls; - - if (NULL != as->aggregator_proc) - { - GNUNET_break (0 == - GNUNET_OS_process_kill (as->aggregator_proc, - SIGKILL)); - GNUNET_OS_process_wait (as->aggregator_proc); - GNUNET_OS_process_destroy (as->aggregator_proc); - as->aggregator_proc = NULL; - } - GNUNET_free (as); -} - - -/** - * Offer "aggregator" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success - */ -static int -aggregator_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct AggregatorState *as = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_process (0, &as->aggregator_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make a "aggregator" CMD. - * - * @param label command label. - * @param config_filename configuration file for the - * aggregator to use. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_aggregator (const char *label, - const char *config_filename) -{ - struct AggregatorState *as; - - as = GNUNET_new (struct AggregatorState); - as->config_filename = config_filename; - { - struct TALER_TESTING_Command cmd = { - .cls = as, - .label = label, - .run = &aggregator_run, - .cleanup = &aggregator_cleanup, - .traits = &aggregator_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_exec_aggregator.c */ diff --git a/src/lib/testing_api_cmd_exec_auditor-sign.c b/src/lib/testing_api_cmd_exec_auditor-sign.c deleted file mode 100644 index deda26686..000000000 --- a/src/lib/testing_api_cmd_exec_auditor-sign.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ - -/** - * @file lib/testing_api_cmd_exec_auditor-sign.c - * @brief run the taler-exchange-aggregator command - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "auditor sign" CMD. - */ -struct AuditorSignState -{ - - /** - * Handle to the process making the signature. - */ - struct GNUNET_OS_Process *auditor_sign_proc; - - /** - * Configuration file used by the command. - */ - const char *config_filename; - - /** - * File name of signed blob. - */ - char *signed_keys_out; -}; - - -/** - * Run the command; calls the `taler-auditor-sign' program. - * - * @param cls closure. - * @param cmd the command. - * @param is interpreter state. - */ -static void -auditor_sign_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct AuditorSignState *ass = cls; - - struct GNUNET_CONFIGURATION_Handle *cfg; - char *test_home_dir; - char *exchange_master_pub; - struct GNUNET_TIME_Absolute now; - - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != GNUNET_CONFIGURATION_load - (cfg, ass->config_filename)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "paths", - "TALER_TEST_HOME", - &test_home_dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "paths", - "TALER_TEST_HOME"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - now = GNUNET_TIME_absolute_get (); - GNUNET_asprintf - (&ass->signed_keys_out, - "%s/.local/share/taler/auditors/auditor-%llu.out", - test_home_dir, - (unsigned long long) now.abs_value_us); - GNUNET_free (test_home_dir); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "MASTER_PUBLIC_KEY", - &exchange_master_pub)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "MASTER_PUBLIC_KEY"); - GNUNET_CONFIGURATION_destroy (cfg); - - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_CONFIGURATION_destroy (cfg); - - ass->auditor_sign_proc = GNUNET_OS_start_process - (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-sign", - "taler-auditor-sign", - "-c", ass->config_filename, - "-u", "http://auditor/", - "-m", exchange_master_pub, - "-r", "auditor.in", - "-o", ass->signed_keys_out, - NULL); - GNUNET_free (exchange_master_pub); - if (NULL == ass->auditor_sign_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Free the state of a "auditor sign" CMD, and possibly - * kill its process if it did not terminate correctly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -auditor_sign_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct AuditorSignState *ass = cls; - - if (NULL != ass->auditor_sign_proc) - { - GNUNET_break (0 == GNUNET_OS_process_kill - (ass->auditor_sign_proc, SIGKILL)); - GNUNET_OS_process_wait (ass->auditor_sign_proc); - GNUNET_OS_process_destroy (ass->auditor_sign_proc); - ass->auditor_sign_proc = NULL; - } - GNUNET_free_non_null (ass->signed_keys_out); - GNUNET_free (ass); -} - - -/** - * Offer "auditor sign" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -auditor_sign_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct AuditorSignState *ass = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_process (0, &ass->auditor_sign_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make a "auditor sign" CMD. - * - * @param label command label - * @param config_filename configuration filename - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_auditor_sign (const char *label, - const char *config_filename) -{ - struct AuditorSignState *ass; - - ass = GNUNET_new (struct AuditorSignState); - ass->config_filename = config_filename; - - { - struct TALER_TESTING_Command cmd = { - .cls = ass, - .label = label, - .run = &auditor_sign_run, - .cleanup = &auditor_sign_cleanup, - .traits = &auditor_sign_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_exec_auditor-sign.c */ diff --git a/src/lib/testing_api_cmd_exec_keyup.c b/src/lib/testing_api_cmd_exec_keyup.c deleted file mode 100644 index 3947ad26e..000000000 --- a/src/lib/testing_api_cmd_exec_keyup.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ - -/** - * @file lib/testing_api_cmd_exec_keyup.c - * @brief run the taler-exchange-keyup command - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "keyup" CMD. - */ -struct KeyupState -{ - - /** - * Process for the "keyup" command. - */ - struct GNUNET_OS_Process *keyup_proc; - - /** - * Configuration file used by the command. - */ - const char *config_filename; - - /** - * If GNUNET_YES, then the fake @e now value will be - * passed to taler-exchange-keyup via the --time - * option. - */ - unsigned int with_now; - - /** - * User-provided fake now. - */ - struct GNUNET_TIME_Absolute now; -}; - - -/** - * Run the command; calls the `taler-exchange-keyup' program. - * - * @param cls closure. - * @param cmd the commaind being run. - * @param is interpreter state. - */ -static void -keyup_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct KeyupState *ks = cls; - - if (GNUNET_YES == ks->with_now) - { - ks->keyup_proc = GNUNET_OS_start_process - (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-keyup", - "taler-exchange-keyup", - "-c", ks->config_filename, - "-o", "auditor.in", - "--time", - GNUNET_STRINGS_absolute_time_to_string (ks->now), - NULL); - } - else - ks->keyup_proc = GNUNET_OS_start_process - (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-keyup", - "taler-exchange-keyup", - "-c", ks->config_filename, - "-o", "auditor.in", - NULL); - - if (NULL == ks->keyup_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - /* This function does not tell whether the command - * succeeded or not! */ - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Free the state of a "keyup" CMD, and possibly kills its - * process if it did not terminate correctly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -keyup_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct KeyupState *ks = cls; - - if (NULL != ks->keyup_proc) - { - GNUNET_break (0 == - GNUNET_OS_process_kill (ks->keyup_proc, - SIGKILL)); - GNUNET_OS_process_wait (ks->keyup_proc); - GNUNET_OS_process_destroy (ks->keyup_proc); - ks->keyup_proc = NULL; - } - GNUNET_free (ks); -} - - -/** - * Offer "keyup" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result - * @param trait name of the trait. - * @param index index number of the object to offer. - * - * @return #GNUNET_OK on success. - */ -static int -keyup_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct KeyupState *ks = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_process (0, &ks->keyup_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make the "keyup" CMD, with "--timestamp" option. - * - * @param label command label. - * @param config_filename configuration filename. - * @param now Unix timestamp representing the fake "now". - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_keyup_with_now - (const char *label, - const char *config_filename, - struct GNUNET_TIME_Absolute now) -{ - struct KeyupState *ks; - - ks = GNUNET_new (struct KeyupState); - ks->config_filename = config_filename; - ks->now = now; - ks->with_now = GNUNET_YES; - { - struct TALER_TESTING_Command cmd = { - .cls = ks, - .label = label, - .run = &keyup_run, - .cleanup = &keyup_cleanup, - .traits = &keyup_traits - }; - - return cmd; - } -} - - -/** - * Make the "keyup" CMD. - * - * @param label command label. - * @param config_filename configuration filename. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_keyup (const char *label, - const char *config_filename) -{ - struct KeyupState *ks; - - ks = GNUNET_new (struct KeyupState); - ks->config_filename = config_filename; - { - struct TALER_TESTING_Command cmd = { - .cls = ks, - .label = label, - .run = &keyup_run, - .cleanup = &keyup_cleanup, - .traits = &keyup_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_exec_keyup.c */ diff --git a/src/lib/testing_api_cmd_exec_wirewatch.c b/src/lib/testing_api_cmd_exec_wirewatch.c deleted file mode 100644 index 75f8f46e4..000000000 --- a/src/lib/testing_api_cmd_exec_wirewatch.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, - or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_exec_wirewatch.c - * @brief run the taler-exchange-wirewatch command - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * State for a "wirewatch" CMD. - */ -struct WirewatchState -{ - - /** - * Process for the wirewatcher. - */ - struct GNUNET_OS_Process *wirewatch_proc; - - /** - * Configuration file used by the wirewatcher. - */ - const char *config_filename; -}; - -/** - * Run the command; use the `taler-exchange-wirewatch' program. - * - * @param cls closure. - * @param cmd command currently being executed. - * @param is interpreter state. - */ -static void -wirewatch_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct WirewatchState *ws = cls; - - ws->wirewatch_proc - = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-wirewatch", - "taler-exchange-wirewatch", - "-c", ws->config_filename, - "-T", /* exit when done */ - NULL); - if (NULL == ws->wirewatch_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Free the state of a "wirewatch" CMD, and possibly - * kills its process if it did not terminate regularly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -wirewatch_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct WirewatchState *ws = cls; - - if (NULL != ws->wirewatch_proc) - { - GNUNET_break (0 == - GNUNET_OS_process_kill (ws->wirewatch_proc, - SIGKILL)); - GNUNET_OS_process_wait (ws->wirewatch_proc); - GNUNET_OS_process_destroy (ws->wirewatch_proc); - ws->wirewatch_proc = NULL; - } - GNUNET_free (ws); -} - - -/** - * Offer "wirewatch" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -wirewatch_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct WirewatchState *ws = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_process (0, - &ws->wirewatch_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Make a "wirewatch" CMD. - * - * @param label command label. - * @param config_filename configuration filename. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_exec_wirewatch (const char *label, - const char *config_filename) -{ - struct WirewatchState *ws; - - ws = GNUNET_new (struct WirewatchState); - ws->config_filename = config_filename; - - { - struct TALER_TESTING_Command cmd = { - .cls = ws, - .label = label, - .run = &wirewatch_run, - .cleanup = &wirewatch_cleanup, - .traits = &wirewatch_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_exec_wirewatch.c */ diff --git a/src/lib/testing_api_cmd_insert_deposit.c b/src/lib/testing_api_cmd_insert_deposit.c deleted file mode 100644 index 1f257574f..000000000 --- a/src/lib/testing_api_cmd_insert_deposit.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, - see -*/ -/** - * @file lib/testing_api_cmd_insert_deposit.c - * @brief deposit a coin directly into the database. - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_json_lib.h" -#include -#include "auditor_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" -#include "taler_exchangedb_plugin.h" - - -/** - * State for a "insert-deposit" CMD. - */ -struct InsertDepositState -{ - /** - * Configuration file used by the command. - */ - const struct TALER_TESTING_DatabaseConnection *dbc; - - /** - * Human-readable name of the shop. - */ - const char *merchant_name; - - /** - * Merchant account name (NOT a payto-URI). - */ - const char *merchant_account; - - /** - * Deadline before which the aggregator should - * send the payment to the merchant. - */ - struct GNUNET_TIME_Relative wire_deadline; - - /** - * Amount to deposit, inclusive of deposit fee. - */ - const char *amount_with_fee; - - /** - * Deposit fee. - */ - const char *deposit_fee; -}; - -/** - * Setup (fake) information about a coin used in deposit. - * - * @param[out] issue information to initialize with "valid" data - */ -static void -fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue) -{ - memset (issue, 0, sizeof (struct - TALER_EXCHANGEDB_DenominationKeyInformationP)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount_nbo ("EUR:1", - &issue->properties.value)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount_nbo ("EUR:0.1", - &issue->properties.fee_withdraw)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount_nbo ("EUR:0.1", - &issue->properties.fee_deposit)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount_nbo ("EUR:0.1", - &issue->properties.fee_refresh)); - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount_nbo ("EUR:0.1", - &issue->properties.fee_refund)); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the commaind being run. - * @param is interpreter state. - */ -static void -insert_deposit_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct InsertDepositState *ids = cls; - struct TALER_EXCHANGEDB_Deposit deposit; - struct TALER_MerchantPrivateKeyP merchant_priv; - struct TALER_EXCHANGEDB_DenominationKeyInformationP issue; - struct TALER_DenominationPublicKey dpk; - struct GNUNET_CRYPTO_RsaPrivateKey *denom_priv; - struct GNUNET_HashCode hc; - - // prepare and store issue first. - fake_issue (&issue); - denom_priv = GNUNET_CRYPTO_rsa_private_key_create (1024); - dpk.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv); - GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key, - &issue.properties.denom_hash); - - if ( (GNUNET_OK != - ids->dbc->plugin->start (ids->dbc->plugin->cls, - ids->dbc->session, - "talertestinglib: denomination insertion")) || - (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - ids->dbc->plugin->insert_denomination_info (ids->dbc->plugin->cls, - ids->dbc->session, - &dpk, - &issue)) || - (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - ids->dbc->plugin->commit (ids->dbc->plugin->cls, - ids->dbc->session)) ) - { - TALER_TESTING_interpreter_fail (is); - return; - } - - /* prepare and store deposit now. */ - memset (&deposit, - 0, - sizeof (deposit)); - - GNUNET_CRYPTO_kdf (&merchant_priv, - sizeof (struct TALER_MerchantPrivateKeyP), - "merchant-priv", - strlen ("merchant-priv"), - ids->merchant_name, - strlen (ids->merchant_name), - NULL, - 0); - GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv, - &deposit.merchant_pub.eddsa_pub); - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, - &deposit.h_contract_terms); - if ( (GNUNET_OK != - TALER_string_to_amount (ids->amount_with_fee, - &deposit.amount_with_fee)) || - (GNUNET_OK != - TALER_string_to_amount (ids->deposit_fee, - &deposit.deposit_fee)) ) - { - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key, - &deposit.coin.denom_pub_hash); - - GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, - &hc); - deposit.coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (denom_priv, - &hc); - { - char *str; - - GNUNET_asprintf (&str, - "payto://x-taler-bank/localhost/%s", - ids->merchant_account); - deposit.receiver_wire_account - = json_pack ("{s:s, s:s}", - "salt", "this-is-a-salt-value", - "url", str); - GNUNET_free (str); - } - - GNUNET_assert (GNUNET_OK == - TALER_JSON_merchant_wire_signature_hash ( - deposit.receiver_wire_account, - &deposit.h_wire)); - deposit.timestamp = GNUNET_TIME_absolute_get (); - GNUNET_TIME_round_abs (&deposit.timestamp); - deposit.wire_deadline = GNUNET_TIME_relative_to_absolute ( - ids->wire_deadline); - GNUNET_TIME_round_abs (&deposit.wire_deadline); - - /* finally, actually perform the DB operation */ - if ( (GNUNET_OK != - ids->dbc->plugin->start (ids->dbc->plugin->cls, - ids->dbc->session, - "libtalertesting: insert deposit")) || - (0 > - ids->dbc->plugin->ensure_coin_known (ids->dbc->plugin->cls, - ids->dbc->session, - &deposit.coin)) || - (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != - ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls, - ids->dbc->session, - &deposit)) || - (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != - ids->dbc->plugin->commit (ids->dbc->plugin->cls, - ids->dbc->session)) ) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - } - - GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (dpk.rsa_public_key); - GNUNET_CRYPTO_rsa_private_key_free (denom_priv); - json_decref (deposit.receiver_wire_account); - - TALER_TESTING_interpreter_next (is); -} - - -/** - * Free the state of a "auditor-dbinit" CMD, and possibly kills its - * process if it did not terminate correctly. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -insert_deposit_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct InsertDepositState *ids = cls; - - GNUNET_free (ids); -} - - -/** - * Offer "insert-deposit" CMD internal data to other commands. - * - * @param cls closure. - * @param[out] ret result - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -insert_deposit_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - (void) cls; - (void) ret; - (void) trait; - (void) index; - return GNUNET_NO; -} - - -/** - * Make the "insert-deposit" CMD. - * - * @param label command label. - * @param dbc collects database plugin and session handles. - * @param merchant_name Human-readable name of the merchant. - * @param merchant_account merchant's account name (NOT a payto:// URI) - * @param wire_deadline point in time where the aggregator should have - * wired money to the merchant. - * @param amount_with_fee amount to deposit (inclusive of deposit fee) - * @param deposit_fee deposit fee - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_insert_deposit (const char *label, - const struct - TALER_TESTING_DatabaseConnection *dbc, - const char *merchant_name, - const char *merchant_account, - struct GNUNET_TIME_Relative wire_deadline, - const char *amount_with_fee, - const char *deposit_fee) -{ - struct InsertDepositState *ids; - - ids = GNUNET_new (struct InsertDepositState); - ids->dbc = dbc; - ids->merchant_name = merchant_name; - ids->merchant_account = merchant_account; - ids->wire_deadline = wire_deadline; - ids->amount_with_fee = amount_with_fee; - ids->deposit_fee = deposit_fee; - - { - struct TALER_TESTING_Command cmd = { - .cls = ids, - .label = label, - .run = &insert_deposit_run, - .cleanup = &insert_deposit_cleanup, - .traits = &insert_deposit_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_insert_deposit.c */ diff --git a/src/lib/testing_api_cmd_recoup.c b/src/lib/testing_api_cmd_recoup.c deleted file mode 100644 index 63319d4f8..000000000 --- a/src/lib/testing_api_cmd_recoup.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_recoup.c - * @brief Implement the /revoke and /recoup test commands. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "revoke" CMD. - */ -struct RevokeState -{ - /** - * Expected HTTP status code. - */ - unsigned int expected_response_code; - - /** - * Command that offers a denomination to revoke. - */ - const char *coin_reference; - - /** - * The interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * The revoke process handle. - */ - struct GNUNET_OS_Process *revoke_proc; - - /** - * Configuration file name. - */ - const char *config_filename; - - /** - * Encoding of the denomination (to revoke) public key hash. - */ - char *dhks; - -}; - - -/** - * State for a "pay back" CMD. - */ -struct RecoupState -{ - /** - * Expected HTTP status code. - */ - unsigned int expected_response_code; - - /** - * Command that offers a reserve private key, - * plus a coin to be paid back. - */ - const char *coin_reference; - - /** - * The interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Amount expected to be paid back. - */ - const char *amount; - - /** - * Handle to the ongoing operation. - */ - struct TALER_EXCHANGE_RecoupHandle *ph; - - /** - * NULL if coin was not refreshed, otherwise reference - * to the melt operation underlying @a coin_reference. - */ - const char *melt_reference; - -}; - - -/** - * Parser reference to a coin. - * - * @param coin_reference of format $LABEL['#' $INDEX]? - * @param[out] cref where we return a copy of $LABEL - * @param[out] idx where we set $INDEX - * @return #GNUNET_SYSERR if $INDEX is present but not numeric - */ -static int -parse_coin_reference (const char *coin_reference, - char **cref, - unsigned int *idx) -{ - const char *index; - - /* We allow command references of the form "$LABEL#$INDEX" or - just "$LABEL", which implies the index is 0. Figure out - which one it is. */ - index = strchr (coin_reference, '#'); - if (NULL == index) - { - *idx = 0; - *cref = GNUNET_strdup (coin_reference); - return GNUNET_OK; - } - *cref = GNUNET_strndup (coin_reference, - index - coin_reference); - if (1 != sscanf (index + 1, - "%u", - idx)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Numeric index (not `%s') required after `#' in command reference of command in %s:%u\n", - index, - __FILE__, - __LINE__); - GNUNET_free (*cref); - *cref = NULL; - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Check the result of the recoup request: checks whether - * the HTTP response code is good, and that the coin that - * was paid back belonged to the right reserve. - * - * @param cls closure - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param amount amount the exchange will wire back for this coin. - * @param timestamp what time did the exchange receive the - * /recoup request - * @param reserve_pub public key of the reserve receiving the recoup, NULL if refreshed or on error - * @param old_coin_pub public key of the dirty coin, NULL if not refreshed or on error - * @param full_response raw response from the exchange. - */ -static void -recoup_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute timestamp, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_CoinSpendPublicKeyP *old_coin_pub, - const json_t *full_response) -{ - struct RecoupState *ps = cls; - struct TALER_TESTING_Interpreter *is = ps->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - const struct TALER_TESTING_Command *reserve_cmd; - char *cref; - unsigned int idx; - - ps->ph = NULL; - if (ps->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - http_status, - cmd->label, - __FILE__, - __LINE__); - json_dumpf (full_response, stderr, 0); - fprintf (stderr, "\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - parse_coin_reference (ps->coin_reference, - &cref, - &idx)) - { - TALER_TESTING_interpreter_fail (is); - return; - } - - reserve_cmd = TALER_TESTING_interpreter_lookup_command - (is, cref); - GNUNET_free (cref); - - if (NULL == reserve_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - switch (http_status) - { - case MHD_HTTP_OK: - /* first, check amount */ - { - struct TALER_Amount expected_amount; - - if (GNUNET_OK != - TALER_string_to_amount (ps->amount, &expected_amount)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (0 != TALER_amount_cmp (amount, &expected_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Total amount missmatch to command %s\n", - cmd->label); - json_dumpf (full_response, stderr, 0); - TALER_TESTING_interpreter_fail (is); - return; - } - } - /* now, check old_coin_pub or reserve_pub, respectively */ - if (NULL != ps->melt_reference) - { - const struct TALER_TESTING_Command *melt_cmd; - const struct TALER_CoinSpendPrivateKeyP *dirty_priv; - struct TALER_CoinSpendPublicKeyP oc; - - melt_cmd = TALER_TESTING_interpreter_lookup_command (is, - ps->melt_reference); - if (NULL == melt_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_coin_priv (melt_cmd, - 0, - &dirty_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv, - &oc.eddsa_pub); - if (0 != GNUNET_memcmp (&oc, - old_coin_pub)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - } - else - { - const struct TALER_ReservePrivateKeyP *reserve_priv; - struct TALER_ReservePublicKeyP rp; - - if (NULL == reserve_pub) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv - (reserve_cmd, idx, &reserve_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, - &rp.eddsa_pub); - if (0 != GNUNET_memcmp (reserve_pub, &rp)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Unmanaged HTTP status code %u.\n", - http_status); - break; - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -recoup_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct RecoupState *ps = cls; - const struct TALER_TESTING_Command *coin_cmd; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - const struct TALER_DenominationBlindingKeyP *blinding_key; - const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; - const struct TALER_DenominationSignature *coin_sig; - struct TALER_PlanchetSecretsP planchet; - char *cref; - unsigned int idx; - - ps->is = is; - if (GNUNET_OK != - parse_coin_reference (ps->coin_reference, - &cref, - &idx)) - { - TALER_TESTING_interpreter_fail (is); - return; - } - - coin_cmd = TALER_TESTING_interpreter_lookup_command - (is, cref); - GNUNET_free (cref); - - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv - (coin_cmd, idx, &coin_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != TALER_TESTING_get_trait_blinding_key - (coin_cmd, idx, &blinding_key)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - planchet.coin_priv = *coin_priv; - planchet.blinding_key = *blinding_key; - - if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub - (coin_cmd, idx, &denom_pub)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig - (coin_cmd, idx, &coin_sig)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Trying to get '%s..' paid back\n", - TALER_B2S (&denom_pub->h_key)); - - ps->ph = TALER_EXCHANGE_recoup (is->exchange, - denom_pub, - coin_sig, - &planchet, - NULL != ps->melt_reference, - recoup_cb, - ps); - GNUNET_assert (NULL != ps->ph); -} - - -/** - * Cleanup the state. - * - * @param cls closure, must be a `struct RevokeState`. - * @param cmd the command which is being cleaned up. - */ -static void -revoke_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct RevokeState *rs = cls; - - if (NULL != rs->revoke_proc) - { - GNUNET_break (0 == GNUNET_OS_process_kill - (rs->revoke_proc, SIGKILL)); - GNUNET_OS_process_wait (rs->revoke_proc); - GNUNET_OS_process_destroy (rs->revoke_proc); - rs->revoke_proc = NULL; - } - GNUNET_free_non_null (rs->dhks); - GNUNET_free (rs); -} - - -/** - * Cleanup the "recoup" CMD state, and possibly cancel - * a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -recoup_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct RecoupState *ps = cls; - if (NULL != ps->ph) - { - TALER_EXCHANGE_recoup_cancel (ps->ph); - ps->ph = NULL; - } - GNUNET_free (ps); -} - - -/** - * Offer internal data from a "revoke" CMD to other CMDs. - * - * @param cls closure - * @param[out] ret result (could be anything) - * @param trait name of the trait - * @param index index number of the object to offer. - * @return #GNUNET_OK on success - */ -static int -revoke_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct RevokeState *rs = cls; - struct TALER_TESTING_Trait traits[] = { - /* Needed by the handler which waits the proc' - * death and calls the next command */ - TALER_TESTING_make_trait_process (0, &rs->revoke_proc), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Run the "revoke" command. The core of the function - * is to call the "keyup" utility passing it the base32 - * encoding of the denomination to revoke. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -revoke_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct RevokeState *rs = cls; - const struct TALER_TESTING_Command *coin_cmd; - const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; - - rs->is = is; - /* Get denom pub from trait */ - coin_cmd = TALER_TESTING_interpreter_lookup_command - (is, rs->coin_reference); - - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_denom_pub - (coin_cmd, 0, &denom_pub)); - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Trying to revoke denom '%s..'\n", - TALER_B2S (&denom_pub->h_key)); - - rs->dhks = GNUNET_STRINGS_data_to_string_alloc - (&denom_pub->h_key, sizeof (struct GNUNET_HashCode)); - - rs->revoke_proc = GNUNET_OS_start_process - (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-keyup", - "taler-exchange-keyup", - "-c", rs->config_filename, - "-r", rs->dhks, - NULL); - - if (NULL == rs->revoke_proc) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Revoke is ongoing..\n"); - - is->reload_keys = GNUNET_OK; - TALER_TESTING_wait_for_sigchld (is); -} - - -/** - * Make a "recoup" command. - * - * @param label the command label - * @param expected_response_code expected HTTP status code - * @param coin_reference reference to any command which - * offers a coin & reserve private key. - * @param amount denomination to pay back. - * @param melt_reference NULL if coin was not refreshed - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_recoup (const char *label, - unsigned int expected_response_code, - const char *coin_reference, - const char *amount, - const char *melt_reference) -{ - struct RecoupState *ps; - - ps = GNUNET_new (struct RecoupState); - ps->expected_response_code = expected_response_code; - ps->coin_reference = coin_reference; - ps->amount = amount; - ps->melt_reference = melt_reference; - { - struct TALER_TESTING_Command cmd = { - .cls = ps, - .label = label, - .run = &recoup_run, - .cleanup = &recoup_cleanup - }; - - return cmd; - } -} - - -/** - * Make a "revoke" command. - * - * @param label the command label. - * @param expected_response_code expected HTTP status code. - * @param coin_reference reference to a CMD that will offer the - * denomination to revoke. - * @param config_filename configuration file name. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_revoke (const char *label, - unsigned int expected_response_code, - const char *coin_reference, - const char *config_filename) -{ - - struct RevokeState *rs; - - rs = GNUNET_new (struct RevokeState); - rs->expected_response_code = expected_response_code; - rs->coin_reference = coin_reference; - rs->config_filename = config_filename; - { - struct TALER_TESTING_Command cmd = { - .cls = rs, - .label = label, - .run = &revoke_run, - .cleanup = &revoke_cleanup, - .traits = &revoke_traits - }; - - return cmd; - } -} diff --git a/src/lib/testing_api_cmd_refresh.c b/src/lib/testing_api_cmd_refresh.c deleted file mode 100644 index 575f1a0c6..000000000 --- a/src/lib/testing_api_cmd_refresh.c +++ /dev/null @@ -1,1411 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_refresh.c - * @brief commands for testing all "refresh" features. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" -#include "taler_signatures.h" -#include "backoff.h" - - -/** - * Information about a fresh coin generated by the refresh - * operation. - */ -struct TALER_TESTING_FreshCoinData -{ - - /** - * If @e amount is NULL, this specifies the denomination key to - * use. Otherwise, this will be set (by the interpreter) to the - * denomination PK matching @e amount. - */ - const struct TALER_EXCHANGE_DenomPublicKey *pk; - - /** - * Set (by the interpreter) to the exchange's signature over the - * coin's public key. - */ - struct TALER_DenominationSignature sig; - - /** - * Set (by the interpreter) to the coin's private key. - */ - struct TALER_CoinSpendPrivateKeyP coin_priv; - - /** - * The blinding key (needed for recoup operations). - */ - struct TALER_DenominationBlindingKeyP blinding_key; - -}; - - -/** - * State for a "refresh melt" command. - */ -struct RefreshMeltState -{ - - /** - * Reference to reserve_withdraw operations for coin to - * be used for the /refresh/melt operation. - */ - const char *coin_reference; - - /** - * "Crypto data" used in the refresh operation. - */ - char *refresh_data; - - /** - * Reference to a previous melt command. - */ - const char *melt_reference; - - /** - * Melt handle while operation is running. - */ - struct TALER_EXCHANGE_RefreshMeltHandle *rmh; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Array of the denomination public keys - * corresponding to the @e num_fresh_coins; - */ - struct TALER_EXCHANGE_DenomPublicKey *fresh_pks; - - /** - * Private key of the dirty coin being melted. - */ - const struct TALER_CoinSpendPrivateKeyP *melt_priv; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Number of bytes in @e refresh_data. - */ - size_t refresh_data_length; - - /** - * Amounts to be generated during melt. - */ - const char **melt_fresh_amounts; - - /** - * Number of fresh coins generated by the melt. - */ - unsigned int num_fresh_coins; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * if set to #GNUNET_YES, then two /refresh/melt operations - * will be performed. This is needed to trigger the logic - * that manages those already-made requests. Note: it - * is not possible to just copy-and-paste a test refresh melt - * CMD to have the same effect, because every data preparation - * generates new planchets that (in turn) make the whole "hash" - * different from any previous one, therefore NOT allowing the - * exchange to pick any previous /rerfesh/melt operation from - * the database. - */ - unsigned int double_melt; - - /** - * Should we retry on (transient) failures? - */ - int do_retry; - - /** - * Set by the melt callback as it comes from the exchange. - */ - uint16_t noreveal_index; -}; - - -/** - * State for a "refresh reveal" CMD. - */ -struct RefreshRevealState -{ - /** - * Link to a "refresh melt" command. - */ - const char *melt_reference; - - /** - * Reveal handle while operation is running. - */ - struct TALER_EXCHANGE_RefreshRevealHandle *rrh; - - /** - * Convenience struct to keep in one place all the - * data related to one fresh coin, set by the reveal callback - * as it comes from the exchange. - */ - struct TALER_TESTING_FreshCoinData *fresh_coins; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Number of fresh coins withdrawn, set by the - * reveal callback as it comes from the exchange, - * it is the length of the @e fresh_coins array. - */ - unsigned int num_fresh_coins; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Should we retry on (transient) failures? - */ - int do_retry; - -}; - - -/** - * State for a "refresh link" CMD. - */ -struct RefreshLinkState -{ - /** - * Link to a "refresh reveal" command. - */ - const char *reveal_reference; - - /** - * Handle to the ongoing operation. - */ - struct TALER_EXCHANGE_RefreshLinkHandle *rlh; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Should we retry on (transient) failures? - */ - int do_retry; - -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -refresh_reveal_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #refresh_reveal_run. - * - * @param cls a `struct RefreshRevealState` - */ -static void -do_reveal_retry (void *cls) -{ - struct RefreshRevealState *rrs = cls; - - rrs->retry_task = NULL; - refresh_reveal_run (rrs, - NULL, - rrs->is); -} - - -/** - * "refresh reveal" request callback; it checks that the response - * code is expected and copies into its command's state the data - * coming from the exchange, namely the fresh coins. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param num_coins number of fresh coins created, length of the - * @a sigs and @a coin_privs arrays, 0 if the operation - * failed. - * @param coin_privs array of @a num_coins private keys for the - * coins that were created, NULL on error. - * @param sigs array of signature over @a num_coins coins, - * NULL on error. - * @param full_response raw exchange response. - */ -static void -reveal_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - unsigned int num_coins, - const struct TALER_PlanchetSecretsP *coin_privs, - const struct TALER_DenominationSignature *sigs, - const json_t *full_response) -{ - struct RefreshRevealState *rrs = cls; - const struct TALER_TESTING_Command *melt_cmd; - - rrs->rrh = NULL; - if (rrs->expected_response_code != http_status) - { - if (GNUNET_YES == rrs->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying refresh reveal failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - rrs->backoff = GNUNET_TIME_UNIT_ZERO; - else - rrs->backoff = EXCHANGE_LIB_BACKOFF (rrs->backoff); - rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff, - &do_reveal_retry, - rrs); - return; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - http_status, - (int) ec, - rrs->is->commands[rrs->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (full_response, stderr, 0); - TALER_TESTING_interpreter_fail (rrs->is); - return; - } - melt_cmd = TALER_TESTING_interpreter_lookup_command - (rrs->is, rrs->melt_reference); - if (NULL == melt_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rrs->is); - return; - } - rrs->num_fresh_coins = num_coins; - switch (http_status) - { - case MHD_HTTP_OK: - rrs->fresh_coins = GNUNET_new_array (num_coins, - struct TALER_TESTING_FreshCoinData); - for (unsigned int i = 0; ifresh_coins[i]; - - if (GNUNET_OK != - TALER_TESTING_get_trait_denom_pub (melt_cmd, - i, - &fc->pk)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rrs->is); - return; - } - fc->coin_priv = coin_privs[i].coin_priv; - fc->blinding_key = coin_privs[i].blinding_key; - fc->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup - (sigs[i].rsa_signature); - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Unknown HTTP status %d\n", - http_status); - } - TALER_TESTING_interpreter_next (rrs->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -refresh_reveal_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct RefreshRevealState *rrs = cls; - struct RefreshMeltState *rms; - const struct TALER_TESTING_Command *melt_cmd; - - rrs->is = is; - melt_cmd = TALER_TESTING_interpreter_lookup_command - (is, rrs->melt_reference); - - if (NULL == melt_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rrs->is); - return; - } - rms = melt_cmd->cls; - rrs->rrh = TALER_EXCHANGE_refresh_reveal - (is->exchange, - rms->refresh_data_length, - rms->refresh_data, - rms->noreveal_index, - &reveal_cb, rrs); - - if (NULL == rrs->rrh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } -} - - -/** - * Free the state from a "refresh reveal" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -refresh_reveal_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct RefreshRevealState *rrs = cls; - - if (NULL != rrs->rrh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rrs->is->ip, - cmd->label); - - TALER_EXCHANGE_refresh_reveal_cancel (rrs->rrh); - rrs->rrh = NULL; - } - if (NULL != rrs->retry_task) - { - GNUNET_SCHEDULER_cancel (rrs->retry_task); - rrs->retry_task = NULL; - } - - for (unsigned int j = 0; j < rrs->num_fresh_coins; j++) - GNUNET_CRYPTO_rsa_signature_free (rrs->fresh_coins[j].sig.rsa_signature); - - GNUNET_free_non_null (rrs->fresh_coins); - rrs->fresh_coins = NULL; - rrs->num_fresh_coins = 0; - GNUNET_free (rrs); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -refresh_link_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #refresh_link_run. - * - * @param cls a `struct RefreshLinkState` - */ -static void -do_link_retry (void *cls) -{ - struct RefreshLinkState *rls = cls; - - rls->retry_task = NULL; - refresh_link_run (rls, - NULL, - rls->is); -} - - -/** - * "refresh link" operation callback, checks that HTTP response - * code is expected _and_ that all the linked coins were actually - * withdrawn by the "refresh reveal" CMD. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code - * @param num_coins number of fresh coins created, length of the - * @a sigs and @a coin_privs arrays, 0 if the operation - * failed. - * @param coin_privs array of @a num_coins private keys for the - * coins that were created, NULL on error. - * @param sigs array of signature over @a num_coins coins, NULL on - * error. - * @param pubs array of public keys for the @a sigs, - * NULL on error. - * @param full_response raw response from the exchange. - */ -static void -link_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - unsigned int num_coins, - const struct TALER_CoinSpendPrivateKeyP *coin_privs, - const struct TALER_DenominationSignature *sigs, - const struct TALER_DenominationPublicKey *pubs, - const json_t *full_response) -{ - - struct RefreshLinkState *rls = cls; - const struct TALER_TESTING_Command *reveal_cmd; - struct TALER_TESTING_Command *link_cmd - = &rls->is->commands[rls->is->ip]; - unsigned int found; - const unsigned int *num_fresh_coins; - - rls->rlh = NULL; - if (rls->expected_response_code != http_status) - { - if (GNUNET_YES == rls->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying refresh link failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - rls->backoff = GNUNET_TIME_UNIT_ZERO; - else - rls->backoff = EXCHANGE_LIB_BACKOFF (rls->backoff); - rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff, - &do_link_retry, - rls); - return; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - http_status, - (int) ec, - link_cmd->label, - __FILE__, - __LINE__); - json_dumpf (full_response, stderr, 0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - reveal_cmd = TALER_TESTING_interpreter_lookup_command - (rls->is, rls->reveal_reference); - - if (NULL == reveal_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - - switch (http_status) - { - case MHD_HTTP_OK: - /* check that number of coins returned matches */ - if (GNUNET_OK != TALER_TESTING_get_trait_uint - (reveal_cmd, 0, &num_fresh_coins)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - if (num_coins != *num_fresh_coins) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected number of fresh coins: %d vs %d in %s:%u\n", - num_coins, - *num_fresh_coins, - __FILE__, - __LINE__); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - /* check that the coins match */ - for (unsigned int i = 0; iis); - return; - } - - for (unsigned int i = 0; ikey.rsa_public_key, - pubs[j].rsa_public_key)) ) - { - found++; - break; - } - } - if (found != num_coins) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Only %u/%u coins match expectations\n", - found, num_coins); - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown HTTP response code %u.\n", - http_status); - } - TALER_TESTING_interpreter_next (rls->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -refresh_link_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct RefreshLinkState *rls = cls; - struct RefreshRevealState *rrs; - struct RefreshMeltState *rms; - const struct TALER_TESTING_Command *reveal_cmd; - const struct TALER_TESTING_Command *melt_cmd; - const struct TALER_TESTING_Command *coin_cmd; - - rls->is = is; - reveal_cmd = TALER_TESTING_interpreter_lookup_command - (rls->is, rls->reveal_reference); - - if (NULL == reveal_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - rrs = reveal_cmd->cls; - melt_cmd = TALER_TESTING_interpreter_lookup_command - (rls->is, rrs->melt_reference); - - if (NULL == melt_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - - /* find reserve_withdraw command */ - { - rms = melt_cmd->cls; - coin_cmd = TALER_TESTING_interpreter_lookup_command - (rls->is, rms->coin_reference); - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - } - - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv - (coin_cmd, 0, &coin_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } - - /* finally, use private key from withdraw sign command */ - rls->rlh = TALER_EXCHANGE_refresh_link - (is->exchange, coin_priv, &link_cb, rls); - - if (NULL == rls->rlh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rls->is); - return; - } -} - - -/** - * Free the state of the "refresh link" CMD, and possibly - * cancel a operation thereof. - * - * @param cls closure - * @param cmd the command which is being cleaned up. - */ -static void -refresh_link_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct RefreshLinkState *rls = cls; - - if (NULL != rls->rlh) - { - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rls->is->ip, - cmd->label); - TALER_EXCHANGE_refresh_link_cancel (rls->rlh); - rls->rlh = NULL; - } - if (NULL != rls->retry_task) - { - GNUNET_SCHEDULER_cancel (rls->retry_task); - rls->retry_task = NULL; - } - GNUNET_free (rls); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -refresh_melt_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #refresh_melt_run. - * - * @param cls a `struct RefreshMeltState` - */ -static void -do_melt_retry (void *cls) -{ - struct RefreshMeltState *rms = cls; - - rms->retry_task = NULL; - refresh_melt_run (rms, - NULL, - rms->is); -} - - -/** - * Callback for a "refresh melt" operation; checks if the HTTP - * response code is okay and re-run the melt operation if the - * CMD was set to do so. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param noreveal_index choice by the exchange in the - * cut-and-choose protocol, UINT16_MAX on error. - * @param exchange_pub public key the exchange used for signing. - * @param full_response raw response body from the exchange. - */ -static void -melt_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint32_t noreveal_index, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const json_t *full_response) -{ - struct RefreshMeltState *rms = cls; - - rms->rmh = NULL; - if (rms->expected_response_code != http_status) - { - if (GNUNET_YES == rms->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying refresh melt failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - rms->backoff = GNUNET_TIME_UNIT_ZERO; - else - rms->backoff = EXCHANGE_LIB_BACKOFF (rms->backoff); - rms->retry_task = GNUNET_SCHEDULER_add_delayed - (rms->backoff, - &do_melt_retry, - rms); - return; - } - } - GNUNET_log - (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - http_status, - (int) ec, - rms->is->commands[rms->is->ip].label, - __FILE__, - __LINE__); - json_dumpf (full_response, stderr, 0); - TALER_TESTING_interpreter_fail (rms->is); - return; - } - rms->noreveal_index = noreveal_index; - - if (GNUNET_YES == rms->double_melt) - { - TALER_LOG_DEBUG ("Doubling the melt (%s)\n", - rms->is->commands[rms->is->ip].label); - rms->rmh = TALER_EXCHANGE_refresh_melt - (rms->is->exchange, rms->refresh_data_length, - rms->refresh_data, &melt_cb, rms); - rms->double_melt = GNUNET_NO; - return; - } - TALER_TESTING_interpreter_next (rms->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -refresh_melt_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct RefreshMeltState *rms = cls; - unsigned int num_fresh_coins; - const char *default_melt_fresh_amounts[] = { - "EUR:1", "EUR:1", "EUR:1", "EUR:0.1", - NULL - }; - const char **melt_fresh_amounts; - - if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts)) - melt_fresh_amounts = default_melt_fresh_amounts; - rms->is = is; - rms->noreveal_index = UINT16_MAX; - for (num_fresh_coins = 0; - NULL != melt_fresh_amounts[num_fresh_coins]; - num_fresh_coins++) - ; - rms->num_fresh_coins = num_fresh_coins; - rms->fresh_pks = GNUNET_new_array - (num_fresh_coins, - struct TALER_EXCHANGE_DenomPublicKey); - { - struct TALER_Amount melt_amount; - struct TALER_Amount fresh_amount; - const struct TALER_DenominationSignature *melt_sig; - const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub; - const struct TALER_TESTING_Command *coin_command; - - if (NULL == (coin_command - = TALER_TESTING_interpreter_lookup_command - (is, rms->coin_reference))) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rms->is); - return; - } - - if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv - (coin_command, 0, &rms->melt_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rms->is); - return; - } - - if (GNUNET_OK != - TALER_TESTING_get_trait_denom_sig (coin_command, - 0, - &melt_sig)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rms->is); - return; - } - if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub - (coin_command, 0, &melt_denom_pub)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rms->is); - return; - } - /* Melt amount starts with the melt fee of the old coin; we'll add the - values and withdraw fees of the fresh coins next */ - melt_amount = melt_denom_pub->fee_refresh; - for (unsigned int i = 0; iis); - return; - } - fresh_pk = TALER_TESTING_find_pk - (TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount); - if (NULL == fresh_pk) - { - GNUNET_break (0); - /* Subroutine logs specific error */ - TALER_TESTING_interpreter_fail (rms->is); - return; - } - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&melt_amount, - &melt_amount, - &fresh_amount)); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&melt_amount, - &melt_amount, - &fresh_pk->fee_withdraw)); - rms->fresh_pks[i] = *fresh_pk; - /* Make a deep copy of the RSA key */ - rms->fresh_pks[i].key.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pk->key.rsa_public_key); - } - rms->refresh_data - = TALER_EXCHANGE_refresh_prepare (rms->melt_priv, - &melt_amount, - melt_sig, - melt_denom_pub, - num_fresh_coins, - rms->fresh_pks, - &rms->refresh_data_length); - - if (NULL == rms->refresh_data) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rms->is); - return; - } - rms->rmh = TALER_EXCHANGE_refresh_melt (is->exchange, - rms->refresh_data_length, - rms->refresh_data, - &melt_cb, - rms); - - if (NULL == rms->rmh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (rms->is); - return; - } - } -} - - -/** - * Free the "refresh melt" CMD state, and possibly cancel a - * pending operation thereof. - * - * @param cls closure, must be a `struct RefreshMeltState`. - * @param cmd the command which is being cleaned up. - */ -static void -refresh_melt_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct RefreshMeltState *rms = cls; - - if (NULL != rms->rmh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rms->is->ip, rms->is->commands[rms->is->ip].label); - TALER_EXCHANGE_refresh_melt_cancel (rms->rmh); - rms->rmh = NULL; - } - if (NULL != rms->retry_task) - { - GNUNET_SCHEDULER_cancel (rms->retry_task); - rms->retry_task = NULL; - } - if (NULL != rms->fresh_pks) - { - for (unsigned int i = 0; i < rms->num_fresh_coins; i++) - GNUNET_CRYPTO_rsa_public_key_free (rms->fresh_pks[i].key.rsa_public_key); - } - GNUNET_free_non_null (rms->fresh_pks); - rms->fresh_pks = NULL; - GNUNET_free_non_null (rms->refresh_data); - rms->refresh_data = NULL; - rms->refresh_data_length = 0; - GNUNET_free_non_null (rms->melt_fresh_amounts); - GNUNET_free (rms); -} - - -/** - * Offer internal data to the "refresh melt" CMD. - * - * @param cls closure. - * @param[out] ret result (could be anything). - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -refresh_melt_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct RefreshMeltState *rms = cls; - - if (index >= rms->num_fresh_coins) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - { - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]), - TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); - } -} - - -/** - * Parse list of amounts for melt operation. - * - * @param[in,out] rms where to store the list - * @param ap NULL-termianted list of amounts to be melted (one per fresh coin) - * @return #GNUNET_OK on success - */ -static int -parse_amounts (struct RefreshMeltState *rms, - va_list ap) -{ - unsigned int len; - unsigned int off; - const char *amount; - - len = 0; - off = 0; - while (NULL != (amount = va_arg (ap, const char *))) - { - if (len == off) - { - struct TALER_Amount a; - - GNUNET_array_grow (rms->melt_fresh_amounts, - len, - off + 16); - if (GNUNET_OK != - TALER_string_to_amount (amount, &a)) - { - GNUNET_break (0); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at index %u\n", - amount, off); - GNUNET_free (rms->melt_fresh_amounts); - rms->melt_fresh_amounts = NULL; - return GNUNET_SYSERR; - } - rms->melt_fresh_amounts[off++] = amount; - } - } - if (0 == off) - return GNUNET_OK; /* no amounts given == use defaults! */ - /* ensure NULL-termination */ - GNUNET_array_grow (rms->melt_fresh_amounts, - len, - off + 1); - return GNUNET_OK; -} - - -/** - * Create a "refresh melt" command. - * - * @param label command label. - * @param coin_reference reference to a command - * that will provide a coin to refresh. - * @param expected_response_code expected HTTP code. - * @param ... NULL-terminated list of amounts to be melted - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refresh_melt (const char *label, - const char *coin_reference, - unsigned int expected_response_code, - ...) -{ - struct RefreshMeltState *rms; - va_list ap; - - rms = GNUNET_new (struct RefreshMeltState); - rms->coin_reference = coin_reference; - rms->expected_response_code = expected_response_code; - va_start (ap, expected_response_code); - GNUNET_assert (GNUNET_OK == - parse_amounts (rms, ap)); - va_end (ap); - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = rms, - .run = &refresh_melt_run, - .cleanup = &refresh_melt_cleanup, - .traits = &refresh_melt_traits - }; - - return cmd; - } -} - - -/** - * Create a "refresh melt" CMD that does TWO /refresh/melt - * requests. This was needed to test the replay of a valid melt - * request, see #5312. - * - * @param label command label - * @param coin_reference reference to a command that will provide - * a coin to refresh - * @param expected_response_code expected HTTP code - * @param ... NULL-terminated list of amounts to be melted - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refresh_melt_double (const char *label, - const char *coin_reference, - unsigned int expected_response_code, - ...) -{ - struct RefreshMeltState *rms; - va_list ap; - - rms = GNUNET_new (struct RefreshMeltState); - rms->coin_reference = coin_reference; - rms->expected_response_code = expected_response_code; - rms->double_melt = GNUNET_YES; - va_start (ap, expected_response_code); - GNUNET_assert (GNUNET_OK == - parse_amounts (rms, ap)); - va_end (ap); - { - struct TALER_TESTING_Command cmd = { - .label = label, - .cls = rms, - .run = &refresh_melt_run, - .cleanup = &refresh_melt_cleanup, - .traits = &refresh_melt_traits - }; - - return cmd; - } -} - - -/** - * Modify a "refresh melt" command to enable retries. - * - * @param cmd command - * @return modified command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refresh_melt_with_retry (struct TALER_TESTING_Command cmd) -{ - struct RefreshMeltState *rms; - - GNUNET_assert (&refresh_melt_run == cmd.run); - rms = cmd.cls; - rms->do_retry = GNUNET_YES; - return cmd; -} - - -/** - * Offer internal data from a "refresh reveal" CMD. - * - * @param cls closure. - * @param[out] ret result (could be anything). - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -refresh_reveal_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct RefreshRevealState *rrs = cls; - unsigned int num_coins = rrs->num_fresh_coins; -#define NUM_TRAITS ((num_coins * 4) + 3) - struct TALER_TESTING_Trait traits[NUM_TRAITS]; - - /* Making coin privs traits */ - for (unsigned int i = 0; ifresh_coins[i].coin_priv); - - /* Making denom pubs traits */ - for (unsigned int i = 0; ifresh_coins[i].pk); - - /* Making denom sigs traits */ - for (unsigned int i = 0; ifresh_coins[i].sig); - /* blinding key traits */ - for (unsigned int i = 0; ifresh_coins[i].blinding_key), - - /* number of fresh coins */ - traits[(num_coins * 4)] = TALER_TESTING_make_trait_uint - (0, &rrs->num_fresh_coins); - - /* whole array of fresh coins */ - traits[(num_coins * 4) + 1] - = TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins), - - /* end of traits */ - traits[(num_coins * 4) + 2] = TALER_TESTING_trait_end (); - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Create a "refresh reveal" command. - * - * @param label command label. - * @param melt_reference reference to a "refresh melt" command. - * @param expected_response_code expected HTTP response code. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refresh_reveal (const char *label, - const char *melt_reference, - unsigned int expected_response_code) -{ - struct RefreshRevealState *rrs; - - rrs = GNUNET_new (struct RefreshRevealState); - rrs->melt_reference = melt_reference; - rrs->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = rrs, - .label = label, - .run = &refresh_reveal_run, - .cleanup = &refresh_reveal_cleanup, - .traits = &refresh_reveal_traits - }; - - return cmd; - } -} - - -/** - * Modify a "refresh reveal" command to enable retries. - * - * @param cmd command - * @return modified command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd) -{ - struct RefreshRevealState *rrs; - - GNUNET_assert (&refresh_reveal_run == cmd.run); - rrs = cmd.cls; - rrs->do_retry = GNUNET_YES; - return cmd; -} - - -/** - * Create a "refresh link" command. - * - * @param label command label. - * @param reveal_reference reference to a "refresh reveal" CMD. - * @param expected_response_code expected HTTP response code - * @return the "refresh link" command - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refresh_link (const char *label, - const char *reveal_reference, - unsigned int expected_response_code) -{ - struct RefreshLinkState *rrs; - - rrs = GNUNET_new (struct RefreshLinkState); - rrs->reveal_reference = reveal_reference; - rrs->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = rrs, - .label = label, - .run = &refresh_link_run, - .cleanup = &refresh_link_cleanup - }; - - return cmd; - } -} - - -/** - * Modify a "refresh link" command to enable retries. - * - * @param cmd command - * @return modified command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refresh_link_with_retry (struct TALER_TESTING_Command cmd) -{ - struct RefreshLinkState *rls; - - GNUNET_assert (&refresh_link_run == cmd.run); - rls = cmd.cls; - rls->do_retry = GNUNET_YES; - return cmd; -} diff --git a/src/lib/testing_api_cmd_refund.c b/src/lib/testing_api_cmd_refund.c deleted file mode 100644 index a45303806..000000000 --- a/src/lib/testing_api_cmd_refund.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_refund.c - * @brief Implement the /refund test command, plus other - * corollary commands (?). - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "refund" CMD. - */ -struct RefundState -{ - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Amount to be refunded. - */ - const char *refund_amount; - - /** - * Expected refund fee. - */ - const char *refund_fee; - - /** - * Reference to any command that can provide a coin to refund. - */ - const char *coin_reference; - - /** - * Refund transaction identifier. - */ - uint64_t refund_transaction_id; - - /** - * Connection to the exchange. - */ - struct TALER_EXCHANGE_Handle *exchange; - - /** - * Handle to the refund operation. - */ - struct TALER_EXCHANGE_RefundHandle *rh; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * Check the result for the refund request, just check if the - * response code is acceptable. - * - * @param cls closure - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param exchange_pub public key the exchange - * used for signing @a obj. - * @param obj response object. - */ -static void -refund_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const json_t *obj) -{ - - struct RefundState *rs = cls; - struct TALER_TESTING_Command *refund_cmd; - - refund_cmd = &rs->is->commands[rs->is->ip]; - rs->rh = NULL; - if (rs->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - http_status, - refund_cmd->label, - __FILE__, - __LINE__); - json_dumpf (obj, stderr, 0); - TALER_TESTING_interpreter_fail (rs->is); - return; - } - TALER_TESTING_interpreter_next (rs->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -refund_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct RefundState *rs = cls; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - struct TALER_CoinSpendPublicKeyP coin; - const json_t *contract_terms; - struct GNUNET_HashCode h_contract_terms; - struct TALER_Amount refund_fee; - struct TALER_Amount refund_amount; - const struct TALER_MerchantPrivateKeyP *merchant_priv; - const struct TALER_TESTING_Command *coin_cmd; - - rs->exchange = is->exchange; - rs->is = is; - - if (GNUNET_OK != - TALER_string_to_amount (rs->refund_amount, - &refund_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u/%s\n", - rs->refund_amount, - is->ip, - cmd->label); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_string_to_amount (rs->refund_fee, - &refund_fee)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u/%s\n", - rs->refund_fee, - is->ip, - cmd->label); - TALER_TESTING_interpreter_fail (is); - return; - } - - coin_cmd = TALER_TESTING_interpreter_lookup_command (is, - rs->coin_reference); - if (NULL == coin_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_contract_terms (coin_cmd, - 0, - &contract_terms)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - GNUNET_assert (GNUNET_OK == - TALER_JSON_hash (contract_terms, - &h_contract_terms)); - - /* Hunting for a coin .. */ - if (GNUNET_OK != - TALER_TESTING_get_trait_coin_priv (coin_cmd, - 0, - &coin_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin.eddsa_pub); - if (GNUNET_OK != - TALER_TESTING_get_trait_merchant_priv (coin_cmd, - 0, - &merchant_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - rs->rh = TALER_EXCHANGE_refund (rs->exchange, - &refund_amount, - &refund_fee, - &h_contract_terms, - &coin, - rs->refund_transaction_id, - merchant_priv, - &refund_cb, - rs); - GNUNET_assert (NULL != rs->rh); -} - - -/** - * Free the state from a "refund" CMD, and possibly cancel - * a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -refund_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct RefundState *rs = cls; - - if (NULL != rs->rh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - rs->is->ip, - cmd->label); - TALER_EXCHANGE_refund_cancel (rs->rh); - rs->rh = NULL; - } - GNUNET_free (rs); -} - - -/** - * Create a "refund" command. - * - * @param label command label. - * @param expected_response_code expected HTTP status code. - * @param refund_amount the amount to ask a refund for. - * @param refund_fee expected refund fee. - * @param coin_reference reference to a command that can - * provide a coin to be refunded. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refund (const char *label, - unsigned int expected_response_code, - const char *refund_amount, - const char *refund_fee, - const char *coin_reference) -{ - struct RefundState *rs; - - rs = GNUNET_new (struct RefundState); - - rs->expected_response_code = expected_response_code; - rs->refund_amount = refund_amount; - rs->refund_fee = refund_fee; - rs->coin_reference = coin_reference; - { - struct TALER_TESTING_Command cmd = { - .cls = rs, - .label = label, - .run = &refund_run, - .cleanup = &refund_cleanup - }; - - return cmd; - } -} - - -/** - * Create a "refund" command, allow to specify refund transaction - * id. Mainly used to create conflicting requests. - * - * @param label command label. - * @param expected_response_code expected HTTP status code. - * @param refund_amount the amount to ask a refund for. - * @param refund_fee expected refund fee. - * @param coin_reference reference to a command that can - * provide a coin to be refunded. - * @param refund_transaction_id transaction id to use - * in the request. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_refund_with_id - (const char *label, - unsigned int expected_response_code, - const char *refund_amount, - const char *refund_fee, - const char *coin_reference, - uint64_t refund_transaction_id) -{ - struct RefundState *rs; - - rs = GNUNET_new (struct RefundState); - rs->expected_response_code = expected_response_code; - rs->refund_amount = refund_amount; - rs->refund_fee = refund_fee; - rs->coin_reference = coin_reference; - rs->refund_transaction_id = refund_transaction_id; - { - struct TALER_TESTING_Command cmd = { - .cls = rs, - .label = label, - .run = &refund_run, - .cleanup = &refund_cleanup - }; - - return cmd; - } -} diff --git a/src/lib/testing_api_cmd_serialize_keys.c b/src/lib/testing_api_cmd_serialize_keys.c deleted file mode 100644 index e18a25b77..000000000 --- a/src/lib/testing_api_cmd_serialize_keys.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - This file is part of TALER - (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_serialize_keys.c - * @brief Lets tests use the keys serialization API. - * @author Marcello Stanisci - */ -#include "platform.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * Internal state for a serialize-keys CMD. - */ -struct SerializeKeysState -{ - /** - * Serialized keys. - */ - json_t *keys; - - /** - * Exchange URL. Needed because the exchange gets disconnected - * from, after keys serialization. This value is then needed by - * subsequent commands that have to reconnect to the exchagne. - */ - char *exchange_url; -}; - - -/** - * Internal state for a connect-with-state CMD. - */ -struct ConnectWithStateState -{ - - /** - * Reference to a CMD that offers a serialized key-state - * that will be used in the reconnection. - */ - const char *state_reference; - - /** - * If set to GNUNET_YES, then the /keys callback has already - * been passed the control to the next CMD. This is necessary - * because it is not uncommon that the /keys callback gets - * invoked multiple times, and without this flag, we would keep - * going "next" CMD upon every invocation (causing impredictable - * behaviour as for the instruction pointer.) - */ - unsigned int consumed; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -serialize_keys_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct SerializeKeysState *sks = cls; - - sks->keys = TALER_EXCHANGE_serialize_data (is->exchange); - if (NULL == sks->keys) - TALER_TESTING_interpreter_fail (is); - - sks->exchange_url = GNUNET_strdup - (TALER_EXCHANGE_get_base_url (is->exchange)); - TALER_EXCHANGE_disconnect (is->exchange); - is->exchange = NULL; - is->working = GNUNET_NO; - TALER_TESTING_interpreter_next (is); -} - - -/** - * Cleanup the state of a "serialize keys" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -serialize_keys_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct SerializeKeysState *sks = cls; - - if (NULL != sks->keys) - { - json_decref (sks->keys); - } - GNUNET_free_non_null (sks->exchange_url); - GNUNET_free (sks); -} - - -/** - * Offer serialized keys as trait. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -serialize_keys_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct SerializeKeysState *sks = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_exchange_keys (0, sks->keys), - TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, - sks->exchange_url), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -connect_with_state_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct ConnectWithStateState *cwss = cls; - const struct TALER_TESTING_Command *state_cmd; - const json_t *serialized_keys; - const char *exchange_url; - - /* This command usually gets rescheduled after serialized - * reconnection. */ - if (GNUNET_YES == cwss->consumed) - { - TALER_TESTING_interpreter_next (is); - return; - } - - cwss->is = is; - state_cmd = TALER_TESTING_interpreter_lookup_command - (is, cwss->state_reference); - - /* Command providing serialized keys not found. */ - if (NULL == state_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_exchange_keys (state_cmd, - 0, - &serialized_keys)); - { - char *dump; - - dump = json_dumps (serialized_keys, - JSON_INDENT (1)); - TALER_LOG_DEBUG ("Serialized key-state: %s\n", - dump); - free (dump); - } - - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_url (state_cmd, - TALER_TESTING_UT_EXCHANGE_BASE_URL, - &exchange_url)); - is->exchange = TALER_EXCHANGE_connect (is->ctx, - exchange_url, - TALER_TESTING_cert_cb, - cwss, - TALER_EXCHANGE_OPTION_DATA, - serialized_keys, - TALER_EXCHANGE_OPTION_END); - cwss->consumed = GNUNET_YES; -} - - -/** - * Cleanup the state of a "connect with state" CMD. Just - * a placeholder to avoid jumping on an invalid address. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -connect_with_state_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct ConnectWithStateState *cwss = cls; - - GNUNET_free (cwss); -} - - -/** - * Make a serialize-keys CMD. It will ask for - * keys serialization __and__ disconnect from the - * exchange. - * - * @param label CMD label - * @return the CMD. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_serialize_keys (const char *label) -{ - struct SerializeKeysState *sks; - - sks = GNUNET_new (struct SerializeKeysState); - { - struct TALER_TESTING_Command cmd = { - .cls = sks, - .label = label, - .run = serialize_keys_run, - .cleanup = serialize_keys_cleanup, - .traits = serialize_keys_traits - }; - - return cmd; - } -} - - -/** - * Make a connect-with-state CMD. This command - * will use a serialized key state to reconnect - * to the exchange. - * - * @param label command label - * @param state_reference label of a CMD offering - * a serialized key state. - * @return the CMD. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_connect_with_state (const char *label, - const char *state_reference) -{ - struct ConnectWithStateState *cwss; - - cwss = GNUNET_new (struct ConnectWithStateState); - cwss->state_reference = state_reference; - cwss->consumed = GNUNET_NO; - { - struct TALER_TESTING_Command cmd = { - .cls = cwss, - .label = label, - .run = connect_with_state_run, - .cleanup = connect_with_state_cleanup - }; - - return cmd; - } -} diff --git a/src/lib/testing_api_cmd_signal.c b/src/lib/testing_api_cmd_signal.c deleted file mode 100644 index cca8e02bd..000000000 --- a/src/lib/testing_api_cmd_signal.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - This file is part of TALER - (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_signal.c - * @brief command(s) to send signals to processes. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "signal" CMD. - */ -struct SignalState -{ - /** - * The process to send the signal to. - */ - struct GNUNET_OS_Process *process; - - /** - * The signal to send to the process. - */ - int signal; -}; - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -signal_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct SignalState *ss = cls; - - GNUNET_break (0 == GNUNET_OS_process_kill - (ss->process, ss->signal)); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Signaling '%d'..\n", - ss->signal); - sleep (6); - TALER_TESTING_interpreter_next (is); -} - - -/** - * Cleanup the state from a "signal" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -signal_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct SignalState *ss = cls; - - GNUNET_free (ss); -} - - -/** - * Create a "signal" CMD. - * - * @param label command label. - * @param process handle to the process to signal. - * @param signal signal to send. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_signal (const char *label, - struct GNUNET_OS_Process *process, - int signal) -{ - struct SignalState *ss; - - ss = GNUNET_new (struct SignalState); - ss->process = process; - ss->signal = signal; - - - struct TALER_TESTING_Command cmd = { - .cls = ss, - .label = label, - .run = &signal_run, - .cleanup = &signal_cleanup - }; - - return cmd; -} diff --git a/src/lib/testing_api_cmd_sleep.c b/src/lib/testing_api_cmd_sleep.c deleted file mode 100644 index f7af53e51..000000000 --- a/src/lib/testing_api_cmd_sleep.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - This file is part of TALER - (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_sleep.c - * @brief command(s) to sleep for a bit - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "sleep" CMD. - */ -struct SleepState -{ - - /** - * How long should we sleep? - */ - unsigned int duration; -}; - - -/** - * No traits to offer, just provide a stub to be called when - * some CMDs iterates through the list of all the commands. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the trait to return. - * @return #GNUNET_OK on success. - */ -static int -sleep_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - (void) cls; - (void) ret; - (void) trait; - (void) index; - return GNUNET_NO; -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -sleep_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct SleepState *ss = cls; - - sleep (ss->duration); - TALER_TESTING_interpreter_next (is); -} - - -/** - * Cleanup the state from a "sleep" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -sleep_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct SleepState *ss = cls; - - (void) cmd; - GNUNET_free (ss); -} - - -/** - * Sleep for @a duration_s seconds. - * - * @param label command label. - * @param duration_s number of seconds to sleep - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_sleep (const char *label, - unsigned int duration_s) -{ - struct SleepState *ss; - - ss = GNUNET_new (struct SleepState); - ss->duration = duration_s; - - { - struct TALER_TESTING_Command cmd = { - .cls = ss, - .label = label, - .run = &sleep_run, - .cleanup = &sleep_cleanup, - .traits = &sleep_traits - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_sleep.c */ diff --git a/src/lib/testing_api_cmd_status.c b/src/lib/testing_api_cmd_status.c deleted file mode 100644 index 41d2c326e..000000000 --- a/src/lib/testing_api_cmd_status.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_status.c - * @brief Implement the /reserve/status test command. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "status" CMD. - */ -struct StatusState -{ - /** - * Label to the command which created the reserve to check, - * needed to resort the reserve key. - */ - const char *reserve_reference; - - /** - * Handle to the "reserve status" operation. - */ - struct TALER_EXCHANGE_ReserveStatusHandle *rsh; - - /** - * Expected reserve balance. - */ - const char *expected_balance; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * Check that the reserve balance and HTTP response code are - * both acceptable. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param json original JSON response from the exchange - * @param balance current balance in the reserve, NULL on error. - * @param history_length number of entries in the transaction - * history, 0 on error. - * @param history detailed transaction history, NULL on error. - */ -static void -reserve_status_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const json_t *json, - const struct TALER_Amount *balance, - unsigned int history_length, - const struct TALER_EXCHANGE_ReserveHistory *history) -{ - struct StatusState *ss = cls; - struct TALER_Amount eb; - - ss->rsh = NULL; - if (ss->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected HTTP response code: %d in %s:%u\n", - http_status, - __FILE__, - __LINE__); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - - GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (ss->expected_balance, - &eb)); - - if (0 != TALER_amount_cmp (&eb, - balance)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected amount in reserve: %s\n", - TALER_amount_to_string (balance)); - TALER_TESTING_interpreter_fail (ss->is); - return; - } - - /** - * TODO (#6049): We should check that reserve history is consistent. Every - * command which relates to reserve 'x' should be added in a linked list of - * all commands that relate to the same reserve 'x'. - * - * API-wise, any command that relates to a reserve should offer a - * method called e.g. "compare_with_history" that takes an element - * of the array returned by "/reserve/status" and checks if that - * element correspond to itself (= the command exposing the check- - * method). - * - * IDEA: Maybe realize this via another trait, some kind of - * "reserve history update trait" which returns information about - * how the command changes the history (provided only by commands - * that change reserve balances)? - */// - TALER_TESTING_interpreter_next (ss->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command being executed. - * @param is the interpreter state. - */ -static void -status_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct StatusState *ss = cls; - const struct TALER_TESTING_Command *create_reserve; - const struct TALER_ReservePublicKeyP *reserve_pubp; - - ss->is = is; - create_reserve - = TALER_TESTING_interpreter_lookup_command (is, - ss->reserve_reference); - - if (NULL == create_reserve) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_pub (create_reserve, - 0, - &reserve_pubp)) - { - GNUNET_break (0); - TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - ss->rsh = TALER_EXCHANGE_reserve_status (is->exchange, - reserve_pubp, - &reserve_status_cb, - ss); -} - - -/** - * Cleanup the state from a "reserve status" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -status_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct StatusState *ss = cls; - - if (NULL != ss->rsh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ss->is->ip, - cmd->label); - TALER_EXCHANGE_reserve_status_cancel (ss->rsh); - ss->rsh = NULL; - } - GNUNET_free (ss); -} - - -/** - * Create a "reserve status" command. - * - * @param label the command label. - * @param reserve_reference reference to the reserve to check. - * @param expected_balance expected balance for the reserve. - * @param expected_response_code expected HTTP response code. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_status (const char *label, - const char *reserve_reference, - const char *expected_balance, - unsigned int expected_response_code) -{ - struct StatusState *ss; - - GNUNET_assert (NULL != reserve_reference); - ss = GNUNET_new (struct StatusState); - ss->reserve_reference = reserve_reference; - ss->expected_balance = expected_balance; - ss->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = ss, - .label = label, - .run = &status_run, - .cleanup = &status_cleanup - }; - - return cmd; - } -} diff --git a/src/lib/testing_api_cmd_track.c b/src/lib/testing_api_cmd_track.c deleted file mode 100644 index 51ad45be4..000000000 --- a/src/lib/testing_api_cmd_track.c +++ /dev/null @@ -1,806 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/testing_api_cmd_track.c - * @brief Implement the testing CMDs for the /track operations. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - -/** - * State for a "track transaction" CMD. - */ -struct TrackTransactionState -{ - - /** - * If non NULL, will provide a WTID to be compared against - * the one returned by the "track transaction" operation. - */ - const char *bank_transfer_reference; - - /** - * The WTID associated by the transaction being tracked. - */ - struct TALER_WireTransferIdentifierRawP wtid; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Reference to any operation that can provide a transaction. - * Will be the transaction to track. - */ - const char *transaction_reference; - - /** - * Index of the coin involved in the transaction. Recall: - * at the exchange, the tracking is done _per coin_. - */ - unsigned int coin_index; - - /** - * Handle to the "track transaction" pending operation. - */ - struct TALER_EXCHANGE_TrackTransactionHandle *tth; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * State for a "track transfer" CMD. - */ -struct TrackTransferState -{ - - /** - * Expected amount for the WTID being tracked. - */ - const char *expected_total_amount; - - /** - * Expected fee for this WTID. - */ - const char *expected_wire_fee; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Reference to any operation that can provide a WTID. - * Will be the WTID to track. - */ - const char *wtid_reference; - - /** - * Reference to any operation that can provide wire details. - * Those wire details will then be matched against the credit - * bank account of the tracked WTID. This way we can test that - * a wire transfer paid back one particular bank account. - */ - const char *wire_details_reference; - - /** - * Reference to any operation that can provide an amount. - * This way we can check that the transferred amount matches - * our expectations. - */ - const char *total_amount_reference; - - /** - * Index to the WTID to pick, in case @a wtid_reference has - * many on offer. - */ - unsigned int index; - - /** - * Handle to a pending "track transfer" operation. - */ - struct TALER_EXCHANGE_TrackTransferHandle *tth; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * Checks what is returned by the "track transaction" operation. - * Checks that the HTTP response code is acceptable, and - if the - * right reference is non NULL - that the wire transfer subject - * line matches our expectations. - * - * @param cls closure. - * @param http_status HTTP status code we got. - * @param ec taler-specific error code. - * @param exchange_pub public key of the exchange - * @param json original json reply (may include signatures, those - * have then been validated already). - * @param wtid wire transfer identifier, NULL if exchange did not - * execute the transaction yet. - * @param execution_time actual or planned execution time for the - * wire transfer. - * @param coin_contribution contribution to the total amount of - * the deposited coin (can be NULL). - */ -static void -deposit_wtid_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const json_t *json, - const struct TALER_WireTransferIdentifierRawP *wtid, - struct GNUNET_TIME_Absolute execution_time, - const struct TALER_Amount *coin_contribution) -{ - struct TrackTransactionState *tts = cls; - struct TALER_TESTING_Interpreter *is = tts->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - - (void) coin_contribution; - (void) exchange_pub; - tts->tth = NULL; - if (tts->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - http_status, - cmd->label, - __FILE__, - __LINE__); - json_dumpf (json, stderr, 0); - TALER_TESTING_interpreter_fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - tts->wtid = *wtid; - if (NULL != tts->bank_transfer_reference) - { - const struct TALER_TESTING_Command *bank_transfer_cmd; - const struct TALER_WireTransferIdentifierRawP *wtid_want; - - /* _this_ wire transfer subject line. */ - bank_transfer_cmd = TALER_TESTING_interpreter_lookup_command - (is, tts->bank_transfer_reference); - if (NULL == bank_transfer_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_TESTING_get_trait_wtid - (bank_transfer_cmd, 0, &wtid_want)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - /* Compare that expected and gotten subjects match. */ - if (0 != GNUNET_memcmp (wtid, - wtid_want)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - } - break; - case MHD_HTTP_ACCEPTED: - /* allowed, nothing to check here */ - break; - case MHD_HTTP_NOT_FOUND: - /* allowed, nothing to check here */ - break; - default: - GNUNET_break (0); - break; - } - TALER_TESTING_interpreter_next (tts->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -track_transaction_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct TrackTransactionState *tts = cls; - const struct TALER_TESTING_Command *transaction_cmd; - const struct TALER_CoinSpendPrivateKeyP *coin_priv; - struct TALER_CoinSpendPublicKeyP coin_pub; - const json_t *contract_terms; - const json_t *wire_details; - struct GNUNET_HashCode h_wire_details; - struct GNUNET_HashCode h_contract_terms; - const struct TALER_MerchantPrivateKeyP *merchant_priv; - - tts->is = is; - transaction_cmd - = TALER_TESTING_interpreter_lookup_command (tts->is, - tts->transaction_reference); - if (NULL == transaction_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - - if (GNUNET_OK != - TALER_TESTING_get_trait_coin_priv (transaction_cmd, - tts->coin_index, - &coin_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - - GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, - &coin_pub.eddsa_pub); - - /* Get the strings.. */ - if (GNUNET_OK != - TALER_TESTING_get_trait_wire_details (transaction_cmd, - 0, - &wire_details)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - - if (GNUNET_OK != - TALER_TESTING_get_trait_contract_terms (transaction_cmd, - 0, - &contract_terms)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - - if ( (NULL == wire_details) || - (NULL == contract_terms) ) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - - /* Should not fail here, json has been parsed already */ - GNUNET_assert - ( (GNUNET_OK == - TALER_JSON_merchant_wire_signature_hash (wire_details, - &h_wire_details)) && - (GNUNET_OK == - TALER_JSON_hash (contract_terms, - &h_contract_terms)) ); - - if (GNUNET_OK != - TALER_TESTING_get_trait_merchant_priv (transaction_cmd, - 0, - &merchant_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - - tts->tth = TALER_EXCHANGE_track_transaction (is->exchange, - merchant_priv, - &h_wire_details, - &h_contract_terms, - &coin_pub, - &deposit_wtid_cb, - tts); - GNUNET_assert (NULL != tts->tth); -} - - -/** - * Cleanup the state from a "track transaction" CMD, and possibly - * cancel a operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -track_transaction_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct TrackTransactionState *tts = cls; - - if (NULL != tts->tth) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - tts->is->ip, - cmd->label); - TALER_EXCHANGE_track_transaction_cancel (tts->tth); - tts->tth = NULL; - } - GNUNET_free (tts); -} - - -/** - * Offer internal data from a "track transaction" CMD. - * - * @param cls closure. - * @param[out] ret result (could be anything). - * @param trait name of the trait. - * @param index index number of the object to offer. - * @return #GNUNET_OK on success. - */ -static int -track_transaction_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct TrackTransactionState *tts = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_wtid (0, &tts->wtid), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); -} - - -/** - * Create a "track transaction" command. - * - * @param label the command label. - * @param transaction_reference reference to a deposit operation, - * will be used to get the input data for the track. - * @param coin_index index of the coin involved in the transaction. - * @param expected_response_code expected HTTP response code. - * @param bank_transfer_reference reference to a command that - * can offer a WTID so as to check that against what WTID - * the tracked operation has. Set as NULL if not needed. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_track_transaction (const char *label, - const char *transaction_reference, - unsigned int coin_index, - unsigned int expected_response_code, - const char *bank_transfer_reference) -{ - struct TrackTransactionState *tts; - - tts = GNUNET_new (struct TrackTransactionState); - tts->transaction_reference = transaction_reference; - tts->expected_response_code = expected_response_code; - tts->bank_transfer_reference = bank_transfer_reference; - tts->coin_index = coin_index; - { - struct TALER_TESTING_Command cmd = { - .cls = tts, - .label = label, - .run = &track_transaction_run, - .cleanup = &track_transaction_cleanup, - .traits = &track_transaction_traits - }; - - return cmd; - } -} - - -/** - * Cleanup the state for a "track transfer" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -track_transfer_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - - struct TrackTransferState *tts = cls; - - if (NULL != tts->tth) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - tts->is->ip, - cmd->label); - TALER_EXCHANGE_track_transfer_cancel (tts->tth); - tts->tth = NULL; - } - GNUNET_free (tts); -} - - -/** - * Check whether the HTTP response code from a "track transfer" - * operation is acceptable, and all other values like total amount, - * wire fees and hashed wire details as well. - * - * @param cls closure. - * @param http_status HTTP status code we got. - * @param ec taler-specific error code. - * @param exchange_pub public key the exchange used for signing - * the response. - * @param json original json reply (may include signatures, those - * have then been validated already). - * @param h_wire hash of the wire transfer address the transfer - * went to, or NULL on error. - * @param execution_time time when the exchange claims to have - * performed the wire transfer. - * @param total_amount total amount of the wire transfer, or NULL - * if the exchange could not provide any @a wtid (set only - * if @a http_status is "200 OK"). - * @param wire_fee wire fee that was charged by the exchange. - * @param details_length length of the @a details array. - * @param details array with details about the combined - * transactions. - */ -static void -track_transfer_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const json_t *json, - const struct GNUNET_HashCode *h_wire, - struct GNUNET_TIME_Absolute execution_time, - const struct TALER_Amount *total_amount, - const struct TALER_Amount *wire_fee, - unsigned int details_length, - const struct TALER_TrackTransferDetails *details) -{ - struct TrackTransferState *tts = cls; - struct TALER_TESTING_Interpreter *is = tts->is; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - struct TALER_Amount expected_amount; - - (void) exchange_pub; - tts->tth = NULL; - if (tts->expected_response_code != http_status) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s in %s:%u\n", - http_status, - cmd->label, - __FILE__, - __LINE__); - json_dumpf (json, stderr, 0); - TALER_TESTING_interpreter_fail (is); - return; - } - - switch (http_status) - { - case MHD_HTTP_OK: - if (NULL == tts->expected_total_amount) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (NULL == tts->expected_wire_fee) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_string_to_amount (tts->expected_total_amount, - &expected_amount)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (0 != TALER_amount_cmp (total_amount, - &expected_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Total amount missmatch to command %s - " - "%s vs %s\n", - cmd->label, - TALER_amount_to_string (total_amount), - TALER_amount_to_string (&expected_amount)); - json_dumpf (json, stderr, 0); - fprintf (stderr, "\n"); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_string_to_amount (tts->expected_wire_fee, - &expected_amount)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (0 != TALER_amount_cmp (wire_fee, - &expected_amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fee missmatch to command %s\n", - cmd->label); - json_dumpf (json, stderr, 0); - TALER_TESTING_interpreter_fail (is); - return; - } - - /** - * Optionally checking: (1) wire-details for this transfer - * match the ones from a referenced "deposit" operation - - * or any operation that could provide wire-details. (2) - * Total amount for this transfer matches the one from any - * referenced command that could provide one. - */if (NULL != tts->wire_details_reference) - { - const struct TALER_TESTING_Command *wire_details_cmd; - const json_t *wire_details; - struct GNUNET_HashCode h_wire_details; - - if (NULL == (wire_details_cmd - = TALER_TESTING_interpreter_lookup_command - (is, tts->wire_details_reference))) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_TESTING_get_trait_wire_details (wire_details_cmd, - 0, - &wire_details)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_assert - (GNUNET_OK == - TALER_JSON_merchant_wire_signature_hash (wire_details, - &h_wire_details)); - - if (0 != GNUNET_memcmp (&h_wire_details, - h_wire)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire hash missmath to command %s\n", - cmd->label); - json_dumpf (json, stderr, 0); - TALER_TESTING_interpreter_fail (is); - return; - } - } - if (NULL != tts->total_amount_reference) - { - const struct TALER_TESTING_Command *total_amount_cmd; - const struct TALER_Amount *total_amount_from_reference; - - if (NULL == (total_amount_cmd - = TALER_TESTING_interpreter_lookup_command - (is, tts->total_amount_reference))) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (GNUNET_OK != - TALER_TESTING_get_trait_amount_obj (total_amount_cmd, - 0, - &total_amount_from_reference)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - if (0 != TALER_amount_cmp (total_amount, - total_amount_from_reference)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Amount missmath to command %s\n", - cmd->label); - json_dumpf (json, stderr, 0); - TALER_TESTING_interpreter_fail (is); - return; - } - } - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command under execution. - * @param is the interpreter state. - */ -static void -track_transfer_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - /* looking for a wtid to track .. */ - struct TrackTransferState *tts = cls; - struct TALER_WireTransferIdentifierRawP wtid; - const struct TALER_WireTransferIdentifierRawP *wtid_ptr; - - /* If no reference is given, we'll use a all-zeros - * WTID */ - memset (&wtid, 0, sizeof (wtid)); - wtid_ptr = &wtid; - - tts->is = is; - if (NULL != tts->wtid_reference) - { - const struct TALER_TESTING_Command *wtid_cmd; - - wtid_cmd = TALER_TESTING_interpreter_lookup_command - (tts->is, tts->wtid_reference); - - if (NULL == wtid_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - - if (GNUNET_OK != TALER_TESTING_get_trait_wtid - (wtid_cmd, tts->index, &wtid_ptr)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (tts->is); - return; - } - GNUNET_assert (NULL != wtid_ptr); - } - tts->tth = TALER_EXCHANGE_track_transfer (is->exchange, - wtid_ptr, - &track_transfer_cb, - tts); - GNUNET_assert (NULL != tts->tth); -} - - -/** - * Make a "track transfer" CMD where no "expected"-arguments, - * except the HTTP response code, are given. The best use case - * is when what matters to check is the HTTP response code, e.g. - * when a bogus WTID was passed. - * - * @param label the command label - * @param wtid_reference reference to any command which can provide - * a wtid. If NULL is given, then a all zeroed WTID is - * used that will at 99.9999% probability NOT match any - * existing WTID known to the exchange. - * @param index index number of the WTID to track, in case there - * are multiple on offer. - * @param expected_response_code expected HTTP response code. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_track_transfer_empty (const char *label, - const char *wtid_reference, - unsigned int index, - unsigned int expected_response_code) -{ - struct TrackTransferState *tts; - - tts = GNUNET_new (struct TrackTransferState); - tts->wtid_reference = wtid_reference; - tts->index = index; - tts->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = tts, - .label = label, - .run = &track_transfer_run, - .cleanup = &track_transfer_cleanup - }; - - return cmd; - } -} - - -/** - * Make a "track transfer" command, specifying which amount and - * wire fee are expected. - * - * @param label the command label. - * @param wtid_reference reference to any command which can provide - * a wtid. Will be the one tracked. - * @param index in case there are multiple WTID offered, this - * parameter selects a particular one. - * @param expected_response_code expected HTTP response code. - * @param expected_total_amount how much money we expect being moved - * with this wire-transfer. - * @param expected_wire_fee expected wire fee. - * @return the command - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_track_transfer (const char *label, - const char *wtid_reference, - unsigned int index, - unsigned int expected_response_code, - const char *expected_total_amount, - const char *expected_wire_fee) -{ - struct TrackTransferState *tts; - - tts = GNUNET_new (struct TrackTransferState); - tts->wtid_reference = wtid_reference; - tts->index = index; - tts->expected_response_code = expected_response_code; - tts->expected_total_amount = expected_total_amount; - tts->expected_wire_fee = expected_wire_fee; - { - struct TALER_TESTING_Command cmd = { - .cls = tts, - .label = label, - .run = &track_transfer_run, - .cleanup = &track_transfer_cleanup - }; - - return cmd; - } -} - - -/* end of testing_api_cmd_track.c */ diff --git a/src/lib/testing_api_cmd_wait.c b/src/lib/testing_api_cmd_wait.c deleted file mode 100644 index d153229ce..000000000 --- a/src/lib/testing_api_cmd_wait.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - This file is part of TALER - (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_wait.c - * @brief command(s) to wait on some process - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * Cleanup the state from a "wait service" CMD. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -wait_service_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - (void) cls; - (void) cmd; - /* nothing to clean. */ - return; -} - - -/** - * No traits to offer, just provide a stub to be called when - * some CMDs iterates through the list of all the commands. - * - * @param cls closure. - * @param[out] ret result. - * @param trait name of the trait. - * @param index index number of the trait to return. - * @return #GNUNET_OK on success. - */ -static int -wait_service_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - (void) cls; - (void) ret; - (void) trait; - (void) index; - return GNUNET_NO; -} - - -/** - * Run a "wait service" CMD. - * - * @param cls closure. - * @param cmd the command being run. - * @param is the interpreter state. - */ -static void -wait_service_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - unsigned int iter = 0; - const char *url = cmd->cls; - char *wget_cmd; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null", - url); - do - { - fprintf (stderr, "."); - - if (10 == iter++) - { - TALER_LOG_ERROR ("Could not reach the proxied service\n"); - TALER_TESTING_interpreter_fail (is); - GNUNET_free (wget_cmd); - return; - } - } - while (0 != system (wget_cmd)); - - GNUNET_free (wget_cmd); - TALER_TESTING_interpreter_next (is); -} - - -/** - * This CMD simply tries to connect via HTTP to the - * service addressed by @a url. It attemps 10 times - * before giving up and make the test fail. - * - * @param label label for the command. - * @param url complete URL to connect to. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_wait_service (const char *label, - const char *url) -{ - struct TALER_TESTING_Command cmd = { - .label = label, - .run = wait_service_run, - .cleanup = wait_service_cleanup, - .traits = wait_service_traits, - .cls = (void *) url - }; - - return cmd; -} - - -/* end of testing_api_cmd_sleep.c */ diff --git a/src/lib/testing_api_cmd_wire.c b/src/lib/testing_api_cmd_wire.c deleted file mode 100644 index e8bf176a6..000000000 --- a/src/lib/testing_api_cmd_wire.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_wire.c - * @brief command for testing /wire. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_testing_lib.h" - - -/** - * State for a "wire" CMD. - */ -struct WireState -{ - - /** - * Handle to the /wire operation. - */ - struct TALER_EXCHANGE_WireHandle *wh; - - /** - * Which wire-method we expect is offered by the exchange. - */ - const char *expected_method; - - /** - * Flag indicating if the expected method is actually - * offered. - */ - unsigned int method_found; - - /** - * Fee we expect is charged for this wire-transfer method. - */ - const char *expected_fee; - - /** - * Expected HTTP response code. - */ - unsigned int expected_response_code; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; -}; - - -/** - * Check whether the HTTP response code is acceptable, that - * the expected wire method is offered by the exchange, and - * that the wire fee is acceptable too. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param accounts_len length of the @a accounts array. - * @param accounts list of wire accounts of the exchange, - * NULL on error. - */ -static void -wire_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - unsigned int accounts_len, - const struct TALER_EXCHANGE_WireAccount *accounts) -{ - struct WireState *ws = cls; - struct TALER_TESTING_Command *cmd = \ - &ws->is->commands[ws->is->ip]; - struct TALER_Amount expected_fee; - - TALER_LOG_DEBUG ("Checking parsed /wire response\n"); - ws->wh = NULL; - if (ws->expected_response_code != http_status) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ws->is); - return; - } - - if (MHD_HTTP_OK == http_status) - { - for (unsigned int i = 0; iexpected_method, - method)) - { - ws->method_found = GNUNET_OK; - if (NULL != ws->expected_fee) - { - GNUNET_assert - (GNUNET_OK == - TALER_string_to_amount (ws->expected_fee, - &expected_fee)); - const struct TALER_EXCHANGE_WireAggregateFees *waf; - for (waf = accounts[i].fees; - NULL != waf; - waf = waf->next) - { - if (0 != TALER_amount_cmp (&waf->wire_fee, - &expected_fee)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fee missmatch to command %s\n", - cmd->label); - TALER_TESTING_interpreter_fail (ws->is); - GNUNET_free (method); - return; - } - } - } - } - TALER_LOG_DEBUG ("Freeing method '%s'\n", - method); - GNUNET_free (method); - } - if (GNUNET_OK != ws->method_found) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "/wire does not offer method '%s'\n", - ws->expected_method); - TALER_TESTING_interpreter_fail (ws->is); - return; - } - } - - TALER_TESTING_interpreter_next (ws->is); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -wire_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct WireState *ws = cls; - ws->is = is; - ws->wh = TALER_EXCHANGE_wire (is->exchange, - &wire_cb, - ws); -} - - -/** - * Cleanup the state of a "wire" CMD, and possibly cancel a - * pending operation thereof. - * - * @param cls closure. - * @param cmd the command which is being cleaned up. - */ -static void -wire_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct WireState *ws = cls; - - if (NULL != ws->wh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %u (%s) did not complete\n", - ws->is->ip, - cmd->label); - TALER_EXCHANGE_wire_cancel (ws->wh); - ws->wh = NULL; - } - GNUNET_free (ws); -} - - -/** - * Create a "wire" command. - * - * @param label the command label. - * @param expected_method which wire-transfer method is expected - * to be offered by the exchange. - * @param expected_fee the fee the exchange should charge. - * @param expected_response_code the HTTP response the exchange - * should return. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_wire (const char *label, - const char *expected_method, - const char *expected_fee, - unsigned int expected_response_code) -{ - struct WireState *ws; - - ws = GNUNET_new (struct WireState); - ws->expected_method = expected_method; - ws->expected_fee = expected_fee; - ws->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = ws, - .label = label, - .run = &wire_run, - .cleanup = &wire_cleanup - }; - - return cmd; - } -} diff --git a/src/lib/testing_api_cmd_withdraw.c b/src/lib/testing_api_cmd_withdraw.c deleted file mode 100644 index 3a834c07b..000000000 --- a/src/lib/testing_api_cmd_withdraw.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_cmd_withdraw.c - * @brief main interpreter loop for testcases - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" -#include "backoff.h" - - -/** - * State for a "withdraw" CMD. - */ -struct WithdrawState -{ - - /** - * Which reserve should we withdraw from? - */ - const char *reserve_reference; - - /** - * String describing the denomination value we should withdraw. - * A corresponding denomination key must exist in the exchange's - * offerings. Can be NULL if @e pk is set instead. - */ - struct TALER_Amount amount; - - /** - * If @e amount is NULL, this specifies the denomination key to - * use. Otherwise, this will be set (by the interpreter) to the - * denomination PK matching @e amount. - */ - struct TALER_EXCHANGE_DenomPublicKey *pk; - - /** - * Exchange base URL. Only used as offered trait. - */ - char *exchange_url; - - /** - * Interpreter state (during command). - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Set (by the interpreter) to the exchange's signature over the - * coin's public key. - */ - struct TALER_DenominationSignature sig; - - /** - * Private key material of the coin, set by the interpreter. - */ - struct TALER_PlanchetSecretsP ps; - - /** - * Withdraw handle (while operation is running). - */ - struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh; - - /** - * Task scheduled to try later. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * How long do we wait until we retry? - */ - struct GNUNET_TIME_Relative backoff; - - /** - * Expected HTTP response code to the request. - */ - unsigned int expected_response_code; - - /** - * Was this command modified via - * #TALER_TESTING_cmd_withdraw_with_retry to - * enable retries? - */ - int do_retry; -}; - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the commaind being run. - * @param is interpreter state. - */ -static void -withdraw_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is); - - -/** - * Task scheduled to re-try #withdraw_run. - * - * @param cls a `struct WithdrawState` - */ -static void -do_retry (void *cls) -{ - struct WithdrawState *ws = cls; - - ws->retry_task = NULL; - withdraw_run (ws, - NULL, - ws->is); -} - - -/** - * "reserve withdraw" operation callback; checks that the - * response code is expected and store the exchange signature - * in the state. - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - * @param sig signature over the coin, NULL on error. - * @param full_response raw response. - */ -static void -reserve_withdraw_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - const struct TALER_DenominationSignature *sig, - const json_t *full_response) -{ - struct WithdrawState *ws = cls; - struct TALER_TESTING_Interpreter *is = ws->is; - - ws->wsh = NULL; - if (ws->expected_response_code != http_status) - { - if (GNUNET_YES == ws->do_retry) - { - if ( (0 == http_status) || - (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || - (TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS == ec) || - (TALER_EC_WITHDRAW_RESERVE_UNKNOWN == ec) || - (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Retrying withdraw failed with %u/%d\n", - http_status, - (int) ec); - /* on DB conflicts, do not use backoff */ - if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) - ws->backoff = GNUNET_TIME_UNIT_ZERO; - else - ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff); - ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff, - &do_retry, - ws); - return; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d to command %s in %s:%u\n", - http_status, - (int) ec, - TALER_TESTING_interpreter_get_current_label (is), - __FILE__, - __LINE__); - json_dumpf (full_response, - stderr, - 0); - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - switch (http_status) - { - case MHD_HTTP_OK: - if (NULL == sig) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - ws->sig.rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); - break; - case MHD_HTTP_FORBIDDEN: - /* nothing to check */ - break; - case MHD_HTTP_CONFLICT: - /* nothing to check */ - break; - case MHD_HTTP_NOT_FOUND: - /* nothing to check */ - break; - default: - /* Unsupported status code (by test harness) */ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Withdraw test command does not support status code %u\n", - http_status); - GNUNET_break (0); - break; - } - TALER_TESTING_interpreter_next (is); -} - - -/** - * Run the command. - */ -static void -withdraw_run (void *cls, - const struct TALER_TESTING_Command *cmd, - struct TALER_TESTING_Interpreter *is) -{ - struct WithdrawState *ws = cls; - const struct TALER_ReservePrivateKeyP *rp; - const struct TALER_TESTING_Command *create_reserve; - const struct TALER_EXCHANGE_DenomPublicKey *dpk; - - (void) cmd; - create_reserve = TALER_TESTING_interpreter_lookup_command - (is, ws->reserve_reference); - if (NULL == create_reserve) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_priv (create_reserve, - 0, - &rp)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - TALER_planchet_setup_random (&ws->ps); - ws->is = is; - - dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange), - &ws->amount); - if (NULL == dpk) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to determine denomination key at %s\n", - (NULL != cmd) ? cmd->label : ""); - GNUNET_assert (0); - } - else - { - /* We copy the denomination key, as re-querying /keys - * would free the old one. */ - ws->pk = TALER_EXCHANGE_copy_denomination_key (dpk); - } - - ws->wsh = TALER_EXCHANGE_reserve_withdraw (is->exchange, - ws->pk, - rp, - &ws->ps, - &reserve_withdraw_cb, - ws); - if (NULL == ws->wsh) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } -} - - -/** - * Free the state of a "withdraw" CMD, and possibly cancel - * a pending operation thereof. - * - * @param cls closure. - * @param cmd the command being freed. - */ -static void -withdraw_cleanup (void *cls, - const struct TALER_TESTING_Command *cmd) -{ - struct WithdrawState *ws = cls; - - if (NULL != ws->wsh) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Command %s did not complete\n", - cmd->label); - TALER_EXCHANGE_reserve_withdraw_cancel (ws->wsh); - ws->wsh = NULL; - } - if (NULL != ws->retry_task) - { - GNUNET_SCHEDULER_cancel (ws->retry_task); - ws->retry_task = NULL; - } - if (NULL != ws->sig.rsa_signature) - { - GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature); - ws->sig.rsa_signature = NULL; - } - if (NULL != ws->pk) - { - TALER_EXCHANGE_destroy_denomination_key (ws->pk); - ws->pk = NULL; - } - GNUNET_free_non_null (ws->exchange_url); - GNUNET_free (ws); -} - - -/** - * Offer internal data to a "withdraw" CMD state to other - * commands. - * - * @param cls closure - * @param[out] ret result (could be anything) - * @param trait name of the trait - * @param index index number of the object to offer. - * @return #GNUNET_OK on success - */ -static int -withdraw_traits (void *cls, - const void **ret, - const char *trait, - unsigned int index) -{ - struct WithdrawState *ws = cls; - const struct TALER_TESTING_Command *reserve_cmd; - const struct TALER_ReservePrivateKeyP *reserve_priv; - const struct TALER_ReservePublicKeyP *reserve_pub; - - /* We offer the reserve key where these coins were withdrawn - * from. */ - reserve_cmd = TALER_TESTING_interpreter_lookup_command - (ws->is, ws->reserve_reference); - - if (NULL == reserve_cmd) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ws->is); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_priv (reserve_cmd, - 0, - &reserve_priv)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ws->is); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_TESTING_get_trait_reserve_pub (reserve_cmd, - 0, - &reserve_pub)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ws->is); - return GNUNET_SYSERR; - } - if (NULL == ws->exchange_url) - ws->exchange_url - = GNUNET_strdup (TALER_EXCHANGE_get_base_url (ws->is->exchange)); - { - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_coin_priv (0 /* only one coin */, - &ws->ps.coin_priv), - TALER_TESTING_make_trait_blinding_key (0 /* only one coin */, - &ws->ps.blinding_key), - TALER_TESTING_make_trait_denom_pub (0 /* only one coin */, - ws->pk), - TALER_TESTING_make_trait_denom_sig (0 /* only one coin */, - &ws->sig), - TALER_TESTING_make_trait_reserve_priv (0, - reserve_priv), - TALER_TESTING_make_trait_reserve_pub (0, - reserve_pub), - TALER_TESTING_make_trait_amount_obj (0, - &ws->amount), - TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, - ws->exchange_url), - TALER_TESTING_trait_end () - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); - } -} - - -/** - * Create a withdraw command, letting the caller specify - * the desired amount as string. - * - * @param label command label. - * @param reserve_reference command providing us with a reserve to withdraw from - * @param amount how much we withdraw. - * @param expected_response_code which HTTP response code - * we expect from the exchange. - * @return the withdraw command to be executed by the interpreter. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_withdraw_amount (const char *label, - const char *reserve_reference, - const char *amount, - unsigned int expected_response_code) -{ - struct WithdrawState *ws; - - ws = GNUNET_new (struct WithdrawState); - ws->reserve_reference = reserve_reference; - if (GNUNET_OK != - TALER_string_to_amount (amount, - &ws->amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %s\n", - amount, - label); - GNUNET_assert (0); - } - ws->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = ws, - .label = label, - .run = &withdraw_run, - .cleanup = &withdraw_cleanup, - .traits = &withdraw_traits - }; - - return cmd; - } -} - - -/** - * Create withdraw command, letting the caller specify the - * amount by a denomination key. - * - * @param label command label. - * @param reserve_reference reference to the reserve to withdraw - * from; will provide reserve priv to sign the request. - * @param dk denomination public key. - * @param expected_response_code expected HTTP response code. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_withdraw_denomination (const char *label, - const char *reserve_reference, - const struct - TALER_EXCHANGE_DenomPublicKey *dk, - unsigned int expected_response_code) -{ - struct WithdrawState *ws; - - if (NULL == dk) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Denomination key not specified at %s\n", - label); - GNUNET_assert (0); - } - ws = GNUNET_new (struct WithdrawState); - ws->reserve_reference = reserve_reference; - ws->pk = TALER_EXCHANGE_copy_denomination_key (dk); - ws->expected_response_code = expected_response_code; - { - struct TALER_TESTING_Command cmd = { - .cls = ws, - .label = label, - .run = &withdraw_run, - .cleanup = &withdraw_cleanup, - .traits = &withdraw_traits - }; - - return cmd; - } -} - - -/** - * Modify a withdraw command to enable retries when the - * reserve is not yet full or we get other transient - * errors from the exchange. - * - * @param cmd a withdraw command - * @return the command with retries enabled - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd) -{ - struct WithdrawState *ws; - - GNUNET_assert (&withdraw_run == cmd.run); - ws = cmd.cls; - ws->do_retry = GNUNET_YES; - return cmd; -} - - -/* end of testing_api_cmd_withdraw.c */ diff --git a/src/lib/testing_api_helpers_auditor.c b/src/lib/testing_api_helpers_auditor.c deleted file mode 100644 index 26585f5b9..000000000 --- a/src/lib/testing_api_helpers_auditor.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_helpers_auditor.c - * @brief helper functions - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_testing_lib.h" -#include "taler_auditor_service.h" - - -/** - * Closure for #cleanup_auditor. - */ -struct CleanupContext -{ - /** - * Where we find the state to clean up. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Next cleanup routine to call, NULL for none. - */ - GNUNET_SCHEDULER_TaskCallback fcb; - - /** - * Closure for @e fcb - */ - void *fcb_cls; -}; - - -/** - * Function to clean up the auditor connection. - * - * @param cls a `struct CleanupContext` - */ -static void -cleanup_auditor (void *cls) -{ - struct CleanupContext *cc = cls; - struct TALER_TESTING_Interpreter *is = cc->is; - - TALER_AUDITOR_disconnect (is->auditor); - is->auditor = NULL; - if (NULL != cc->fcb) - cc->fcb (cc->fcb_cls); - GNUNET_free (cc); -} - - -/** - * Closure for #auditor_main_wrapper() - */ -struct MainWrapperContext -{ - /** - * Main function to launch. - */ - TALER_TESTING_Main main_cb; - - /** - * Closure for @e main_cb. - */ - void *main_cb_cls; - - /** - * Configuration we use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * Name of the configuration file. - */ - const char *config_filename; - -}; - - -/** - * Function called with information about the auditor. - * - * @param cls closure - * @param vi basic information about the auditor - * @param compat protocol compatibility information - */ -static void -auditor_version_cb (void *cls, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat) -{ - struct TALER_TESTING_Interpreter *is = cls; - - if (TALER_AUDITOR_VC_MATCH != compat) - { - TALER_TESTING_interpreter_fail (is); - return; - } - - is->auditor_working = GNUNET_YES; -} - - -/** - * Setup the @a is 'auditor' member before running the main test loop. - * - * @param cls must be a `struct MainWrapperContext *` - * @param[in,out] is interpreter state to setup - */ -static void -auditor_main_wrapper (void *cls, - struct TALER_TESTING_Interpreter *is) -{ - struct MainWrapperContext *mwc = cls; - struct CleanupContext *cc; - char *auditor_base_url; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (mwc->cfg, - "auditor", - "BASE_URL", - &auditor_base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "BASE_URL"); - return; - } - - is->auditor = TALER_AUDITOR_connect (is->ctx, - auditor_base_url, - &auditor_version_cb, - is); - GNUNET_free (auditor_base_url); - - if (NULL == is->auditor) - { - GNUNET_break (0); - return; - } - - cc = GNUNET_new (struct CleanupContext); - cc->is = is; - cc->fcb = is->final_cleanup_cb; - cc->fcb_cls = is->final_cleanup_cb_cls; - is->final_cleanup_cb = cleanup_auditor; - is->final_cleanup_cb_cls = cc; - mwc->main_cb (mwc->main_cb_cls, - is); -} - - -/** - * Install signal handlers plus schedules the main wrapper - * around the "run" method. - * - * @param cls our `struct MainWrapperContext` - * @param cfg configuration we use - * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. - * non-GNUNET_OK codes are #GNUNET_SYSERR most of the - * times. - */ -static int -setup_with_cfg (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct MainWrapperContext *mwc = cls; - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = mwc->config_filename, - .main_cb = &auditor_main_wrapper, - .main_cb_cls = mwc - }; - - mwc->cfg = cfg; - return TALER_TESTING_setup_with_auditor_and_exchange_cfg (&setup_ctx, - cfg); -} - - -/** - * Install signal handlers plus schedules the main wrapper - * around the "run" method. - * - * @param main_cb the "run" method which contains all the - * commands. - * @param main_cb_cls a closure for "run", typically NULL. - * @param config_filename configuration filename. - * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. - * non-GNUNET_OK codes are #GNUNET_SYSERR most of the - * times. - */ -int -TALER_TESTING_auditor_setup (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_filename) -{ - struct MainWrapperContext mwc = { - .main_cb = main_cb, - .main_cb_cls = main_cb_cls, - .config_filename = config_filename - }; - - return GNUNET_CONFIGURATION_parse_and_run (config_filename, - &setup_with_cfg, - &mwc); -} - - -/* end of testing_auditor_api_helpers.c */ diff --git a/src/lib/testing_api_helpers_bank.c b/src/lib/testing_api_helpers_bank.c deleted file mode 100644 index c8a780ac6..000000000 --- a/src/lib/testing_api_helpers_bank.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_helpers_bank.c - * @brief convenience functions for bank tests. - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" - -#define BANK_FAIL() \ - do {GNUNET_break (0); return NULL; } while (0) - - -/** - * Runs the Fakebank by guessing / extracting the portnumber - * from the base URL. - * - * @param bank_url bank's base URL. - * @return the fakebank process handle, or NULL if any - * error occurs. - */ -struct TALER_FAKEBANK_Handle * -TALER_TESTING_run_fakebank (const char *bank_url) -{ - const char *port; - long pnum; - struct TALER_FAKEBANK_Handle *fakebankd; - - port = strrchr (bank_url, - (unsigned char) ':'); - if (NULL == port) - pnum = 80; - else - pnum = strtol (port + 1, NULL, 10); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting Fakebank on port %u (%s)\n", - (unsigned int) pnum, - bank_url); - fakebankd = TALER_FAKEBANK_start ((uint16_t) pnum); - if (NULL == fakebankd) - { - GNUNET_break (0); - return NULL; - } - return fakebankd; -} - - -/** - * Look for substring in a programs' name. - * - * @param prog program's name to look into - * @param marker chunk to find in @a prog - * @return #GNUNET_YES if @a marker is present, otherwise #GNUNET_NO - */ -int -TALER_TESTING_has_in_name (const char *prog, - const char *marker) -{ - size_t name_pos; - size_t pos; - - if (! prog || ! marker) - return GNUNET_NO; - - pos = 0; - name_pos = 0; - while (prog[pos]) - { - if ('/' == prog[pos]) - name_pos = pos + 1; - pos++; - } - if (name_pos == pos) - return GNUNET_YES; - return (NULL != strstr (prog + name_pos, marker)); -} - - -/** - * Start the (Python) bank process. Assume the port - * is available and the database is clean. Use the "prepare - * bank" function to do such tasks. - * - * @param config_filename configuration filename. - * @param bank_url base URL of the bank, used by `wget' to check - * that the bank was started right. - * @return the process, or NULL if the process could not - * be started. - */ -struct GNUNET_OS_Process * -TALER_TESTING_run_bank (const char *config_filename, - const char *bank_url) -{ - struct GNUNET_OS_Process *bank_proc; - unsigned int iter; - char *wget_cmd; - char *database; - char *serve_cfg; - char *serve_arg; - struct GNUNET_CONFIGURATION_Handle *cfg; - - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != - GNUNET_CONFIGURATION_load (cfg, - config_filename)) - { - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - exit (77); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "bank", - "database", - &database)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "bank", - "database"); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - exit (77); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "bank", - "serve", - &serve_cfg)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "bank", - "serve"); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (database); - exit (77); - } - GNUNET_CONFIGURATION_destroy (cfg); - - serve_arg = "serve-http"; - if (0 != strcmp ("http", serve_cfg)) - serve_arg = "serve-uwsgi"; - GNUNET_free (serve_cfg); - bank_proc = GNUNET_OS_start_process - (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-bank-manage-testing", - "taler-bank-manage-testing", - config_filename, - database, - serve_arg, NULL); - GNUNET_free (database); - if (NULL == bank_proc) - { - BANK_FAIL (); - } - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 2 -T 1 %s -o /dev/null -O /dev/null", - bank_url); - - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `taler-bank-manage' to be ready (via %s)\n", wget_cmd); - iter = 0; - do - { - if (10 == iter) - { - fprintf ( - stderr, - "Failed to launch `taler-bank-manage' (or `wget')\n"); - GNUNET_OS_process_kill (bank_proc, - SIGTERM); - GNUNET_OS_process_wait (bank_proc); - GNUNET_OS_process_destroy (bank_proc); - GNUNET_free (wget_cmd); - BANK_FAIL (); - } - fprintf (stderr, "."); - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - fprintf (stderr, "\n"); - - return bank_proc; - -} - - -/** - * Prepare the bank execution. Check if the port is available - * and reset database. - * - * @param config_filename configuration file name. - * @param config_section section of the configuration with the exchange's account - * @param[out] bc set to the bank's configuration data - * @return the base url, or NULL upon errors. Must be freed - * by the caller. - */ -int -TALER_TESTING_prepare_bank (const char *config_filename, - const char *config_section, - struct TALER_TESTING_BankConfiguration *bc) -{ - struct GNUNET_CONFIGURATION_Handle *cfg; - unsigned long long port; - struct GNUNET_OS_Process *dbreset_proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - char *database; - char *exchange_payto_uri; - - cfg = GNUNET_CONFIGURATION_create (); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_load (cfg, config_filename)) - { - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "bank", - "DATABASE", - &database)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "bank", - "DATABASE"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - config_section, - "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */ - &exchange_payto_uri)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - config_section, - "URL"); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "bank", - "HTTP_PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "bank", - "HTTP_PORT"); - GNUNET_CONFIGURATION_destroy (cfg); - GNUNET_free (database); - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - fprintf (stderr, - "Required port %llu not available, skipping.\n", - port); - GNUNET_break (0); - GNUNET_free (database); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - - /* DB preparation */ - if (NULL == - (dbreset_proc = GNUNET_OS_start_process ( - GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-bank-manage", - "taler-bank-manage", - "-c", config_filename, - "--with-db", database, - "django", - "flush", - "--no-input", NULL))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to flush the bank db.\n"); - GNUNET_free (database); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - GNUNET_free (database); - - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (dbreset_proc, - &type, - &code)) - { - GNUNET_OS_process_destroy (dbreset_proc); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - fprintf (stderr, - "Failed to setup database\n"); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error running `taler-bank-manage django flush'!\n"); - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (dbreset_proc); - if (GNUNET_OK != - TALER_BANK_auth_parse_cfg (cfg, - config_section, - &bc->exchange_auth)) - { - GNUNET_break (0); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - GNUNET_CONFIGURATION_destroy (cfg); - bc->exchange_payto = exchange_payto_uri; - bc->user42_payto = "payto://x-taler-bank/localhost/42"; - bc->user43_payto = "payto://x-taler-bank/localhost/43"; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Using pybank %s on port %u\n", - bc->exchange_auth.wire_gateway_url, - (unsigned int) port); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n", - bc->exchange_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", - bc->user42_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", - bc->user43_payto); - return GNUNET_OK; -} - - -/** - * Prepare launching a fakebank. Check that the configuration - * file has the right option, and that the port is available. - * If everything is OK, return the configuration data of the fakebank. - * - * @param config_filename configuration file to use - * @param config_section which account to use (must match x-taler-bank) - * @param[out] bc set to the bank's configuration data - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_prepare_fakebank (const char *config_filename, - const char *config_section, - struct TALER_TESTING_BankConfiguration *bc) -{ - struct GNUNET_CONFIGURATION_Handle *cfg; - unsigned long long fakebank_port; - char *exchange_payto_uri; - - cfg = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, - config_filename)) - return GNUNET_SYSERR; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "BANK", - "HTTP_PORT", - &fakebank_port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "BANK", - "HTTP_PORT"); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - config_section, - "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */ - &exchange_payto_uri)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - config_section, - "URL"); - GNUNET_CONFIGURATION_destroy (cfg); - return GNUNET_SYSERR; - } - bc->exchange_auth.method = TALER_BANK_AUTH_NONE; - { - char *exchange_xtalerbank_account; - - exchange_xtalerbank_account - = TALER_xtalerbank_account_from_payto (exchange_payto_uri); - if (NULL == exchange_xtalerbank_account) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - GNUNET_asprintf (&bc->exchange_auth.wire_gateway_url, - "http://localhost:%u/%s/", - (unsigned int) fakebank_port, - exchange_xtalerbank_account); - GNUNET_free (exchange_xtalerbank_account); - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Using fakebank %s on port %u\n", - bc->exchange_auth.wire_gateway_url, - (unsigned int) fakebank_port); - - GNUNET_CONFIGURATION_destroy (cfg); - if (GNUNET_OK != - TALER_TESTING_url_port_free (bc->exchange_auth.wire_gateway_url)) - { - GNUNET_free (bc->exchange_auth.wire_gateway_url); - bc->exchange_auth.wire_gateway_url = NULL; - return GNUNET_SYSERR; - } - /* Now we know it's the fake bank, for purpose of authentication, we - * don't have any auth. */ - bc->exchange_auth.method = TALER_BANK_AUTH_NONE; - bc->exchange_payto = exchange_payto_uri; - bc->user42_payto = "payto://x-taler-bank/localhost/42"; - bc->user43_payto = "payto://x-taler-bank/localhost/43"; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n", - bc->exchange_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", - bc->user42_payto); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", - bc->user43_payto); - return GNUNET_OK; -} - - -/** - * Allocate and return a piece of wire-details. Combines - * a @a payto -URL and adds some salt to create the JSON. - * - * @param payto payto://-URL to encapsulate - * @return JSON describing the account, including the - * payto://-URL of the account, must be manually decref'd - */ -json_t * -TALER_TESTING_make_wire_details (const char *payto) -{ - return json_pack ("{s:s, s:s}", - "url", payto, - "salt", - "test-salt (must be constant for aggregation tests)"); -} - - -/* end of testing_api_helpers_bank.c */ diff --git a/src/lib/testing_api_helpers_exchange.c b/src/lib/testing_api_helpers_exchange.c deleted file mode 100644 index 5979fc015..000000000 --- a/src/lib/testing_api_helpers_exchange.c +++ /dev/null @@ -1,976 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/testing_api_helpers_exchange.c - * @brief helper functions - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * Remove files from previous runs - * - * @param config_name configuration filename. - */ -void -TALER_TESTING_cleanup_files (const char *config_name) -{ - if (GNUNET_OK != - GNUNET_CONFIGURATION_parse_and_run (config_name, - &TALER_TESTING_cleanup_files_cfg, - NULL)) - exit (77); -} - - -/** - * Remove files from previous runs - * - * @param cls NULL - * @param cfg configuration - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_cleanup_files_cfg (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - char *dir; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "exchange", - "KEYDIR", - &dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "KEYDIR"); - return GNUNET_SYSERR; - } - if (GNUNET_YES == - GNUNET_DISK_directory_test (dir, - GNUNET_NO)) - GNUNET_break (GNUNET_OK == - GNUNET_DISK_directory_remove (dir)); - GNUNET_free (dir); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "exchange", - "REVOCATION_DIR", - &dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "REVOCATION_DIR"); - return GNUNET_SYSERR; - } - if (GNUNET_YES == - GNUNET_DISK_directory_test (dir, - GNUNET_NO)) - GNUNET_break (GNUNET_OK == - GNUNET_DISK_directory_remove (dir)); - GNUNET_free (dir); - return GNUNET_OK; -} - - -/** - * Run `taler-exchange-keyup`. - * - * @param config_filename configuration file to use - * @param output_filename where to write the output for the auditor - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_run_keyup (const char *config_filename, - const char *output_filename) -{ - struct GNUNET_OS_Process *proc; - - proc = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-keyup", - "taler-exchange-keyup", - "-c", config_filename, - "-o", output_filename, - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-exchange-keyup`, is your PATH correct?\n"); - return GNUNET_SYSERR; - } - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_destroy (proc); - return GNUNET_OK; -} - - -/** - * Run `taler-auditor-sign`. - * - * @param config_filename configuration file to use - * @param exchange_master_pub master public key of the exchange - * @param auditor_base_url what is the base URL of the auditor - * @param signdata_in where is the information from taler-exchange-keyup - * @param signdata_out where to write the output for the exchange - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_run_auditor_sign (const char *config_filename, - const char *exchange_master_pub, - const char *auditor_base_url, - const char *signdata_in, - const char *signdata_out) -{ - struct GNUNET_OS_Process *proc; - - proc = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-sign", - "taler-auditor-sign", - "-c", config_filename, - "-u", auditor_base_url, - "-m", exchange_master_pub, - "-r", signdata_in, - "-o", signdata_out, - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-sign`, is your PATH correct?\n"); - return GNUNET_SYSERR; - } - GNUNET_OS_process_wait (proc); - GNUNET_OS_process_destroy (proc); - return GNUNET_OK; -} - - -/** - * Run `taler-auditor-exchange`. - * - * @param config_filename configuration file to use - * @param exchange_master_pub master public key of the exchange - * @param exchange_base_url what is the base URL of the exchange - * @param do_remove #GNUNET_NO to add exchange, #GNUNET_YES to remove - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_run_auditor_exchange (const char *config_filename, - const char *exchange_master_pub, - const char *exchange_base_url, - int do_remove) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - TALER_LOG_DEBUG ("Add exchange (%s,%s) to the auditor\n", - exchange_base_url, - exchange_master_pub); - - proc = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-exchange", - "taler-auditor-exchange", - "-c", config_filename, - "-u", exchange_base_url, - "-m", exchange_master_pub, - (GNUNET_YES == do_remove) - ? "-r" - : NULL, - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-exchange`, is your PATH correct?\n"); - return GNUNET_SYSERR; - } - GNUNET_assert (GNUNET_OK == - GNUNET_OS_process_wait_status (proc, - &type, - &code)); - GNUNET_OS_process_destroy (proc); - if ( (0 != code) || - (GNUNET_OS_PROCESS_EXITED != type) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "taler-auditor-exchange terminated with error (%d/%d)\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Run `taler-exchange-dbinit -r` (reset exchange database). - * - * @param config_filename configuration file to use - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_exchange_db_reset (const char *config_filename) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - proc = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-dbinit", - "taler-exchange-dbinit", - "-c", config_filename, - "-r", - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n"); - return GNUNET_NO; - } - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (proc, - &type, - &code)) - { - GNUNET_break (0); - GNUNET_OS_process_destroy (proc); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (proc); - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to setup (exchange) database, exit code %d\n", - (int) code); - return GNUNET_NO; - } - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error (%d/%d) running `taler-exchange-dbinit'!\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Run `taler-auditor-dbinit -r` (reset auditor database). - * - * @param config_filename configuration file to use - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_auditor_db_reset (const char *config_filename) -{ - struct GNUNET_OS_Process *proc; - enum GNUNET_OS_ProcessStatusType type; - unsigned long code; - - proc = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-dbinit", - "taler-auditor-dbinit", - "-c", config_filename, - "-r", - NULL); - if (NULL == proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to run `taler-auditor-dbinit`, is your PATH correct?\n"); - return GNUNET_NO; - } - if (GNUNET_SYSERR == - GNUNET_OS_process_wait_status (proc, - &type, - &code)) - { - GNUNET_break (0); - GNUNET_OS_process_destroy (proc); - return GNUNET_SYSERR; - } - GNUNET_OS_process_destroy (proc); - if ( (type == GNUNET_OS_PROCESS_EXITED) && - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to setup (auditor) database, exit code %d\n", - (int) code); - return GNUNET_NO; - } - if ( (type != GNUNET_OS_PROCESS_EXITED) || - (0 != code) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected error (%d/%d) running `taler-auditor-dbinit'!\n", - (int) type, - (int) code); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Type of closure for - * #sign_keys_for_exchange. - */ -struct SignInfo -{ - /** - * Members will be set to the exchange configuration. - */ - struct TALER_TESTING_ExchangeConfiguration *ec; - - /** - * Name of the configuration file to use. - */ - const char *config_filename; - - /** - * Must be set to input file with the data to be signed before - * calling #TALER_TESTING_sign_keys_for_exchange. - */ - const char *auditor_sign_input_filename; -}; - - -/** - * Sign the keys for an exchange given configuration @a cfg. - * The information to be signed must be in a file "auditor.in". - * - * @param[in,out] cls a `struct SignInfo` with further paramters - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -static int -sign_keys_for_exchange (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct SignInfo *si = cls; - char *test_home_dir; - char *signed_keys_out; - char *exchange_master_pub; - int ret; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &si->ec->exchange_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "exchange", - "BASE_URL"); - si->ec->exchange_url = NULL; - return GNUNET_NO; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "BASE_URL", - &si->ec->auditor_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "auditor", - "BASE_URL"); - GNUNET_free (si->ec->exchange_url); - si->ec->exchange_url = NULL; - si->ec->auditor_url = NULL; - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "paths", - "TALER_TEST_HOME", - &test_home_dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "paths", - "TALER_TEST_HOME"); - ret = GNUNET_SYSERR; - goto fail; - } - - GNUNET_asprintf (&signed_keys_out, - "%s/.local/share/taler/auditors/auditor.out", - test_home_dir); - GNUNET_free (test_home_dir); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "MASTER_PUBLIC_KEY", - &exchange_master_pub)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "MASTER_PUBLIC_KEY"); - GNUNET_free (signed_keys_out); - ret = GNUNET_SYSERR; - goto fail; - } - if (GNUNET_OK != - TALER_TESTING_run_auditor_exchange (si->config_filename, - exchange_master_pub, - si->ec->exchange_url, - GNUNET_NO)) - { - GNUNET_free (signed_keys_out); - ret = GNUNET_NO; - goto fail; - } - - if (GNUNET_OK != - TALER_TESTING_run_auditor_sign (si->config_filename, - exchange_master_pub, - si->ec->auditor_url, - si->auditor_sign_input_filename, - signed_keys_out)) - { - GNUNET_free (signed_keys_out); - GNUNET_free (exchange_master_pub); - ret = GNUNET_NO; - goto fail; - } - GNUNET_free (signed_keys_out); - GNUNET_free (exchange_master_pub); - return GNUNET_OK; -fail: - GNUNET_free (si->ec->exchange_url); - GNUNET_free (si->ec->auditor_url); - si->ec->exchange_url = NULL; - si->ec->auditor_url = NULL; - return ret; -} - - -/** - * Prepare launching an exchange. Checks that the configured - * port is available, runs taler-exchange-keyup, - * taler-auditor-sign and taler-exchange-dbinit. Does NOT - * launch the exchange process itself. - * - * @param config_filename configuration file to use - * @param[out] ec will be set to the exchange configuration data - * @return #GNUNET_OK on success, #GNUNET_NO if test should be - * skipped, #GNUNET_SYSERR on test failure - */ -int -TALER_TESTING_prepare_exchange (const char *config_filename, - struct TALER_TESTING_ExchangeConfiguration *ec) -{ - struct SignInfo si = { - .config_filename = config_filename, - .ec = ec, - .auditor_sign_input_filename = "auditor.in" - }; - - if (GNUNET_OK != - TALER_TESTING_run_keyup (config_filename, - si.auditor_sign_input_filename)) - return GNUNET_NO; - if (GNUNET_OK != - TALER_TESTING_exchange_db_reset (config_filename)) - return GNUNET_NO; - if (GNUNET_OK != - TALER_TESTING_auditor_db_reset (config_filename)) - return GNUNET_NO; - if (GNUNET_OK != - GNUNET_CONFIGURATION_parse_and_run (config_filename, - &sign_keys_for_exchange, - &si)) - return GNUNET_NO; - return GNUNET_OK; -} - - -/** - * Find denomination key matching the given amount. - * - * @param keys array of keys to search - * @param amount coin value to look for - * @return NULL if no matching key was found - */ -const struct TALER_EXCHANGE_DenomPublicKey * -TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_Amount *amount) -{ - struct GNUNET_TIME_Absolute now; - struct TALER_EXCHANGE_DenomPublicKey *pk; - char *str; - - now = GNUNET_TIME_absolute_get (); - for (unsigned int i = 0; inum_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; inum_denom_keys; i++) - { - pk = &keys->denom_keys[i]; - if ( (0 == TALER_amount_cmp (amount, - &pk->value)) && - ( (now.abs_value_us < pk->valid_from.abs_value_us) || - (now.abs_value_us > - pk->withdraw_valid_until.abs_value_us) ) ) - { - GNUNET_log - (GNUNET_ERROR_TYPE_WARNING, - "Have denomination key for `%s', but with wrong" - " expiration range %llu vs [%llu,%llu)\n", - str, - (unsigned long long) now.abs_value_us, - (unsigned long long) pk->valid_from.abs_value_us, - (unsigned long long) - pk->withdraw_valid_until.abs_value_us); - GNUNET_free (str); - return NULL; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No denomination key for amount %s found\n", - str); - GNUNET_free (str); - return NULL; -} - - -/** - * Wait for the exchange to have started. Waits for at - * most 10s, after that returns 77 to indicate an error. - * - * @param base_url what URL should we expect the exchange - * to be running at - * @return 0 on success - */ -int -TALER_TESTING_wait_exchange_ready (const char *base_url) -{ - char *wget_cmd; - unsigned int iter; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %skeys -o /dev/null -O /dev/null", - base_url); // make sure ends with '/' - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `taler-exchange-httpd' to be ready (check with: %s)\n", - wget_cmd); - iter = 0; - do - { - if (10 == iter) - { - fprintf (stderr, - "Failed to launch `taler-exchange-httpd' (or `wget')\n"); - GNUNET_free (wget_cmd); - return 77; - } - fprintf (stderr, ".\n"); - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - return 0; -} - - -/** - * Wait for the auditor to have started. Waits for at - * most 10s, after that returns 77 to indicate an error. - * - * @param base_url what URL should we expect the auditor - * to be running at - * @return 0 on success - */ -int -TALER_TESTING_wait_auditor_ready (const char *base_url) -{ - char *wget_cmd; - unsigned int iter; - - GNUNET_asprintf (&wget_cmd, - "wget -q -t 1 -T 1 %sversion -o /dev/null -O /dev/null", - base_url); // make sure ends with '/' - /* give child time to start and bind against the socket */ - fprintf (stderr, - "Waiting for `taler-auditor-httpd' to be ready\n"); - iter = 0; - do - { - if (10 == iter) - { - fprintf (stderr, - "Failed to launch `taler-auditor-httpd' (or `wget')\n"); - GNUNET_free (wget_cmd); - return 77; - } - fprintf (stderr, ".\n"); - sleep (1); - iter++; - } - while (0 != system (wget_cmd)); - GNUNET_free (wget_cmd); - return 0; -} - - -/** - * Initialize scheduler loop and curl context for the testcase - * including starting and stopping the exchange using the given - * configuration file. - * - * @param main_cb routine containing all the commands to run. - * @param main_cb_cls closure for @a main_cb, typically NULL. - * @param config_file configuration file for the test-suite. - * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. - * non-#GNUNET_OK codes are #GNUNET_SYSERR most of the - * time. - */ -int -TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_file) -{ - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = config_file, - .main_cb = main_cb, - .main_cb_cls = main_cb_cls - }; - int result; - - result = - GNUNET_CONFIGURATION_parse_and_run (config_file, - &TALER_TESTING_setup_with_exchange_cfg, - &setup_ctx); - if (GNUNET_OK != result) - return result; - return GNUNET_OK; -} - - -/** - * Initialize scheduler loop and curl context for the test case - * including starting and stopping the exchange using the given - * configuration file. - * - * @param cls must be a `struct TALER_TESTING_SetupContext *` - * @param cfg configuration to use. - * @return #GNUNET_OK if no errors occurred. - */ -int -TALER_TESTING_setup_with_exchange_cfg (void *cls, - const struct - GNUNET_CONFIGURATION_Handle *cfg) -{ - const struct TALER_TESTING_SetupContext *setup_ctx = cls; - struct GNUNET_OS_Process *exchanged; - unsigned long long port; - char *serve; - char *base_url; - int result; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "SERVE", - &serve)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "SERVE"); - return GNUNET_NO; - } - - if (0 == strcmp ("tcp", serve)) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "exchange", - "PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "PORT"); - GNUNET_free (serve); - return GNUNET_NO; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Required port %llu not available, skipping.\n", - port); - GNUNET_free (serve); - return GNUNET_NO; - } - } - GNUNET_free (serve); - exchanged = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-exchange-httpd", - "taler-exchange-httpd", - "-c", setup_ctx->config_filename, - "-i", - NULL); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "BASE_URL"); - return GNUNET_NO; - } - - if (0 != TALER_TESTING_wait_exchange_ready (base_url)) - { - GNUNET_free (base_url); - return 77; - } - GNUNET_free (base_url); - - /* NOTE: this call blocks. */ - result = TALER_TESTING_setup (setup_ctx->main_cb, - setup_ctx->main_cb_cls, - setup_ctx->config_filename, - exchanged, - GNUNET_YES); - GNUNET_break (0 == - GNUNET_OS_process_kill (exchanged, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (exchanged)); - GNUNET_OS_process_destroy (exchanged); - return result; -} - - -/** - * Initialize scheduler loop and curl context for the test case - * including starting and stopping the auditor and exchange using the - * given configuration file. - * - * @param cls must be a `struct TALER_TESTING_SetupContext *` - * @param cfg configuration to use. - * @return #GNUNET_OK if no errors occurred. - */ -int -TALER_TESTING_setup_with_auditor_and_exchange_cfg (void *cls, - const struct - GNUNET_CONFIGURATION_Handle * - cfg) -{ - const struct TALER_TESTING_SetupContext *setup_ctx = cls; - struct GNUNET_OS_Process *auditord; - unsigned long long port; - char *serve; - char *base_url; - int result; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "SERVE", - &serve)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "SERVE"); - return GNUNET_NO; - } - - if (0 == strcmp ("tcp", serve)) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - "auditor", - "PORT", - &port)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "PORT"); - GNUNET_free (serve); - return GNUNET_NO; - } - - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - (uint16_t) port)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Required port %llu not available, skipping.\n", - port); - GNUNET_free (serve); - return GNUNET_NO; - } - } - GNUNET_free (serve); - auditord = GNUNET_OS_start_process (GNUNET_NO, - GNUNET_OS_INHERIT_STD_ALL, - NULL, NULL, NULL, - "taler-auditor-httpd", - "taler-auditor-httpd", - "-c", setup_ctx->config_filename, - NULL); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "auditor", - "BASE_URL", - &base_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "auditor", - "BASE_URL"); - return GNUNET_NO; - } - - if (0 != TALER_TESTING_wait_auditor_ready (base_url)) - { - GNUNET_free (base_url); - GNUNET_break (0 == - GNUNET_OS_process_kill (auditord, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (auditord)); - GNUNET_OS_process_destroy (auditord); - return 77; - } - GNUNET_free (base_url); - - /* NOTE: this call blocks. */ - result = TALER_TESTING_setup_with_exchange_cfg ((void *) setup_ctx, - cfg); - GNUNET_break (0 == - GNUNET_OS_process_kill (auditord, - SIGTERM)); - GNUNET_break (GNUNET_OK == - GNUNET_OS_process_wait (auditord)); - GNUNET_OS_process_destroy (auditord); - return result; -} - - -/** - * Initialize scheduler loop and curl context for the test case - * including starting and stopping the auditor and exchange using the - * given configuration file. - * - * @param main_cb main method. - * @param main_cb_cls main method closure. - * @param config_file configuration file name. Is is used - * by both this function and the exchange itself. In the - * first case it gives out the exchange port number and - * the exchange base URL so as to check whether the port - * is available and the exchange responds when requested - * at its base URL. - * @return #GNUNET_OK if no errors occurred. - */ -int -TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_file) -{ - struct TALER_TESTING_SetupContext setup_ctx = { - .config_filename = config_file, - .main_cb = main_cb, - .main_cb_cls = main_cb_cls - }; - - return GNUNET_CONFIGURATION_parse_and_run (config_file, - & - TALER_TESTING_setup_with_auditor_and_exchange_cfg, - &setup_ctx); -} - - -/** - * Test port in URL string for availability. - * - * @param url URL to extract port from, 80 is default - * @return #GNUNET_OK if the port is free - */ -int -TALER_TESTING_url_port_free (const char *url) -{ - const char *port; - long pnum; - - port = strrchr (url, - (unsigned char) ':'); - if (NULL == port) - pnum = 80; - else - pnum = strtol (port + 1, NULL, 10); - if (GNUNET_OK != - GNUNET_NETWORK_test_port_free (IPPROTO_TCP, - pnum)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Port %u not available.\n", - (unsigned int) pnum); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/* end of testing_api_helpers_exchange.c */ diff --git a/src/lib/testing_api_loop.c b/src/lib/testing_api_loop.c deleted file mode 100644 index 06151d02c..000000000 --- a/src/lib/testing_api_loop.c +++ /dev/null @@ -1,829 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/testing_api_loop.c - * @brief main interpreter loop for testcases - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" - -/** - * Pipe used to communicate child death via signal. - * Must be global, as used in signal handler! - */ -static struct GNUNET_DISK_PipeHandle *sigpipe; - -/** - * Lookup command by label. - * - * @param is interpreter state to search - * @param label label to look for - * @return NULL if command was not found - */ -const struct TALER_TESTING_Command * -TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is, - const char *label) -{ - if (NULL == label) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Attempt to lookup command for empty label\n"); - return NULL; - } - /* Search backwards as we most likely reference recent commands */ - for (int i = is->ip; i >= 0; i--) - { - const struct TALER_TESTING_Command *cmd = &is->commands[i]; - - /* Give precedence to top-level commands. */ - if ( (NULL != cmd->label) && - (0 == strcmp (cmd->label, - label)) ) - return cmd; - - if (TALER_TESTING_cmd_is_batch (cmd)) - { -#define BATCH_INDEX 1 - struct TALER_TESTING_Command *batch; - - GNUNET_assert (GNUNET_OK == - TALER_TESTING_get_trait_cmd (cmd, - BATCH_INDEX, - &batch)); - for (unsigned int j = 0; - NULL != (cmd = &batch[j])->label; - j++) - { - if ( (NULL != cmd->label) && - (0 == strcmp (cmd->label, - label)) ) - return cmd; - } - } - } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Command not found: %s\n", - label); - return NULL; - -} - - -/** - * Obtain main execution context for the main loop. - */ -struct GNUNET_CURL_Context * -TALER_TESTING_interpreter_get_context - (struct TALER_TESTING_Interpreter *is) -{ - return is->ctx; -} - - -struct TALER_FAKEBANK_Handle * -TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is) -{ - return is->fakebank; -} - - -/** - * Run tests starting the "fakebank" first. The "fakebank" - * is a C minimalist version of the human-oriented Python bank, - * which is also part of the Taler project. - * - * @param is pointer to the interpreter state - * @param commands the list of commands to execute - * @param bank_url the url the fakebank is supposed to run on - */ -void -TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is, - struct TALER_TESTING_Command *commands, - const char *bank_url) -{ - const char *port; - long pnum; - - port = strrchr (bank_url, - (unsigned char) ':'); - if (NULL == port) - pnum = 80; - else - pnum = strtol (port + 1, NULL, 10); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting Fakebank on port %u (%s)\n", - (unsigned int) pnum, - bank_url); - is->fakebank = TALER_FAKEBANK_start ((uint16_t) pnum); - if (NULL == is->fakebank) - { - GNUNET_break (0); - is->result = GNUNET_SYSERR; - return; - } - TALER_TESTING_run (is, - commands); -} - - -/** - * Run the main interpreter loop that performs exchange operations. - * - * @param cls contains the `struct InterpreterState` - */ -static void -interpreter_run (void *cls); - - -/** - * Current command is done, run the next one. - */ -void -TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is) -{ - static unsigned long long ipc; - static struct GNUNET_TIME_Absolute last_report; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - - if (GNUNET_SYSERR == is->result) - return; /* ignore, we already failled! */ - if (TALER_TESTING_cmd_is_batch (cmd)) - TALER_TESTING_cmd_batch_next (is); - else - is->ip++; - if (0 == (ipc % 1000)) - { - if (0 != ipc) - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - "Interpreter executed 1000 instructions in %s\n", - GNUNET_STRINGS_relative_time_to_string ( - GNUNET_TIME_absolute_get_duration (last_report), - GNUNET_YES)); - last_report = GNUNET_TIME_absolute_get (); - } - ipc++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Current command failed, clean up and fail the test case. - * - * @param is interpreter of the test - */ -void -TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is) -{ - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed at command `%s'\n", - cmd->label); - while (TALER_TESTING_cmd_is_batch (cmd)) - { - cmd = TALER_TESTING_cmd_batch_get_current (cmd); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Batch is at command `%s'\n", - cmd->label); - } - is->result = GNUNET_SYSERR; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Create command array terminator. - * - * @return a end-command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_end (void) -{ - static struct TALER_TESTING_Command cmd; - cmd.label = NULL; - - return cmd; -} - - -/** - * Obtain current label. - */ -const char * -TALER_TESTING_interpreter_get_current_label (struct - TALER_TESTING_Interpreter *is) -{ - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - - return cmd->label; -} - - -/** - * Run the main interpreter loop that performs exchange operations. - * - * @param cls contains the `struct TALER_TESTING_Interpreter` - */ -static void -interpreter_run (void *cls) -{ - struct TALER_TESTING_Interpreter *is = cls; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - - is->task = NULL; - - if (NULL == cmd->label) - { - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Running command END\n"); - is->result = GNUNET_OK; - GNUNET_SCHEDULER_shutdown (); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Running command `%s'\n", - cmd->label); - - cmd->run (cmd->cls, - cmd, - is); -} - - -/** - * Function run when the test terminates (good or bad). - * Cleans up our state. - * - * @param cls the interpreter state. - */ -static void -do_shutdown (void *cls) -{ - struct TALER_TESTING_Interpreter *is = cls; - struct TALER_TESTING_Command *cmd; - const char *label; - - label = is->commands[is->ip].label; - if (NULL == label) - label = "END"; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Executing shutdown at `%s'\n", - label); - - for (unsigned int j = 0; - NULL != (cmd = &is->commands[j])->label; - j++) - cmd->cleanup (cmd->cls, - cmd); - - if (NULL != is->exchange) - { - TALER_LOG_DEBUG ("Disconnecting the exchange\n"); - TALER_EXCHANGE_disconnect (is->exchange); - is->exchange = NULL; - } - if (NULL != is->task) - { - GNUNET_SCHEDULER_cancel (is->task); - is->task = NULL; - } - if (NULL != is->ctx) - { - GNUNET_CURL_fini (is->ctx); - is->ctx = NULL; - } - if (NULL != is->rc) - { - GNUNET_CURL_gnunet_rc_destroy (is->rc); - is->rc = NULL; - } - if (NULL != is->timeout_task) - { - GNUNET_SCHEDULER_cancel (is->timeout_task); - is->timeout_task = NULL; - } - if (NULL != is->child_death_task) - { - GNUNET_SCHEDULER_cancel (is->child_death_task); - is->child_death_task = NULL; - } - if (NULL != is->fakebank) - { - TALER_FAKEBANK_stop (is->fakebank); - is->fakebank = NULL; - } - GNUNET_free_non_null (is->commands); -} - - -/** - * Function run when the test terminates (good or bad) with timeout. - * - * @param cls NULL - */ -static void -do_timeout (void *cls) -{ - struct TALER_TESTING_Interpreter *is = cls; - - is->timeout_task = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Terminating test due to timeout\n"); - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Task triggered whenever we receive a SIGCHLD (child - * process died). - * - * @param cls closure - */ -static void -maint_child_death (void *cls) -{ - struct TALER_TESTING_Interpreter *is = cls; - struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; - const struct GNUNET_DISK_FileHandle *pr; - - struct GNUNET_OS_Process **processp; - char c[16]; - - if (TALER_TESTING_cmd_is_batch (cmd)) - { - struct TALER_TESTING_Command *batch_cmd; - - GNUNET_assert - (GNUNET_OK == TALER_TESTING_get_trait_cmd - (cmd, 0, &batch_cmd)); /* bad? */ - cmd = batch_cmd; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got SIGCHLD for `%s'.\n", - cmd->label); - - is->child_death_task = NULL; - pr = GNUNET_DISK_pipe_handle (sigpipe, - GNUNET_DISK_PIPE_END_READ); - GNUNET_break (0 < - GNUNET_DISK_file_read (pr, - &c, - sizeof (c))); - if (GNUNET_OK != - TALER_TESTING_get_trait_process (cmd, - 0, - &processp)) - { - GNUNET_break (0); - TALER_TESTING_interpreter_fail (is); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got the dead child process handle" - ", waiting for termination ...\n"); - - GNUNET_OS_process_wait (*processp); - GNUNET_OS_process_destroy (*processp); - *processp = NULL; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "... definitively terminated\n"); - - if (GNUNET_OK == is->reload_keys) - { - if (NULL == is->exchanged) - { - GNUNET_break (0); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Triggering key state reload at exchange\n"); - GNUNET_break (0 == GNUNET_OS_process_kill - (is->exchanged, SIGUSR1)); - sleep (5); /* make sure signal was received and processed */ - } - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Dead child, go on with next command.\n"); - TALER_TESTING_interpreter_next (is); -} - - -/** - * Wait until we receive SIGCHLD signal. - * Then obtain the process trait of the current - * command, wait on the the zombie and continue - * with the next command. - */ -void -TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is) -{ - const struct GNUNET_DISK_FileHandle *pr; - - GNUNET_assert (NULL == is->child_death_task); - pr = GNUNET_DISK_pipe_handle (sigpipe, - GNUNET_DISK_PIPE_END_READ); - is->child_death_task - = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, - pr, - &maint_child_death, - is); -} - - -/** - * Run the testsuite. Note, CMDs are copied into - * the interpreter state because they are _usually_ - * defined into the "run" method that returns after - * having scheduled the test interpreter. - * - * @param is the interpreter state - * @param commands the list of command to execute - * @param timeout how long to wait - */ -void -TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is, - struct TALER_TESTING_Command *commands, - struct GNUNET_TIME_Relative timeout) -{ - unsigned int i; - - if (NULL != is->timeout_task) - { - GNUNET_SCHEDULER_cancel (is->timeout_task); - is->timeout_task = NULL; - } - /* get the number of commands */ - for (i = 0; NULL != commands[i].label; i++) - ; - is->commands = GNUNET_new_array (i + 1, - struct TALER_TESTING_Command); - memcpy (is->commands, - commands, - sizeof (struct TALER_TESTING_Command) * i); - is->timeout_task = GNUNET_SCHEDULER_add_delayed - (timeout, - &do_timeout, - is); - GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is); - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is); -} - - -/** - * Run the testsuite. Note, CMDs are copied into - * the interpreter state because they are _usually_ - * defined into the "run" method that returns after - * having scheduled the test interpreter. - * - * @param is the interpreter state - * @param commands the list of command to execute - */ -void -TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, - struct TALER_TESTING_Command *commands) -{ - TALER_TESTING_run2 (is, - commands, - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, - 5)); -} - - -/** - * Information used by the wrapper around the main - * "run" method. - */ -struct MainContext -{ - /** - * Main "run" method. - */ - TALER_TESTING_Main main_cb; - - /** - * Closure for @e main_cb. - */ - void *main_cb_cls; - - /** - * Interpreter state. - */ - struct TALER_TESTING_Interpreter *is; - - /** - * Configuration filename. The wrapper uses it to fetch - * the exchange port number; We could have passed the port - * number here, but having the config filename seems more - * generic. - */ - const char *config_filename; - - /** - * URL of the exchange. - */ - char *exchange_url; - -}; - - -/** - * Signal handler called for SIGCHLD. Triggers the - * respective handler by writing to the trigger pipe. - */ -static void -sighandler_child_death () -{ - static char c; - int old_errno = errno; /* back-up errno */ - - GNUNET_break (1 == GNUNET_DISK_file_write - (GNUNET_DISK_pipe_handle (sigpipe, - GNUNET_DISK_PIPE_END_WRITE), - &c, sizeof (c))); - errno = old_errno; /* restore errno */ -} - - -/** - * "Canonical" cert_cb used when we are connecting to the - * Exchange. - * - * @param cls closure, typically, the "run" method containing - * all the commands to be run, and a closure for it. - * @param keys the exchange's keys. - * @param compat protocol compatibility information. - */ -void -TALER_TESTING_cert_cb (void *cls, - const struct TALER_EXCHANGE_Keys *keys, - enum TALER_EXCHANGE_VersionCompatibility compat) -{ - struct MainContext *main_ctx = cls; - struct TALER_TESTING_Interpreter *is = main_ctx->is; - - if (NULL == keys) - { - if (GNUNET_NO == is->working) - { - GNUNET_log - (GNUNET_ERROR_TYPE_WARNING, - "Got NULL response for /keys" - " during startup, retrying!\n"); - TALER_EXCHANGE_disconnect (is->exchange); - GNUNET_assert - (NULL != (is->exchange = TALER_EXCHANGE_connect - (is->ctx, - main_ctx->exchange_url, - &TALER_TESTING_cert_cb, - main_ctx, - TALER_EXCHANGE_OPTION_END))); - return; - } - else - GNUNET_log - (GNUNET_ERROR_TYPE_ERROR, - "Got NULL response for /keys" - " during execution!\n"); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got %d DK from /keys in generation %u\n", - keys->num_denom_keys, - is->key_generation + 1); - } - is->key_generation++; - is->keys = keys; - - /* /keys has been called for some reason and - * the interpreter is already running. */ - if (GNUNET_YES == is->working) - return; - - is->working = GNUNET_YES; - - /* Very first start of tests, call "run()" */ - if (1 == is->key_generation) - { - main_ctx->main_cb (main_ctx->main_cb_cls, - is); - return; - } - - /* Tests already started, just trigger the - * next command. */ - TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n", - is->ip); - GNUNET_SCHEDULER_add_now (&interpreter_run, - is); -} - - -/** - * Initialize scheduler loop and curl context for the testcase, - * and responsible to run the "run" method. - * - * @param cls closure, typically the "run" method, the - * interpreter state and a closure for "run". - */ -static void -main_wrapper_exchange_agnostic (void *cls) -{ - struct MainContext *main_ctx = cls; - - main_ctx->main_cb (main_ctx->main_cb_cls, - main_ctx->is); -} - - -/** - * Function run when the test is aborted before we launch the actual - * interpreter. Cleans up our state. - * - * @param cls the main context - */ -static void -do_abort (void *cls) -{ - struct MainContext *main_ctx = cls; - struct TALER_TESTING_Interpreter *is = main_ctx->is; - - is->timeout_task = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Executing abort prior to interpreter launch\n"); - if (NULL != is->exchange) - { - TALER_EXCHANGE_disconnect (is->exchange); - is->exchange = NULL; - } -} - - -/** - * Initialize scheduler loop and curl context for the testcase, - * and responsible to run the "run" method. - * - * @param cls a `struct MainContext *` - * @param cfg configuration to use - */ -static int -main_exchange_connect_with_cfg (void *cls, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct MainContext *main_ctx = cls; - struct TALER_TESTING_Interpreter *is = main_ctx->is; - char *exchange_url; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - "exchange", - "BASE_URL", - &exchange_url)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "BASE_URL"); - return GNUNET_SYSERR; - } - main_ctx->exchange_url = exchange_url; - is->cfg = cfg; - is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort, - main_ctx); - GNUNET_break - (NULL != (is->exchange = TALER_EXCHANGE_connect - (is->ctx, - exchange_url, - &TALER_TESTING_cert_cb, - main_ctx, - TALER_EXCHANGE_OPTION_END))); - is->cfg = NULL; - return GNUNET_OK; -} - - -/** - * Initialize scheduler loop and curl context for the testcase, - * and responsible to run the "run" method. - * - * @param cls a `struct MainContext *` - */ -static void -main_wrapper_exchange_connect (void *cls) -{ - struct MainContext *main_ctx = cls; - - GNUNET_break (GNUNET_OK == - GNUNET_CONFIGURATION_parse_and_run (main_ctx->config_filename, - & - main_exchange_connect_with_cfg, - main_ctx)); -} - - -/** - * Install signal handlers plus schedules the main wrapper - * around the "run" method. - * - * @param main_cb the "run" method which contains all the - * commands. - * @param main_cb_cls a closure for "run", typically NULL. - * @param config_filename configuration filename. - * @param exchanged exchange process handle: will be put in the - * state as some commands - e.g. revoke - need to send - * signal to it, for example to let it know to reload the - * key state.. if NULL, the interpreter will run without - * trying to connect to the exchange first. - * @param exchange_connect #GNUNET_YES if the test should connect - * to the exchange, #GNUNET_NO otherwise - * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. - * non-GNUNET_OK codes are #GNUNET_SYSERR most of the - * times. - */ -int -TALER_TESTING_setup (TALER_TESTING_Main main_cb, - void *main_cb_cls, - const char *config_filename, - struct GNUNET_OS_Process *exchanged, - int exchange_connect) -{ - struct TALER_TESTING_Interpreter is; - struct MainContext main_ctx = { - .main_cb = main_cb, - .main_cb_cls = main_cb_cls, - /* needed to init the curl ctx */ - .is = &is, - /* needed to read values like exchange port - * number to construct the exchange url.*/ - .config_filename = config_filename - }; - struct GNUNET_SIGNAL_Context *shc_chld; - - memset (&is, - 0, - sizeof (is)); - is.exchanged = exchanged; - sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, - GNUNET_NO, GNUNET_NO); - GNUNET_assert (NULL != sigpipe); - shc_chld = GNUNET_SIGNAL_handler_install - (GNUNET_SIGCHLD, - &sighandler_child_death); - is.ctx = GNUNET_CURL_init - (&GNUNET_CURL_gnunet_scheduler_reschedule, - &is.rc); - GNUNET_CURL_enable_async_scope_header (is.ctx, "Taler-Correlation-Id"); - GNUNET_assert (NULL != is.ctx); - is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx); - - /* Blocking */ - - if (GNUNET_YES == exchange_connect) - GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect, - &main_ctx); - else - GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic, - &main_ctx); - if (NULL != is.final_cleanup_cb) - is.final_cleanup_cb (is.final_cleanup_cb_cls); - GNUNET_free_non_null (main_ctx.exchange_url); - GNUNET_SIGNAL_handler_uninstall (shc_chld); - GNUNET_DISK_pipe_close (sigpipe); - sigpipe = NULL; - return is.result; -} - - -/* end of testing_api_loop.c */ diff --git a/src/lib/testing_api_trait_amount.c b/src/lib/testing_api_trait_amount.c deleted file mode 100644 index b33259e5d..000000000 --- a/src/lib/testing_api_trait_amount.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 - -*/ -/** - * @file lib/testing_api_trait_amount.c - * @brief offer amounts as traits. - * @author Marcello Stanisci - */ - -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_AMOUNT "amount" - -/** - * Obtain an amount from a @a cmd. - * - * @param cmd command to extract the amount from. - * @param index which amount to pick if @a cmd has multiple - * on offer - * @param[out] amount set to the amount. - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_get_trait_amount_obj (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_Amount **amount) -{ - return cmd->traits (cmd->cls, - (const void **) amount, - TALER_TESTING_TRAIT_AMOUNT, - index); -} - - -/** - * Offer amount. - * - * @param index which amount to offer, in case there are - * multiple available. - * @param amount the amount to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_amount_obj (unsigned int index, - const struct TALER_Amount *amount) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_AMOUNT, - .ptr = (const void *) amount - }; - - return ret; -} - - -/* end of testing_api_trait_amount.c */ diff --git a/src/lib/testing_api_trait_blinding_key.c b/src/lib/testing_api_trait_blinding_key.c deleted file mode 100644 index f20116870..000000000 --- a/src/lib/testing_api_trait_blinding_key.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 - -*/ -/** - * @file lib/testing_api_trait_blinding_key.c - * @brief offer blinding keys as traits. - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_BLINDING_KEY "blinding-key" - - -/** - * Obtain a blinding key from a @a cmd. - * - * @param cmd command to extract trait from - * @param index which coin to pick if @a cmd has multiple on offer. - * @param[out] blinding_key set to the offered blinding key. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_blinding_key - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_DenominationBlindingKeyP **blinding_key) -{ - return cmd->traits (cmd->cls, - (const void **) blinding_key, - TALER_TESTING_TRAIT_BLINDING_KEY, - index); -} - - -/** - * Offer blinding key. - * - * @param index index number to associate to the offered key. - * @param blinding_key blinding key to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_blinding_key - (unsigned int index, - const struct TALER_DenominationBlindingKeyP *blinding_key) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_BLINDING_KEY, - .ptr = (const void *) blinding_key - }; - - return ret; -} - - -/* end of testing_api_trait_blinding_key.c */ diff --git a/src/lib/testing_api_trait_cmd.c b/src/lib/testing_api_trait_cmd.c deleted file mode 100644 index 7982f8e8d..000000000 --- a/src/lib/testing_api_trait_cmd.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/testing_api_trait_cmd.c - * @brief offers CMDs as traits. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_CMD "cmd" - - -/** - * Obtain a command from @a cmd. - * - * @param cmd command to extract the command from. - * @param index always zero. Commands offering this - * kind of traits do not need this index. For - * example, a "batch" CMD returns always the - * CMD currently being executed. - * @param[out] _cmd where to write the wire details. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_cmd (const struct TALER_TESTING_Command *cmd, - unsigned int index, - struct TALER_TESTING_Command **_cmd) -{ - return cmd->traits (cmd->cls, - (const void **) _cmd, - TALER_TESTING_TRAIT_CMD, - index); -} - - -/** - * Offer a command in a trait. - * - * @param index always zero. Commands offering this - * kind of traits do not need this index. For - * example, a "meta" CMD returns always the - * CMD currently being executed. - * @param cmd wire details to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_cmd (unsigned int index, - const struct TALER_TESTING_Command *cmd) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_CMD, - .ptr = (const struct TALER_TESTING_Command *) cmd - }; - return ret; -} - - -/* end of testing_api_trait_cmd.c */ diff --git a/src/lib/testing_api_trait_coin_priv.c b/src/lib/testing_api_trait_coin_priv.c deleted file mode 100644 index a8b496e77..000000000 --- a/src/lib/testing_api_trait_coin_priv.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 - -*/ - -/** - * @file lib/testing_api_trait_coin_priv.c - * @brief coin priv traits. - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_COIN_PRIVATE_KEY "coin-private-key" - - -/** - * Obtain a coin private key from a @a cmd. - * - * @param cmd command to extract trait from. - * @param index index of the coin priv to obtain. - * @param[out] coin_priv set to the private key of the coin. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_coin_priv - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_CoinSpendPrivateKeyP **coin_priv) -{ - return cmd->traits (cmd->cls, - (const void **) coin_priv, - TALER_TESTING_TRAIT_COIN_PRIVATE_KEY, - index); -} - - -/** - * Offer coin private key. - * - * @param index index number to associate with offered coin priv. - * @param coin_priv coin private key to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_coin_priv - (unsigned int index, - const struct TALER_CoinSpendPrivateKeyP *coin_priv) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_COIN_PRIVATE_KEY, - .ptr = (const void *) coin_priv - }; - - return ret; -} - - -/* end of testing_api_trait_coin_priv.c */ diff --git a/src/lib/testing_api_trait_contract.c b/src/lib/testing_api_trait_contract.c deleted file mode 100644 index 0fe741774..000000000 --- a/src/lib/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 - -*/ -/** - * @file lib/testing_api_trait_contract.c - * @brief offers contract term trait. - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "taler_testing_lib.h" - - -/** - * Contains a contract terms object as a json_t. - */ -#define TALER_TESTING_TRAIT_CONTRACT_TERMS "contract-terms" - - -/** - * Obtain contract terms from @a cmd. - * - * @param cmd command to extract the contract terms from. - * @param index contract terms index number. - * @param[out] contract_terms where to write the contract terms. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_contract_terms (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const json_t **contract_terms) -{ - return cmd->traits (cmd->cls, - (const void **) contract_terms, - TALER_TESTING_TRAIT_CONTRACT_TERMS, - index); -} - - -/** - * Offer contract terms. - * - * @param index contract terms index number. - * @param contract_terms contract terms to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_contract_terms (unsigned int index, - const json_t *contract_terms) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_CONTRACT_TERMS, - .ptr = (const void *) contract_terms - }; - return ret; -} diff --git a/src/lib/testing_api_trait_denom_pub.c b/src/lib/testing_api_trait_denom_pub.c deleted file mode 100644 index 7217495c6..000000000 --- a/src/lib/testing_api_trait_denom_pub.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 - -*/ -/** - * @file lib/testing_api_trait_denom_pub.c - * @brief denom pub traits. - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_DENOM_PUB "denomination-public-key" - - -/** - * Obtain a denomination public key from a @a cmd. - * - * @param cmd command to extract trait from - * @param index index number of the denom to obtain. - * @param[out] denom_pub set to the offered denom pub. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_denom_pub (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct - TALER_EXCHANGE_DenomPublicKey **denom_pub) -{ - return cmd->traits (cmd->cls, - (const void **) denom_pub, - TALER_TESTING_TRAIT_DENOM_PUB, - index); -} - - -/** - * Make a trait for a denomination public key. - * - * @param index index number to associate to the offered denom pub. - * @param denom_pub denom pub to offer with this trait. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_denom_pub (unsigned int index, - const struct - TALER_EXCHANGE_DenomPublicKey *denom_pub) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_DENOM_PUB, - .ptr = (const void *) denom_pub - }; - - return ret; -} - - -/* end of testing_api_trait_denom_pub.c */ diff --git a/src/lib/testing_api_trait_denom_sig.c b/src/lib/testing_api_trait_denom_sig.c deleted file mode 100644 index 9f6e2b984..000000000 --- a/src/lib/testing_api_trait_denom_sig.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 - -*/ - -/** - * @file lib/testing_api_trait_denom_sig.c - * @brief offer denomination signatures as traits - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_DENOM_SIG "denomination-signature" - - -/** - * Obtain a denomination signature from a @a cmd. - * - * @param cmd command to extract the denom sig from. - * @param index index number associated with the denom sig. - * @param[out] denom_sig set to the offered signature. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_denom_sig - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_DenominationSignature **denom_sig) -{ - return cmd->traits (cmd->cls, - (const void **) denom_sig, - TALER_TESTING_TRAIT_DENOM_SIG, - index); -} - - -/** - * Offer denom sig. - * - * @param index index number to associate to the signature on - * offer. - * @param denom_sig the denom sig on offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_denom_sig - (unsigned int index, - const struct TALER_DenominationSignature *denom_sig) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_DENOM_SIG, - .ptr = (const void *) denom_sig - }; - - return ret; -} - - -/* end of testing_api_trait_denom_sig.c */ diff --git a/src/lib/testing_api_trait_exchange_pub.c b/src/lib/testing_api_trait_exchange_pub.c deleted file mode 100644 index a7fc215e2..000000000 --- a/src/lib/testing_api_trait_exchange_pub.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 - -*/ -/** - * @file lib/testing_api_trait_exchange_pub.c - * @brief exchange pub traits. - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_EXCHANGE_PUB "exchange-public-key" - - -/** - * Obtain a exchange public key from a @a cmd. - * - * @param cmd command to extract trait from - * @param index index number of the exchange to obtain. - * @param[out] exchange_pub set to the offered exchange pub. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_exchange_pub - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_ExchangePublicKeyP **exchange_pub) -{ - return cmd->traits (cmd->cls, - (const void **) exchange_pub, - TALER_TESTING_TRAIT_EXCHANGE_PUB, - index); -} - - -/** - * Make a trait for a exchange public key. - * - * @param index index number to associate to the offered exchange pub. - * @param exchange_pub exchange pub to offer with this trait. - * - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_exchange_pub - (unsigned int index, - const struct TALER_ExchangePublicKeyP *exchange_pub) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_EXCHANGE_PUB, - .ptr = (const void *) exchange_pub - }; - - return ret; -} - - -/* end of testing_api_trait_exchange_pub.c */ diff --git a/src/lib/testing_api_trait_exchange_sig.c b/src/lib/testing_api_trait_exchange_sig.c deleted file mode 100644 index ffb084a54..000000000 --- a/src/lib/testing_api_trait_exchange_sig.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 - -*/ -/** - * @file lib/testing_api_trait_exchange_sig.c - * @brief exchange pub traits. - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_EXCHANGE_SIG "exchange-online-signature" - - -/** - * Obtain a exchange signature (online sig) from a @a cmd. - * - * @param cmd command to extract trait from - * @param index index number of the exchange to obtain. - * @param[out] exchange_sig set to the offered exchange signature. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_exchange_sig - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_ExchangeSignatureP **exchange_sig) -{ - return cmd->traits (cmd->cls, - (const void **) exchange_sig, - TALER_TESTING_TRAIT_EXCHANGE_SIG, - index); -} - - -/** - * Make a trait for a exchange signature. - * - * @param index index number to associate to the offered exchange pub. - * @param exchange_sig exchange signature to offer with this trait. - * - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_exchange_sig - (unsigned int index, - const struct TALER_ExchangeSignatureP *exchange_sig) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_EXCHANGE_SIG, - .ptr = (const void *) exchange_sig - }; - - return ret; -} - - -/* end of testing_api_trait_exchange_sig.c */ diff --git a/src/lib/testing_api_trait_fresh_coin.c b/src/lib/testing_api_trait_fresh_coin.c deleted file mode 100644 index 48a57d26f..000000000 --- a/src/lib/testing_api_trait_fresh_coin.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 - -*/ -/** - * @file lib/testing_api_trait_fresh_coin.c - * @brief traits to offer fresh conins (after "melt" operations) - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_FRESH_COINS "fresh-coins" - -/** - * Get a array of fresh coins. - * - * @param cmd command to extract the fresh coin from. - * @param index which array to pick if @a cmd has multiple - * on offer. - * @param[out] fresh_coins will point to the offered array. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_fresh_coins - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_TESTING_FreshCoinData **fresh_coins) -{ - return cmd->traits (cmd->cls, - (const void **) fresh_coins, - TALER_TESTING_TRAIT_FRESH_COINS, - index); -} - - -/** - * Offer a _array_ of fresh coins. - * - * @param index which array of fresh coins to offer, - * if there are multiple on offer. Typically passed as - * zero. - * @param fresh_coins the array of fresh coins to offer - * @return the trait, - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_fresh_coins - (unsigned int index, - const struct TALER_TESTING_FreshCoinData *fresh_coins) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_FRESH_COINS, - .ptr = (const void *) fresh_coins - }; - return ret; -} - - -/* end of testing_api_trait_fresh_coin.c */ diff --git a/src/lib/testing_api_trait_json.c b/src/lib/testing_api_trait_json.c deleted file mode 100644 index f7739aa8e..000000000 --- a/src/lib/testing_api_trait_json.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/testing_api_trait_json.c - * @brief offers JSON traits. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_WIRE_DETAILS "wire-details" -#define TALER_TESTING_TRAIT_EXCHANGE_KEYS "exchange-keys" - -/** - * Obtain serialized exchange keys from @a cmd. - * - * @param cmd command to extract the keys from. - * @param index index number associate with the keys on offer. - * @param[out] keys where to write the serialized keys. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_exchange_keys - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const json_t **keys) -{ - return cmd->traits (cmd->cls, - (const void **) keys, - TALER_TESTING_TRAIT_EXCHANGE_KEYS, - index); -} - - -/** - * Offer serialized keys in a trait. - * - * @param index index number associate with the serial keys - * on offer. - * @param keys serialized keys to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_exchange_keys - (unsigned int index, - const json_t *keys) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_EXCHANGE_KEYS, - .ptr = (const json_t *) keys - }; - return ret; -} - - -/** - * Obtain wire details from @a cmd. - * - * @param cmd command to extract the wire details from. - * @param index index number associate with the wire details - * on offer; usually zero, as one command sticks to - * one bank account. - * @param[out] wire_details where to write the wire details. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_wire_details - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const json_t **wire_details) -{ - return cmd->traits (cmd->cls, - (const void **) wire_details, - TALER_TESTING_TRAIT_WIRE_DETAILS, - index); -} - - -/** - * Offer wire details in a trait. - * - * @param index index number associate with the wire details - * on offer; usually zero, as one command sticks to - * one bank account. - * @param wire_details wire details to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_wire_details - (unsigned int index, - const json_t *wire_details) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS, - .ptr = (const json_t *) wire_details - }; - return ret; -} - - -/* end of testing_api_trait_json.c */ diff --git a/src/lib/testing_api_trait_merchant_key.c b/src/lib/testing_api_trait_merchant_key.c deleted file mode 100644 index 1657560d3..000000000 --- a/src/lib/testing_api_trait_merchant_key.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_trait_merchant_key.c - * @brief traits to offer peer's (private) keys - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_MERCHANT_PRIV "merchant-priv" -#define TALER_TESTING_TRAIT_MERCHANT_PUB "merchant-pub-pub" - -/** - * Obtain a private key from a "peer". Used e.g. to obtain - * a merchant's priv to sign a /track request. - * - * @param cmd command that is offering the key. - * @param index (typically zero) which key to return if there - * are multiple on offer. - * @param[out] priv set to the key coming from @a cmd. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_merchant_priv - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_MerchantPrivateKeyP **priv) -{ - return cmd->traits (cmd->cls, - (const void **) priv, - TALER_TESTING_TRAIT_MERCHANT_PRIV, - index); -} - - -/** - * Offer private key, typically done when CMD_1 needs it to - * sign a request. - * - * @param index (typically zero) which key to return if there are - * multiple on offer. - * @param priv which object should be offered. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_merchant_priv (unsigned int index, - const struct - TALER_MerchantPrivateKeyP *priv) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_MERCHANT_PRIV, - .ptr = (const void *) priv - }; - - return ret; -} - - -/** - * Obtain a public key from a "peer". Used e.g. to obtain - * a merchant's public key to use backend's API. - * - * @param cmd command offering the key. - * @param index (typically zero) which key to return if there - * are multiple on offer. - * @param[out] pub set to the key coming from @a cmd. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_merchant_pub - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_MerchantPublicKeyP **pub) -{ - return cmd->traits (cmd->cls, - (const void **) pub, - TALER_TESTING_TRAIT_MERCHANT_PUB, - index); -} - - -/** - * Offer public key. - * - * @param index (typically zero) which key to return if there - * are multiple on offer. NOTE: if one key is offered, it - * is mandatory to set this as zero. - * @param pub which object should be returned. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_merchant_pub (unsigned int index, - const struct - TALER_MerchantPublicKeyP *pub) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_MERCHANT_PUB, - .ptr = (const void *) pub - }; - - return ret; -} - - -/* end of testing_api_trait_merchant_key.c */ diff --git a/src/lib/testing_api_trait_number.c b/src/lib/testing_api_trait_number.c deleted file mode 100644 index c644b8e31..000000000 --- a/src/lib/testing_api_trait_number.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_trait_number.c - * @brief traits to offer numbers - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_UINT "uint" -#define TALER_TESTING_TRAIT_UINT64 "uint-64" -#define TALER_TESTING_TRAIT_BANK_ROW "bank-transaction-row" - - -/** - * Obtain a number from @a cmd. - * - * @param cmd command to extract the number from. - * @param index the number's index number. - * @param[out] n set to the number coming from @a cmd. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_uint (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const unsigned int **n) -{ - return cmd->traits (cmd->cls, - (const void **) n, - TALER_TESTING_TRAIT_UINT, - index); -} - - -/** - * Offer a number. - * - * @param index the number's index number. - * @param n the number to offer. - * @return #GNUNET_OK on success. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_uint (unsigned int index, - const unsigned int *n) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_UINT, - .ptr = (const void *) n - }; - return ret; -} - - -/** - * Obtain a "number" value from @a cmd, 64-bit version. - * - * @param cmd command to extract the number from. - * @param index the number's index number. - * @param[out] n set to the number coming from @a cmd. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_uint64 (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const uint64_t **n) -{ - return cmd->traits (cmd->cls, - (const void **) n, - TALER_TESTING_TRAIT_UINT64, - index); -} - - -/** - * Offer number trait, 64-bit version. - * - * @param index the number's index number. - * @param n number to offer. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_uint64 (unsigned int index, - const uint64_t *n) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_UINT64, - .ptr = (const void *) n - }; - return ret; -} - - -/** - * Obtain a bank transaction row value from @a cmd. - * - * @param cmd command to extract the number from. - * @param[out] row set to the number coming from @a cmd. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_bank_row (const struct TALER_TESTING_Command *cmd, - const uint64_t **row) -{ - return cmd->traits (cmd->cls, - (const void **) row, - TALER_TESTING_TRAIT_BANK_ROW, - 0); -} - - -/** - * Offer bank transaction row trait. - * - * @param row number to offer. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_bank_row (const uint64_t *row) -{ - struct TALER_TESTING_Trait ret = { - .index = 0, - .trait_name = TALER_TESTING_TRAIT_BANK_ROW, - .ptr = (const void *) row - }; - return ret; -} - - -/* end of testing_api_trait_number.c */ diff --git a/src/lib/testing_api_trait_process.c b/src/lib/testing_api_trait_process.c deleted file mode 100644 index 26b2f0e05..000000000 --- a/src/lib/testing_api_trait_process.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, - or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty - of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ - -/** - * @file lib/testing_api_trait_process.c - * @brief trait offering process handles. - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_PROCESS "process" - - -/** - * Obtain location where a command stores a pointer to a process. - * - * @param cmd command to extract trait from. - * @param index which process to pick if @a cmd - * has multiple on offer. - * @param[out] processp set to the address of the pointer to the - * process. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_process - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - struct GNUNET_OS_Process ***processp) -{ - return cmd->traits (cmd->cls, - (const void **) processp, - TALER_TESTING_TRAIT_PROCESS, - index); -} - - -/** - * Offer location where a command stores a pointer to a process. - * - * @param index offered location index number, in case there are - * multiple on offer. - * @param processp process location to offer. - * - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_process - (unsigned int index, - struct GNUNET_OS_Process **processp) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_PROCESS, - .ptr = (const void *) processp - }; - - return ret; -} - - -/* end of testing_api_trait_process.c */ diff --git a/src/lib/testing_api_trait_reserve_priv.c b/src/lib/testing_api_trait_reserve_priv.c deleted file mode 100644 index 3d79b356a..000000000 --- a/src/lib/testing_api_trait_reserve_priv.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 - -*/ -/** - * @file lib/testing_api_trait_reserve_priv.c - * @brief implements reserve private key trait - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY \ - "reserve-private-key" - -/** - * Obtain a reserve private key from a @a cmd. - * - * @param cmd command to extract the reserve priv from. - * @param index reserve priv's index number. - * @param[out] reserve_priv set to the reserve priv. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_reserve_priv - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_ReservePrivateKeyP **reserve_priv) -{ - return cmd->traits (cmd->cls, - (const void **) reserve_priv, - TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY, - index); -} - - -/** - * Offer a reserve private key. - * - * @param index reserve priv's index number. - * @param reserve_priv reserve private key to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_reserve_priv - (unsigned int index, - const struct TALER_ReservePrivateKeyP *reserve_priv) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY, - .ptr = (const void *) reserve_priv - }; - return ret; -} - - -/* end of testing_api_trait_reserve_priv.c */ diff --git a/src/lib/testing_api_trait_reserve_pub.c b/src/lib/testing_api_trait_reserve_pub.c deleted file mode 100644 index 997ceee75..000000000 --- a/src/lib/testing_api_trait_reserve_pub.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 3, or - (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_trait_reserve_pub.c - * @brief implements reserve public key trait - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY \ - "reserve-public-key" - -/** - * Obtain a reserve public key from a @a cmd. - * - * @param cmd command to extract the reserve pub from. - * @param index reserve pub's index number. - * @param[out] reserve_pub set to the reserve pub. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_reserve_pub - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_ReservePublicKeyP **reserve_pub) -{ - return cmd->traits (cmd->cls, - (const void **) reserve_pub, - TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY, - index); -} - - -/** - * Offer a reserve public key. - * - * @param index reserve pub's index number. - * @param reserve_pub reserve public key to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_reserve_pub - (unsigned int index, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY, - .ptr = (const void *) reserve_pub - }; - return ret; -} - - -/* end of testing_api_trait_reserve_pub.c */ diff --git a/src/lib/testing_api_trait_string.c b/src/lib/testing_api_trait_string.c deleted file mode 100644 index 0c7a606ff..000000000 --- a/src/lib/testing_api_trait_string.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2018-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - -*/ -/** - * @file lib/testing_api_trait_string.c - * @brief offers strings traits. - * @author Marcello Stanisci - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -/** - * Some string. Avoid, use something more precise! - */ -#define TALER_TESTING_TRAIT_STRING "string" - -/** - * An HTTP-URL. - */ -#define TALER_TESTING_TRAIT_URL "url" - -/** - * A PAYTO-URL. - */ -#define TALER_TESTING_TRAIT_PAYTO "payto" - -/** - * String identifying an order. - */ -#define TALER_TESTING_TRAIT_ORDER_ID "order-id" - - -/** - * Obtain a string from @a cmd. - * - * @param cmd command to extract the subject from. - * @param index index number associated with the transfer - * subject to offer. - * @param[out] s where to write the offered - * string - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_string (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const char **s) -{ - return cmd->traits (cmd->cls, - (const void **) s, - TALER_TESTING_TRAIT_STRING, - index); -} - - -/** - * Offer string. - * - * @param index index number associated with the transfer - * subject being offered. - * @param s transfer subject to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_string (unsigned int index, - const char *s) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_STRING, - .ptr = (const void *) s - }; - return ret; -} - - -/** - * Obtain a HTTP url from @a cmd. - * - * @param cmd command to extract the url from. - * @param index which url is to be picked, in case - * multiple are offered. - * @param[out] url where to write the url. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_url (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const char **url) -{ - return cmd->traits (cmd->cls, - (const void **) url, - TALER_TESTING_TRAIT_URL, - index); -} - - -/** - * Offer HTTP url in a trait. - * - * @param index which url is to be picked, - * in case multiple are offered. - * @param url the url to offer. - * - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_url (unsigned int index, - const char *url) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_URL, - .ptr = (const void *) url - }; - - GNUNET_assert (0 != strncasecmp (url, - "payto://", - strlen ("payto://"))); - - return ret; -} - - -/** - * Obtain a order id from @a cmd. - * - * @param cmd command to extract the order id from. - * @param index which order id is to be picked, in case - * multiple are offered. - * @param[out] order_id where to write the order id. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_order_id (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const char **order_id) -{ - return cmd->traits (cmd->cls, - (const void **) order_id, - TALER_TESTING_TRAIT_ORDER_ID, - index); -} - - -/** - * Offer order id in a trait. - * - * @param index which order id is to be offered, - * in case multiple are offered. - * @param order_id the order id to offer. - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_order_id (unsigned int index, - const char *order_id) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_ORDER_ID, - .ptr = (const void *) order_id - }; - return ret; -} - - -/** - * Obtain a PAYTO-url from @a cmd. - * - * @param cmd command to extract the url from. - * @param pt which url is to be picked, in case - * multiple are offered. - * @param[out] url where to write the url. - * @return #GNUNET_OK on success. - */ -int -TALER_TESTING_get_trait_payto (const struct TALER_TESTING_Command *cmd, - enum TALER_TESTING_PaytoType pt, - const char **url) -{ - return cmd->traits (cmd->cls, - (const void **) url, - TALER_TESTING_TRAIT_PAYTO, - (unsigned int) pt); -} - - -/** - * Offer a "payto" URL reference. - * - * @param pt which reference is to be offered, - * in case multiple are offered. - * @param payto_uri the payto URI - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_payto (enum TALER_TESTING_PaytoType pt, - const char *payto_uri) -{ - struct TALER_TESTING_Trait ret = { - .index = (unsigned int) pt, - .trait_name = TALER_TESTING_TRAIT_PAYTO, - .ptr = (const void *) payto_uri, - }; - - GNUNET_assert (0 == strncasecmp (payto_uri, - "payto://", - strlen ("payto://"))); - return ret; -} - - -/* end of testing_api_trait_string.c */ diff --git a/src/lib/testing_api_trait_time.c b/src/lib/testing_api_trait_time.c deleted file mode 100644 index 6e6128a61..000000000 --- a/src/lib/testing_api_trait_time.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 - -*/ - -/** - * @file lib/testing_api_trait_time.c - * @brief traits to offer time stamps. - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_TIME_ABS "time-abs" - -/** - * Obtain a absolute time from @a cmd. - * - * @param cmd command to extract trait from - * @param index which time stamp to pick if - * @a cmd has multiple on offer. - * @param[out] time set to the wanted WTID. - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_get_trait_absolute_time - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct GNUNET_TIME_Absolute **time) -{ - return cmd->traits (cmd->cls, - (const void **) time, - TALER_TESTING_TRAIT_TIME_ABS, - index); -} - - -/** - * Offer a absolute time. - * - * @param index associate the object with this index - * @param time which object should be returned - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_absolute_time - (unsigned int index, - const struct GNUNET_TIME_Absolute *time) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_TIME_ABS, - .ptr = (const void *) time - }; - return ret; -} - - -/* end of testing_api_trait_time.c */ diff --git a/src/lib/testing_api_trait_wtid.c b/src/lib/testing_api_trait_wtid.c deleted file mode 100644 index 65390b8c9..000000000 --- a/src/lib/testing_api_trait_wtid.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 - -*/ - -/** - * @file lib/testing_api_trait_number.c - * @brief traits to offer numbers - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - -#define TALER_TESTING_TRAIT_WTID "wtid" - -/** - * Obtain a WTID value from @a cmd. - * - * @param cmd command to extract trait from - * @param index which WTID to pick if @a cmd has multiple on - * offer - * @param[out] wtid set to the wanted WTID. - * @return #GNUNET_OK on success - */ -int -TALER_TESTING_get_trait_wtid - (const struct TALER_TESTING_Command *cmd, - unsigned int index, - const struct TALER_WireTransferIdentifierRawP **wtid) -{ - return cmd->traits (cmd->cls, - (const void **) wtid, - TALER_TESTING_TRAIT_WTID, - index); -} - - -/** - * Offer a WTID. - * - * @param index associate the object with this index - * @param wtid which object should be returned - * @return the trait. - */ -struct TALER_TESTING_Trait -TALER_TESTING_make_trait_wtid - (unsigned int index, - const struct TALER_WireTransferIdentifierRawP *wtid) -{ - struct TALER_TESTING_Trait ret = { - .index = index, - .trait_name = TALER_TESTING_TRAIT_WTID, - .ptr = (const void *) wtid - }; - return ret; -} - - -/* end of testing_api_trait_number.c */ diff --git a/src/lib/testing_api_traits.c b/src/lib/testing_api_traits.c deleted file mode 100644 index 366e7e718..000000000 --- a/src/lib/testing_api_traits.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 - -*/ -/** - * @file lib/testing_api_traits.c - * @brief loop for trait resolution - * @author Christian Grothoff - * @author Marcello Stanisci - */ -#include "platform.h" -#include "taler_json_lib.h" -#include -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "taler_testing_lib.h" - - -/** - * End a trait array. Usually, commands offer several traits, - * and put them in arrays. - */ -struct TALER_TESTING_Trait -TALER_TESTING_trait_end () -{ - struct TALER_TESTING_Trait end = { - .index = 0, - .trait_name = NULL, - .ptr = NULL - }; - - return end; -} - - -/** - * Pick the chosen trait from the traits array. - * - * @param traits the traits array. - * @param ret where to store the result. - * @param trait type of the trait to extract. - * @param index index number of the object to extract. - * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise. - */ -int -TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, - const void **ret, - const char *trait, - unsigned int index) -{ - for (unsigned int i = 0; NULL != traits[i].trait_name; i++) - { - if ( (0 == strcmp (trait, traits[i].trait_name)) && - (index == traits[i].index) ) - { - *ret = (void *) traits[i].ptr; - return GNUNET_OK; - } - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Trait %s/%u not found.\n", - trait, index); - - return GNUNET_SYSERR; -} - - -/* end of testing_api_traits.c */ diff --git a/src/testing/.gitignore b/src/testing/.gitignore new file mode 100644 index 000000000..17a848cce --- /dev/null +++ b/src/testing/.gitignore @@ -0,0 +1,8 @@ +test_auditor_api_version +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 diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am new file mode 100644 index 000000000..fd5fb9449 --- /dev/null +++ b/src/testing/Makefile.am @@ -0,0 +1,308 @@ +# This Makefile.am is in the public domain + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/include \ + $(LIBGCRYPT_CFLAGS) \ + $(POSTGRESQL_CPPFLAGS) + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + + +# Libraries + +lib_LTLIBRARIES = \ + libtalertesting.la + +libtalertesting_la_LDFLAGS = \ + -version-info 0:0:0 \ + -no-undefined +libtalertesting_la_SOURCES = \ + testing_api_cmd_auditor_deposit_confirmation.c \ + testing_api_cmd_auditor_exchanges.c \ + testing_api_cmd_auditor_exec_auditor.c \ + testing_api_cmd_auditor_exec_auditor_dbinit.c \ + testing_api_cmd_auditor_exec_wire_auditor.c \ + testing_api_cmd_bank_admin_add_incoming.c \ + testing_api_cmd_bank_check.c \ + testing_api_cmd_bank_admin_check.c \ + testing_api_cmd_bank_check_empty.c \ + testing_api_cmd_bank_history_credit.c \ + testing_api_cmd_bank_history_debit.c \ + testing_api_cmd_bank_transfer.c \ + testing_api_cmd_batch.c \ + testing_api_cmd_check_keys.c \ + testing_api_cmd_deposit.c \ + testing_api_cmd_exec_aggregator.c \ + testing_api_cmd_exec_wirewatch.c \ + testing_api_cmd_exec_keyup.c \ + testing_api_cmd_exec_auditor-sign.c \ + testing_api_cmd_recoup.c \ + testing_api_cmd_refund.c \ + testing_api_cmd_refresh.c \ + testing_api_cmd_serialize_keys.c \ + testing_api_cmd_signal.c \ + testing_api_cmd_sleep.c \ + testing_api_cmd_status.c \ + testing_api_cmd_track.c \ + testing_api_cmd_wait.c \ + testing_api_cmd_wire.c \ + testing_api_cmd_withdraw.c \ + testing_api_cmd_insert_deposit.c \ + testing_api_helpers_auditor.c \ + testing_api_helpers_bank.c \ + testing_api_helpers_exchange.c \ + testing_api_loop.c \ + testing_api_traits.c \ + testing_api_trait_amount.c \ + testing_api_trait_blinding_key.c \ + testing_api_trait_cmd.c \ + testing_api_trait_coin_priv.c \ + testing_api_trait_contract.c \ + testing_api_trait_denom_pub.c \ + testing_api_trait_denom_sig.c \ + testing_api_trait_exchange_pub.c \ + testing_api_trait_exchange_sig.c \ + testing_api_trait_fresh_coin.c \ + testing_api_trait_json.c \ + testing_api_trait_merchant_key.c \ + testing_api_trait_number.c \ + testing_api_trait_process.c \ + testing_api_trait_reserve_pub.c \ + testing_api_trait_reserve_priv.c \ + testing_api_trait_string.c \ + testing_api_trait_time.c \ + testing_api_trait_wtid.c +libtalertesting_la_LIBADD = \ + $(top_builddir)/src/lib/libtalerexchange.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + -lgnunetcurl \ + -lgnunetjson \ + -lgnunetutil \ + -ljansson \ + $(XLIB) + + +# Test cases + +AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; + +check_PROGRAMS = \ + test_auditor_api \ + test_auditor_api_version \ + test_bank_api_with_fakebank \ + test_bank_api_with_pybank \ + test_exchange_api \ + test_exchange_api_keys_cherry_picking \ + test_exchange_api_revocation \ + test_exchange_api_overlapping_keys_bug \ + test_taler_exchange_aggregator-postgres \ + test_taler_exchange_wirewatch-postgres +if HAVE_TWISTER + check_PROGRAMS += \ + test_exchange_api_twisted \ + test_bank_api_with_fakebank_twisted \ + test_bank_api_with_pybank_twisted +endif + +TESTS = \ + $(check_PROGRAMS) + +test_auditor_api_SOURCES = \ + test_auditor_api.c +test_auditor_api_LDADD = \ + libtalerauditor.la \ + libtalertesting.la \ + libtalerexchange.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_auditor_api_version_SOURCES = \ + test_auditor_api_version.c +test_auditor_api_version_LDADD = \ + libtalerauditor.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_bank_api_with_fakebank_SOURCES = \ + test_bank_api.c +test_bank_api_with_fakebank_LDADD = \ + $(top_builddir)/src/lib/libtalertesting.la \ + -ltalerexchange \ + -lgnunetutil \ + $(top_builddir)/src/bank-lib/libtalerbank.la + +test_bank_api_with_pybank_SOURCES = \ + test_bank_api.c +test_bank_api_with_pybank_LDADD = \ + libtalertesting.la \ + libtalerexchange.la \ + -lgnunetutil \ + $(top_builddir)/src/bank-lib/libtalerbank.la + +test_exchange_api_SOURCES = \ + test_exchange_api.c +test_exchange_api_LDADD = \ + libtalertesting.la \ + libtalerexchange.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_exchange_api_revocation_SOURCES = \ + test_exchange_api_revocation.c +test_exchange_api_revocation_LDADD = \ + libtalertesting.la \ + libtalerexchange.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_exchange_api_keys_cherry_picking_SOURCES = \ + test_exchange_api_keys_cherry_picking.c +test_exchange_api_keys_cherry_picking_LDADD = \ + libtalertesting.la \ + libtalerexchange.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_exchange_api_overlapping_keys_bug_SOURCES = \ + test_exchange_api_overlapping_keys_bug.c +test_exchange_api_overlapping_keys_bug_LDADD = \ + libtalertesting.la \ + libtalerexchange.la \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_taler_exchange_aggregator_postgres_SOURCES = \ + test_taler_exchange_aggregator.c +test_taler_exchange_aggregator_postgres_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/lib/libtalertesting.la \ + -lmicrohttpd \ + -lgnunetutil \ + -lgnunetjson \ + -ljansson \ + -lpthread + +test_taler_exchange_wirewatch_postgres_SOURCES = \ + test_taler_exchange_wirewatch.c +test_taler_exchange_wirewatch_postgres_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + $(top_builddir)/src/lib/libtalertesting.la \ + -lmicrohttpd \ + -lgnunetutil \ + -lgnunetjson \ + -lgnunetpq \ + -ljansson \ + -lpthread + +test_exchange_api_twisted_SOURCES = \ + test_exchange_api_twisted.c +test_exchange_api_twisted_LDADD = \ + $(LIBGCRYPT_LIBS) \ + libtalertesting.la \ + libtalerexchange.la \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + -ltalertwistertesting \ + -lgnunetjson \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_bank_api_with_fakebank_twisted_SOURCES = \ + test_bank_api_twisted.c +test_bank_api_with_fakebank_twisted_LDADD = \ + $(top_builddir)/src/lib/libtalertesting.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/lib/libtalerexchange.la \ + $(top_builddir)/src/json/libtalerjson.la \ + -ltalertwistertesting \ + -lgnunetjson \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + +test_bank_api_with_pybank_twisted_SOURCES = \ + test_bank_api_twisted.c +test_bank_api_with_pybank_twisted_LDADD = \ + $(top_builddir)/src/lib/libtalertesting.la \ + $(top_builddir)/src/bank-lib/libtalerbank.la \ + $(top_builddir)/src/bank-lib/libtalerfakebank.la \ + $(top_builddir)/src/lib/libtalerexchange.la \ + $(top_builddir)/src/json/libtalerjson.la \ + -ltalertwistertesting \ + -lgnunetjson \ + -lgnunetcurl \ + -lgnunetutil \ + -ljansson + + +# Distribution + +EXTRA_DIST = \ + test_bank_api.conf \ + test_bank_api_bank_twisted.conf \ + test_auditor_api.conf \ + test_auditor_api_expire_reserve_now.conf \ + test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \ + test_exchange_api_home/.config/taler/account-2.json \ + test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json \ + test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \ + test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv \ + test_exchange_api_home/.config/taler/test.json \ + test_exchange_api_home/.config/taler/sepa.json \ + test_exchange_api.conf \ + test_exchange_api_twisted.conf \ + test_exchange_api_keys_cherry_picking.conf \ + test_exchange_api_keys_cherry_picking_extended.conf \ + test_exchange_api_keys_cherry_picking_extended_2.conf \ + test_exchange_api_expire_reserve_now.conf \ + test-taler-exchange-aggregator-postgres.conf \ + test-taler-exchange-wirewatch-postgres.conf diff --git a/src/testing/afl-generate.sh b/src/testing/afl-generate.sh new file mode 100644 index 000000000..b0afcab35 --- /dev/null +++ b/src/testing/afl-generate.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# +# This file is part of TALER +# Copyright (C) 2015 GNUnet e.V. +# +# TALER is free software; you can redistribute it and/or modify it under the +# terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along with +# TALER; see the file COPYING. If not, If not, see +# +# +# This will generate testcases in a directory 'afl-tests', which can then +# be moved into src/exchange/afl-tests/ to be run during exchange-testing. +# +# This script uses American Fuzzy Loop (AFL) to fuzz the exchange to +# automatically create tests with good coverage. You must install +# AFL and set AFL_HOME to the directory where AFL is installed +# before running. Also, a directory "baseline/" should exist with +# templates for inputs for AFL to fuzz. These can be generated +# by running wireshark on loopback while running 'make check' in +# this directory. Save each HTTP request to a new file. +# +# Note that you want to switch 'TESTRUN = NO' and pre-init the +# database before running this, otherwise it will be awfully slow. +# +# Must be run from this directory. +# +$AFL_HOME/afl-fuzz -i baseline/ -m 250 -o afl-tests/ -f /tmp/afl-input taler-exchange-httpd -i -f /tmp/afl-input -d test-exchange-home/ -C diff --git a/src/testing/baseline/admin_add_incoming.req b/src/testing/baseline/admin_add_incoming.req new file mode 100644 index 000000000..677678b5d --- /dev/null +++ b/src/testing/baseline/admin_add_incoming.req @@ -0,0 +1,7 @@ +POST /admin/add/incoming HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json +Content-Length: 220 + +{"reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","amount":{"currency":"EUR","value":5,"fraction":10000},"execution_date":"/Date(1442821651)/","wire":{"type":"TEST","bank":"source bank","account":42}} \ No newline at end of file diff --git a/src/testing/baseline/deposit.req b/src/testing/baseline/deposit.req new file mode 100644 index 000000000..a400796f1 --- /dev/null +++ b/src/testing/baseline/deposit.req @@ -0,0 +1,8 @@ +POST /deposit HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json +Content-Length: 1658 +Expect: 100-continue + +{"ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26E9M8S0M6CSH6X334GSN8RW30D9G8MT46CA660W34GSG6MT4AD9K8GT3ECSH6MVK0E2374V38H1M8MR4CDJ66MWK4E1S6MR3GCT28CV32H1Q8N23GCHG70S36C1K8MS3GCSN8RV36D9S710KGD9K6GWKEGJ28GRM4CJ56X1K6DJ18D2KGHA46D13GDA66GVK4GHJ8N13AE9J8RVK6GT184S48E1K6X336G9Q8N142CJ4692M6EA16GRKJD9N6523ADA36X13GG9G70TK6DHN68R36CT18GR4CDSJ6CW3GCT364W46CSR8RV42GJ474SMADSH851K4H9Q8GS42CHS8RV3GCSJ64V46DSN8RSM6HHN6N246D9S6934AH9P6X23JGSH652K0DJ5612KJGA26N242CH35452081918G2J2G0","timestamp":"/Date(1442821652)/","f":{"currency":"EUR","value":5,"fraction":0},"wire":{"type":"TEST","bank":"dest bank","account":42},"coin_pub":"JXWK4NS0H2W4V4BETQ90CCEDADP6QQ3MV3YZ7RV2KXEM8PWXE8Q0","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","h_contract_terms":"1CMEEFQ5S4QJGGAMVYFV07XQRHQA311CR2MTRNC5M9KZV6ETDV1SY00WJFEV2CG9BXQTEQPZAF8A54C2HX32TZCN20VBGPFPS2Z16B0","merchant_pub":"C36TEXQXFW00170C2EJ66ZR0000CX9VPZNZG00109NX020000000","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","refund_deadline":"/Date(0)/","coin_sig":"X16E0DP8C2BJNVNX09G24FFC5GA4W7RN2YXZP9WJTAN9BY6B4GMA39QNYR51XNNEZ3H1J7TP0K9G55JZ8V7WS7CZMD7E64HWYBFWM00"} diff --git a/src/testing/baseline/keys.req b/src/testing/baseline/keys.req new file mode 100644 index 000000000..a9503a864 --- /dev/null +++ b/src/testing/baseline/keys.req @@ -0,0 +1,7 @@ +GET /keys HTTP/1.1 +User-Agent: Wget/1.16.3 (linux-gnu) +Accept: */* +Accept-Encoding: identity +Host: 127.0.0.1:8081 +Connection: Keep-Alive + diff --git a/src/testing/baseline/refresh_link.req b/src/testing/baseline/refresh_link.req new file mode 100644 index 000000000..acf3dff51 --- /dev/null +++ b/src/testing/baseline/refresh_link.req @@ -0,0 +1,5 @@ +GET /refresh/link?coin_pub=WQHES0X5XK43VBG1Y8FXR2YEJM04HQVMDTCS07MH691XWADG8QCG HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json + diff --git a/src/testing/baseline/refresh_melt.req b/src/testing/baseline/refresh_melt.req new file mode 100644 index 000000000..98b5b6389 --- /dev/null +++ b/src/testing/baseline/refresh_melt.req @@ -0,0 +1,8 @@ +POST /refresh/melt HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json +Content-Length: 34136 +Expect: 100-continue + +{"new_denoms":["51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSN8CV38D9G8MT46CSG650M4GHQ6N0M6HHR6X142EA26H13JG9N6RV3AD1P6GV34HHK8S0M6CT28RTMAH9R8H0K2GHN68W46G9K8RT32CT560RKCC268RRKJCSJ70S30CA564SKAD9J84VM8DSG611MAG9R6H2MAG9M8MT4CDHG8CWM8HHH84T3AD1N6X0KEH9P8RRMCCSQ8MT30CSK6MVK0GA48CW30D9J6WTK0CSN650MAD1R70TM4CHG850K2G9H89142DT488S42DT36RVM6DSS6GTK2CSJ84WMCDHP8CV3GDSP6GTM4G9H6N246GHH6GWKGD1N70R34HA689148GHP8RVK2E9M8MRKJCJ28D0KEGT26CS3EH256RVKEDSJ74WKGGT16RSM6H9M6GVKGDS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSN8CV38D9G8MT46CSG650M4GHQ6N0M6HHR6X142EA26H13JG9N6RV3AD1P6GV34HHK8S0M6CT28RTMAH9R8H0K2GHN68W46G9K8RT32CT560RKCC268RRKJCSJ70S30CA564SKAD9J84VM8DSG611MAG9R6H2MAG9M8MT4CDHG8CWM8HHH84T3AD1N6X0KEH9P8RRMCCSQ8MT30CSK6MVK0GA48CW30D9J6WTK0CSN650MAD1R70TM4CHG850K2G9H89142DT488S42DT36RVM6DSS6GTK2CSJ84WMCDHP8CV3GDSP6GTM4G9H6N246GHH6GWKGD1N70R34HA689148GHP8RVK2E9M8MRKJCJ28D0KEGT26CS3EH256RVKEDSJ74WKGGT16RSM6H9M6GVKGDS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSN8CV38D9G8MT46CSG650M4GHQ6N0M6HHR6X142EA26H13JG9N6RV3AD1P6GV34HHK8S0M6CT28RTMAH9R8H0K2GHN68W46G9K8RT32CT560RKCC268RRKJCSJ70S30CA564SKAD9J84VM8DSG611MAG9R6H2MAG9M8MT4CDHG8CWM8HHH84T3AD1N6X0KEH9P8RRMCCSQ8MT30CSK6MVK0GA48CW30D9J6WTK0CSN650MAD1R70TM4CHG850K2G9H89142DT488S42DT36RVM6DSS6GTK2CSJ84WMCDHP8CV3GDSP6GTM4G9H6N246GHH6GWKGD1N70R34HA689148GHP8RVK2E9M8MRKJCJ28D0KEGT26CS3EH256RVKEDSJ74WKGGT16RSM6H9M6GVKGDS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GSP8MSM2E1J70T36G9Q750K8D9P692KCHA36MSM4GHS6MWK6DJ564S32DHQ8MT3EHHG84W32G9M88RKGG9J74W3GC1R8H1M6DHQ891K8C9M84TM4CSQ6124CC1G60T30H9Q6CVK2DSH74T4CGT1751MAC1P88RK2GSR8GTKJEA46N0M2DT48CV4CDSP6MSKJE9K64SM6CSS6GVMCD9G6CT3EDT6652K2GJ46RT36GHJ85138H1Q6114AC1Q6H23ACHS8RR46H9M60VKECT688VKGC9S8CW44E1G612K6H1K70VKADSN68T34D1K70R32G9R6934AE246GRKCCJ66N142G9K8CVK8GHS6WS3GH9J74S4ADHM8MSKGD248D330CHK6MVM2DA48GSKCGHH88TKCC9354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0","51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30H1J65244GA27533AC248MW34C1P6N136GSR88V3AC1H8N1K8CJ2891M8DA2712K8E1N6GW48DSJ8GW4CDSJ6RT48DJ28GW46DT46H136E216D14AE9Q60VKECT26S2M8EA38MSK2D9S6MTM4CHQ88T3GD9M8D34ACHJ6MR38CT46X1M6CSH74SKCG9Q712K4GHG712M2D9Q8D1K2E9K6X2K0D1H8RVK0E9Q610M2E1K612K4E9M6MTMCH9P60WMCCHR6CWKGE2168SK4GJ26WV3GGT188S38H1P8MW44D1K6S344HHP74W4CG9M8H1K0C1M8933ECA16D13AH9P6RTK4GSM6CRK0GA36RV4ADSM7524CH9G8N0KAEA288WK0GJ16RWK0CSK6N0KJGT674T3GCS354520818CMG26C1H60R30C935452081918G2J2G0"],"transfer_pubs":[["J65E5480S6ZVPBA5HV9D4APYXFS527DAJGN5HKZ5EWP89EFSKGK0"],["TYZZG5HSXTYJMA9XD3EMTX2S36V7F4VPR1RHQPKJSTWXJD2KPDAG"],["2MN2X2X7P6GJCN09Z6ZDF2R9W1W3BSYJER7FTBSDDSWMRJ7DG0DG"]],"melt_coins":[{"value_with_fee":{"currency":"EUR","value":4,"fraction":0},"coin_pub":"WQHES0X5XK43VBG1Y8FXR2YEJM04HQVMDTCS07MH691XWADG8QCG","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","denom_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26DJ384R4CCHP8RTK6DJ46X344C9M6S1KEDSQ8923EE9P84SKAH9R84SMAGT670SM4GT66123EDJ46RVK0E1N65336H226H2K8CA38CVKCH9N711K2H1S6X134GHJ6924CGJ68RRMAH9P6MT30H23651KCD1N6X0M8GA58CS34E9K70V32E1S8MTK8GJ270WK0HA368V3GDHM68RK2CHS610MAH1H8RR42CT58H342DSG8D1MCC1J6N0KEHHS6WVM2GHS60WM8G9G6GTMAC258D338HHP8MWM2GSS8MW3GCA270TK6G9G6WRM2GA56RSMCC9R88T3JEA270SK0HJ284R3CC9Q6WVK0DT570TKJE9P68SK0CSG88T3CCHJ60R48C9N611KAD9N6WVMAC9N70T46GH35452081918G2J2G0","confirm_sig":"ZKYCWKVTVQCWMWTAQRNRSKGQP6AC14VF7W525ZQYFZ6J2T1GM7PE7945W3HNW32S0MZBX8K65VQPXH83NMQR2SGTY7DX2T60RKHFP00"}],"secret_encs":[["DCZPFTHF1GZRXFVSYJ4AK1HH4QE46T8F60X1AQ6T6BF1WHBNTJ3FEGH7Y1TH5A6YT10GFYGV12S8V9MB4HEKHRYBBMR7JJ9KB264TNR"],["ANBQS74BACGAWEC0F0654HYGZB3NBSNXVD4KZY4TRP4JMRADJE2Y5BYV513Y37PPMR6V5P200FEAHTZ5TS3R9G9MBYM6Z144N853PQG"],["1X6P2JR301MPR5JYMKPV1HXAFXKH9M09HWVQ4PS6JNK1K6E8ZSMW1C6NS79CPFP443QBVEW9SRWXXJQT91EHFKJ8007AB4S64SPWN3G"]],"coin_evs":[["1XB4A97X8ATPH1KG5NAMJGJY258AGK0MKVJRHN4NGKPRD17DQM0CMTT351FB7T56NTVA9E5VTH9Q12A10C3YVDEYJB4B66EC1NPXNPMNSVTBJ7HGM4DXFB03K1BXK247QK581CGE54286BTK6B5VW0FTS4AZ3NQP43V9E6VV1HTKG1CM5WQJEY14TAC8P2YSV2XH61RG4E84R","JVNGX2AR684RF4VRYFSS69WNMJBDDS9Y4AXFRX5JRFES5QBTMM51SB84BN61S5W0R7PZGK09NQ8QMX7Z90AE0JJH76J7DCM94DKWMV88K966NEA2CNMS50PG6D0K73619K67S9HJ0PQTQH8YD91P4CQQZTRPV7Y2RHEGMBB2G67ZBVVH1S9Q0HYX69Y2B3J2WYFMH3BJESVGE","6MZ6ZDF26MSAZN3VK3QDY62MD3AXZTK8K46A7ZFNBVCR33AE6H3A309F822EKPHT2YTJB6PMSPSJ3ZAE99Z5Q2J8F87X5N723J713A0QR87KYJ2NZ3PFCS5CC8FXJYK6YXZ4ND6FHNJRJZZZZRXE05VP14XW1BZFYZGQQZ8J05FYKY8AYFNCZ50WT7W8M83XS50GTYJGQTNPT","Q0JWR4WRPYT7TCNCV47RJ1FW3HEFQABN9EE27DBMDB4FYAVK8X9KM38HH9KN8QW28RXFXAKT3MGHXPGRWCY9P313CPR5Z2XSR3ZGKFHQHTP1A02SSD0DHH12RCV5TJ7M86WXWT7F00CQ8HV5H90MFEDX6J2X9JNX26NC0PRH0YXHGW7XVWXF00ZEJCGJDEZ1EVXA5BNW3SAEY","B20PSGCM77EVSXEC6T41N1T55KX76B5K3X38VBQ8NSAN2BKNH0W4DQGVZQTBA2588YCRW1TN9G721GP7ZCP9H32BBC9HM3XFTNJ4QBV2FMM7KSG6T0H418EBNBGKZXMTD9ZDVV6A2TEBMXSEKYVK9HCZT8EEQ7E44DWBDHN274N9D4ZDEFCZXNF0MKBM3TYZGHJ5T71T88CE4","F95WT8Y2WRXGK07MY3FMV1Y6PS44CMP59KK8G82EKW3Z0Y6C6QZ2CVC4A6DF9N3E6HW8SQ3CF4FSD1QC2DN5E9DM5G762DW491BAE5RC2A3YPGJTZ3XBFJ3R3NSRDRZMHR6Y755QDRZZEVFTEPN7MZ90SE6KTQS80CHNMTX15NMZPNFJSCQSEJ9RQJKZBH9ZZFMNXT8BXM7K4","1B8GKDJYJYCZ8Y2HCETV6EWA8FRVR0AAD7TRXFXBHNF7G10CZYDFTKBJ8X0J0M7VR1KQV67SF5VMM7VVG5ZQ4F9QEKRV3GSBB4M75CAXSEXSHDT36RJ6A98EKP3EZXT65HX2K788ZE4SVE5N2NJ8Q26P318PK9X69YWB4W7R1F1F9WHZ8WKJ69G5YZ1T9WR1N8CXTJASXW3A8","FV0Y6B21F01D5EH31R80BHG7GKA08C7HN3FYDMGQE6HJ2Y9ZSVJ17HR8Y22WGPN98T08E6XP4PZNMJ3RHAFK8DAVW3AYM5VNPHV3JSB5B64F0H60EMQNA59A2QAFRV3FCHJQATY87SGT9E67HRVE5QDP9HJC7A351WM55VV5MW3T251VVZ8N5V2GVX6MD14MR9ZX9TBS4N30J","K8QSPQTEV9YZC7MC6AT9R8Y0QGG4PT1V45KSSZR2YY9SBA3QEQG7R6YR4RKEKR5DGDM2K4DN9K128TQMMPFWZR8N95F29Q8E2WBD22F5SRFPJ2KJA6SEZ6RMPCHG6C4BJEV7PZAEVTNJDK8T79PJCB5B97D5WQ52TT2DB6Q4S599D61AA54FCVM9R3AB03PDTYZ0PCKBMJ23G","1655VA0GT3ASG2JVEZ93BWE01YDEA70ZW2FD1W3AZTD4B4WK9GYPMM9Y6KXDGDDB2TMDF5CWXNAX0B7E396E1NH3GCK8KFHMGXNPG0CTD2KNW9X3QB4HKK68JM2WGMF05VJ6K4G76R4A10JWPEZTD554TSFYVEM0355C9E5P9W5GFFFYQMTAXG43V8GP7P4BDBD81Q9G87MXG","J3T1MSDB9ZHCCNAYDXEQAMETNSCX5DJYQBCXGREMYAWAQ8AJCY5JV00HHX31DVT7X5S25CEX88707E81X4KNCN7RBRFMFNP8QZHFZHXNS6MN7BD4MGRVQEC50EWH6N6EFY1GA039KYJKX24XMGZXKB27H5R0RKN7YC00EKN99SGKF3YN7DPR8880MG457438G1YJR7BGRCG7J","DX73NQ14FVC978B1HP03MWBD83YT6NVP607WB126RAJPKPB11GSWB7H9W0QJSH9WD4SN9JJE6FDMQZTMJXCN1AKDBKKVPWW9VBEAE0YVCG64S16TXMSF5FTWNXYG7RDTHK03BXDGVXSPZFE7A2F6FPK9WCBBZSMKB8EJFGJK1PKKBHVA1Q2MX91NK32XPF00WFWZCC3N72JY2","PKSMQXMCT9H53FHGKVVPPTTHJ0M5X4SSR0XARN34VV7DX9ZA9N8379NVQKN4E5V6JXAPEVGPREWD720RZCVB90DDHRFW8GG6G434GR1A77SVPG9GKP2DEKBVP3CZ9WDMQD9RFZZ2Z3ZQ34YVD2J1Y4AZ52ADY5FXPB06W9NQ9NH7AQVHTPMSTP181MZM507M777SAPSCR9J8M","1XV578XYBQYYSV9V8ZRACRG3JTN103BZFPF5JXHF8YDCCCJM9XS343JYM8N6Q3J8D0NF2T8TPZKCB32MC1GXWZZRRWQW77JSSYXGA8136DNFYTCKB8EP277KBXAYXBW0ZX7S13J5NDGR7ZJ7QTAAPTEAG9MX6QBT9Z7ZZ1MECV7Z0D7GE7Z6KWASE5T4SW0MFHKVD1EAFNG0P","86PDN3KMT8AW8TVXEBGG3199YSEDMQX91QW82QVZ9TPYCNS3YKK3NCK5J64VKPKGJGQJP8E3RX97NZ4RDQ0PR21QS93MTWXSHKCTK2KTH7TQPKVQSWPGVC8CZDEGD9X484HJKMQG56RP1MZE7AWKK9C5ZK7MSN21GTG1KNF591Q8DVX0TM06BD8VGF6QNC745CFRMRSYHXK7P","KGXXZAECQ6DETR97HRYKFC4A1WAKC3S0FYNHS16J342WMPPP78NHWZXSEPN04XEQY6QNR9ECWZNXY6BZHXWAW2EV42295GBVA4R2J2KAK9EF7MR2789EHY0MVQJME1ADGEPGCQ02WHWT3C173SPDKW1DA5C8HBF847KV00A3F3ZM2HE18N5MFFQXBB014HK0MC4NW6G19AESR","92G786WTFN4BP3Z2RX1Q79ZPHGMPYC21K646XA8AB97V103DSJY0S4Y1FHHSHYQ8WZPWF0W07VY6CDG66438K8E8DWN7CCSB6R8KSC2VNAQBVC1ZD2H9VG33309B6QEKK5PYAGJZN5NG0CJXW9RFGPCNJJZW6KHM4TCMDJVKV9P953Q0TWVM2YZWK37504QJ41MZ4KXN52M30"],["NG0RYVSNPXP4B2NEYCTVC5A0EW5PFFW8V3PH9X5FFQ2VHCETMWDPZ75HBSC8QDBCWZ6EV9SEN1SMEMXABK3YTXBDDXYTN0JNKX1ME9T71JJTZZQ7XA1890DZR3ZAMD0XW8GZENDNAP4R5B80DQYFDEENSB141DZ0HG3A3FZA7JMCSBY0Y0PB2AXNS25Q6CQ5WA7GWCWA09PD2","R70NVRHFT6HCP69K8QQM9HQX0CZQYG09VV2VA7RKCVFDRTNH44XZHRBEJTBW1ASDS7WYA47PBVPB9T77B32ER6V2745Y8B1P22CZ5T70WTE6Y4HSS60CM5SFB6QT1VXTVW9G0DAC3XY2QDX6TKKQA1HX3RB0GPJH47D08KB1Y4EP1SXW851CFNEE373YJHBNYXMSE3MJBCQFP","JGZK4NS2E8D1CTR8ZAR5CHGN7T09Q41P545ZNNB7RMYV0CZ9CQWJWZZWRQZDRDCHV5PQS9G6WZB37CHQMZ7Y207D23FQAPMN6CP30CXYEQ449R3V7B8BYGJ84VYW60201B4343GG75TTTN947VVEYA3BWKRY4M5XCXSPAGW1TTAH9VAE8CBXBKAKJESX8XWS4W5PYBG8793TR","CEVHPNNSWR438ZWEK27YRYBKZXVBT8AM9QP2KXWC59ZSM8Q7J0GZNXZYBES04RB7BJY4D5YCPT3VRT7EPK0576809CG98X5SPTQPSR4TZ0R6DWMXH9893FCTVJX2A4H2EGSGP3Q6H53FD4CSDBMZFZVACXPMW1CR07A1GG7XFXSK1BP1BTGMBQD0818G6BC6SBFTXS1Z68PD8","72BFMSPJ57Q1B88JS6NX8YETQP0GSSRHXM25ZBGNW06YGYJ7FT1D7KVGF4PRKKQK8KN4MGHK5DXRQDTNEJSRZYGAN6DV5QAW9PACT7FQQXG6G4JS7J129VXFQP3DYTV0455Q37H5YPVGMWXZ4GNBQJ86HWWD670XY8JAR4WTYHX8FWJXZW57Q94KK79SD51HBJH1SJ4Q5C04W","2MDED6PYFV264D0SETN9MD4F0SADGVD75J8Y16DTSABNPW09AKE7A5F4QNB2124WDQ0HW4SGHCX26NAG46Q960Y01VYSX0GQHVKESSMEAZ2426GJ8KR0E6KTAXDZY6HZ6DRSPXXGZ07YZT2XF696CP8215HE92RGT7A50H5XXV2FDGFWJXYNCB7QND27ZWYWTK0KTCRYT104Y","267QZPCB0QGC63V9E75Y41J5285Q3FX6KQHM08MAKZ248X9WJK5H6H903C0T02W4G3EA22E0C1MHCWP5VRAEC8D0J0VYW9JNCH9YGPQJ3P941AADABVXG4M2K724C8VCFZQNXYJAMY4Q65WYHW6VYPN9H1K7ZABPAZX82SSSBPYKJZBREJ15MSS50R9HJ6FWW7T9P8ES015PY","7W8HPWAGBVFK0KTWG02RRTWKAE4W0PJH76GH9JWD7H48BS7CVD1T38QBX7HJVC6PJEAJ5NGP7MSJ9D5H1FD2T9Q5X4YQMQ1F80H4G8GRGXFKS863G48HN15D72EZSM9V8M75FXCH3639PHENNV35GA6TWPRS70HEJSBAX9A52DWTB63ZCSZXFGACZEQFGR0EKEE0AZB3HKE2J","JMGGS2DPDKNQKTM593M69Z1R331654KR6N12Q7EZPX20BMHV1P9JZZ8HNN6VHQ76YKWNMW9HR3173C2J66R8EVVWZAR001Z18F9HJ9YBVSM1Y94PJSM57GNVRNN0GH11A3ZRCA4WBKFC64A4RE6KTYMMJKJNHTR9A75QC7JWG5YY9D0J8TM9KXQW8495V702VS0E40121HNHY","REH6B17HSBJGMMPYKG7EA1J4G1D7H95N20P647AWHJKY3VA5BDZKN84FEG0G0FK6TKNN8D0TDFQ41610SK9CBR27SFD16PKEZ7AP97NB9ENPQRQ9PEKR76KB6VFWP666MJBTQJ5R7WGKTTE3ZN5Z2VWY2CPB437746CYBN52G2P2Q7V6SDGXV5HPYJBKXESS1JMVH3EHDC988","MRE9Q877Z18VMFNH1PWNH9N3Z5YE2SDZCVVFBZAA41SSRC2F81D6F9TCZP2AGYAEXWM3977KWJ6SV215ZJ24RAWA94NCKEFQ1CMW8MYJ063EP68NVVPH51SFVYQVHYC45MGNEXK61R9KFK6RWYV5Y6CHMAYZTW5M17WBSHBZ79F4DSWHVVY7774FX3WEEVM8EZ0WMJWY99A1P","2CM59NJVJ68NYX5ZJM2ZX7JK8EW7JXAVE0H2D1ZTX9X6X72P9768WK5GG3ED7MGEYGFQBK5YSSJ0DM68DRPDPTAHQGWTGJ7E79GAW96BXHYV64BQXXEV9YQ0XR84G8VZWQ8Z7T9VX7VQ0HHX1SAS3NGNZAH1H03KPFNAZMNMGV3H4Q3PC96JHGAP5JNDWA1FAFJ410REB33D0","2KEXQVJHACQX7V1XGF8PA6DV0EVAKFNSA037YJ3BP91NNQB60ZBAEFT9DKVW2M19R51B8HGQ2RCBSWBRHD0RFC95TYGJVKNJSCMQPXV7SM6A1JH18DFPWB1AJBS4SSVJXZ9V72TY2P8Q8ZTBMGCYERXCT4QJMASTQM1T22C9AXMMPZ1BHKNB2FBJ3TY9AQP4ZGHRSRBKR75E4","5Q9ZFEFF6C6XPGM78EXAWJF2CKJVJ0SPA113XT7R5JTRW7MKE70TETKK1MBRSTF566AEZB2CBX6CR10J6DPAQ92GC6XYK27A52KQGQHR5W346RGF28WE2PPC8S3XWTGCGVP318AKKTC8GZQ62FRYZVPTVF07HWYHDESQFKYNSDRNV8Q5KPGRQM27SK3CX14RA2K9KZ0NJJ0FE","7ZK7H90WBS080M9TH8XH9DNENKQ78YHYSXWF16VRM76YDKP4RG97DEM1DBX84VXH98M64CJS1GYTDKG4XA8XCNSZ4KQ12GAXCJC168DBR8Q4M29X2Q70WNR7BZDNH0DQJMR154M0C1NH2EHJBKA76PNZT2369PT9Q4961EBCY5FE85EKCX7584GXBMHQF1GRDVCCDVY7TH210","CFSSPFE27VKZHPS7D48AAHE0C2XKXS774CDPFE530P5C4EFZVZEP1PTS3NYB7KBNHNAGMZX8YZJVTNJAB1DE7GCRG43Q2JVS15RGJC4K9PDA0Q2MG4DGRX1CM28HE8CB1XWVW7MCDJHPNE28NWN0CYHDES8GHAZ6Y50NNZRN31FV8C28V0PRNZK4WFAPJ4EGV5NQPHGSZAWNG","9XJB29QY06J1DYBXQRV9F7M3T11JTGSZHX8D0Y80Q07M646VTHNFKNA19CG84BA2DKRE1D5DS3M72QH29S9EZEADW6PCS1FXGCMGZ0RQXT5ASSX7VBQ40NGPYY6PFE6CYV45YYEGPGJ2DCQCNYP2Q9E78SBD53QTQVYZG7W3QE8EASEPSZXP1VVB1TYYHN0B1BZGY2JKGWWPY"],["CSATAT8AQRB91XKHJD1B7MK1DPVPV991WZM4Y2NF0G8SNQSR391KBDGHR0AWGZ8V6EYXKNGTACT9GRBWWAPYTDPWFZ5QPY9GY8Z4YDXRK1QW30YT6JMAYQM2TH36XP81G2X55785ZJWCRXZ9QQDGGMMM8QZTWN9TPW8JXH4XM8A0DPG5354PF3782GVC8J8DXD7KY88KT0FZY","4MG8W9X1M5361HRRG6W9QF13EQDRFWVAQGMWJKEESZ3FBCWP7QQGQBBDT3ZYE3XARBVGJAVFQRQPAYA1PC4CQYRX0CZTS0E4QZB3ACMXG9XJ91VPP7X0ZG08WXWMT02M9V4HCHJ7MJQZ7EWCRJAG7E14BQ465R123P6QFGY770GN0BBNT040S3XPC88CD8X3D8497DE2YA1MT","DCSBAHV955VGACX5WE2N02QZSPQ9N375DCS0W3298N8KF59YHVTS7FYJ1NE011VWF8ET7F6SQZHW1NWJZW3XYWN2ZMWXCRGH80CD6N8YA6EE8Z2N2PW4T65M0DDX4YFXZPG61E7JJGK03VTDW5J8WS2F2R88GNNJMWBQCYBWWTZ34H7J5XAPBBY3AF4M6A8C0RAHPX0FS044W","5CKW4V17Q2XAV54F07X0C2NZCRZ21B9M79JM37F10DZJ3YMY9WPEWSYEDC6DP1QZ2DRRAXDCFG1WZH3C0Z58Y26XGSC28R9Q3ZFSKZHS0F0DC08JWY01W9GPECCN0CP0Q19N7GWX7HAFVR0PR89P0DTBPJ02NKCG14HZK933C6C62AFS8GFWNWN7FJ042YVSH69BAM9FQX4JT","G3J5ZS034N9TKESCEBQJQVXJMYB7HX48QT7QTEZA688019KSSCFVDG2TD963JA9NQF2G80Q3J1853PRB8QD2WFWDSMPP9X4FXKAEH79Q2X8K2KZJ120848KY421H81WAA1AMPZ6APD67RDRBKM0H5GN974TBQ8S5ENFRJSNTJRJEDY57GRHAN8V2R2PCNCY1VWH92EN1MJA4P","BFTC88T9TMD6EQPMBN6M7ZES14AGZMK8CYF0BQ7JAPPAPKXRTW83Q2ZF5270PG9WN0SET02R2HHFEM4J66GDWK2GYCF6GBZWF0GAH9ZC0AHVT3JW2XWDZ2X1DH2WB9Y10A7QB83S3E1S5DQEJXD6AS4J6HCBJBZJPC1EJZP3E5R5ANY1EYZ7P1692WSNABA0KWZS5T05DK51M","HFBFB0NVHM82461FBYT7SKWR1R38QD6MPMTSZXQAAH7CKVSKE21M4KZMWE3EF2C0FFJ6QGZPFWYXM58NANQMHP293WNJD5NYM31ZGV3ZS8SDP9DK1ZVSF5WXW3PEKYCAR3C7J6QZKAT1CVQF86P6M3S7XPVN8EV212SG4ENANH650EF7H5RDBN29PRREWB5JA4PSX9TQR1Y92","1JT0M6407RNBHQFZ0SKEPHQW2ZTZTQ5X7BZ1Q1FBQVR9QBH3EP20CH1KJSP71PC8Z4WFKJ97442BWG991RJC0XE7Y71PW9SXMPX4MG1SVN371ZG3GNCBX3Z9AZAAR9PGHS46AVG1RH71X1WQZ7W9HGQPRYDPCMQBQ7N2PD0AH8EJMT2ASXKPNK09S9H9B0ZTYMB5KK2VB7C72","E5PWK8V063470P271354CCZ3JS5H6GB8GWPDCDB125CVT4YHR3MGTYAFTDJP38F2WSNERY5KNE9VK85N70WC6VZ22WF7MABK2FJZM3179NHBV92FQC19BR21002AZHHE4A171QYFX69NXV3XA90HY27ECQ28YCPZNKEPQXXVCNHVSFJJE8553M68KM81EW45GXEV3797W2KX4","JQGN8RXXYMHG8MD2GSNQ6NQ8QCH8A6WDT0S0WY4ZP5424RGY975300CQC1C575K619FY2JN71RQ62RM6W2TBVZX0Z5B8A2PQ2MTN6W486AHBJKX6ST9HA05EQ9VMJN3PGDSF1GACENFK8CA1EW4KNG185PG6CP7YY1TNX3FZ43H020K8SYTQWMPM6FAZ5N4MA6CQND1ZJ6AC0","NJ5PM2Z4VNYKG6X93KWH0GQZNMBKHYM2FWX0BSNPGJ18Q7R32YC9FPC2Z45MPJ5EZY4E3FD0CD67TB9K4879SQ33SCG4Z9BARNQVWXMK975GRGAB4306D1W7PF1QD1MTVW79DHY3M2VVC01R4T41M3TXYTD1X3JF1PBGC4T63MF9MJS4KZTS03Z84AY6C9WK9RTNHXN7R0VJC","1ERPPXVG2NJ4RHCD8QED1E25R6QCAKKZWRV3EAVS4Y17ZDTXK46TSBJ1MF4HN26K3FHRE3PVBV4DA1RJ36R70BSAHSW7KTEGJNR8M5FBJ7ZDT907X2H0RMPCDANGGT9Q8VWYKBAHQ1T72S0ZAEC079SKV16XWTRX698P3P2TCJQDT7EA0G67N82YFPRE7YVGFKTMYXYC7EH1E","91CHR983Z222JN1695J11YY836RHP6J02SSZ8T5ACZ15X0D1YAW8VTCMECW3CPMCHG2RWTS5C30HSRWTYHAE3J3F61Q5N34ZSBVFPWJMN8WSFTAFEG7WZDWCM1VJZX5KZGXF7RTCS09MHJ0WRMCGC18WSR2SDV64P9HE1WTNCD8KT65JGQ3ZPWAWVJNJS63YNTGDPZ4RHTZ78","8Y2GMEETX3N9XTAB124JYKMHQH29009WJ5KF6V31WWZ99GXWZJHC5C03P3CKMB4R8M7ARQ3XD7AHPJTY2EKKPPF9QXWN7685HDTPT2SBCQ67XHHRA2RJ5E1S4VFP2YB1H0W1D9RE4C6WDT7FNVWXFHXAEQAJRJ577QNJD8G4ZSARSJ2SP6625AW9VQVVRFS0FWMBWJZNHXGWE","33MH8RQ5PXQFB0Q2T0H30VM9G4J0ZQHB3JHH8MWF5K3F3KDBAR20ZG4APHCTF1XRG530W7K2476P7BNFKENP2WXJ4HAW6RS91EQKGYD6PEHRYCVF8JJTMWR32WFVPV5Z2M1FWKNNC5N4CC3MK7S2K1V05PQMZ347KYD45FW7Y4KKJJ89TDPT7SFSQP1A0J00SN3MMTSEGXMVC","HR05CWNNQ5VBAF0WNHP8DZGN3S0DGYJ37EYP8S57MK8KDXQHXTPV2SXNJ2M5SZMS43BR168FJTB1SC9EW9P9YT7DYRBRM7G0VSD86P4QBG42NH06XYCCF7TVN9H9EB5K1G07M2Y3TT4WBAZ2Z350PV67ZANG43054GZA4N08BN2WEDFN94BNFKF45C10C3FFG77D9P3PDMGVG","JS43E6R3YEVTRZGRTS3RF0F9PCW7NBTWB6XEV146AXNTSKEKCDQ8CX76GX6HA06N0RTA699M99FXMD4JX04VY961YXJ18G96Z1AEEJ5BR5A8GYEWSNJSR5Y55ETBCKHBHR6CJ8A3659Y45FNG7H4C1K44WZ520PE4NAQVJ9QS1H2RWQ5ZZ8H8J8WGBDQC6DQYRTQHR0WF2156"]],"link_encs":[["7A1HVQDZ7C2M4K913020KMYGK4K86PM30APZ8AH5ERT5Z83QZPJRTGEFXF0TGYH36R1N36N3VKB5V845FK33ZW3R4G01X6CZNE37XHXE707T0TA4DYGYNX295QSVF5VEPD8QMK1J7ZAGDS27QP9H1QVK3NRBTZVRZ23XAV642CGEFS1ZMPWEDSHWECQ4G6CFK1V0K2118BQYS41R9P05NZ18PY3Z1FWNZH472HTKWT74KC752S0W1C2ASM428009","VN0WT37PVBAEYW3GH2ZGZ6X37R0XATMMGHJ86G953NVD6TE608Z3A6P9PG9XAFAGPQ13GSQ435C8763NR5T28RQHH4JB9N578TW7FHA5Z4Z6MDS6CMFK9A6ZGGT35G28NH6YG55EZR6GCM5E2ZKA8A9TR8Z8C6N4BTEVJCCJRWQ5MG8W4TR5N3YNPA7NAM49TYECT56BHJPCD6DHJ3XQF2XTZQTCECDJWZG4TXK3DEZM7Y55XFJ49C7F1P17MWQJ","88RWAYX9765MBR4KBM2BN9NSQ5KHWFC0AQZ6B0RF617VF5CSJJZBB69XEVDFC12K5D0T06KBE71BHK9E5ZTEWD5FK4Z2JVKD6WV6QBFHQ8Y1ZPP7Y2EYB9XFW7S9NVM27FNX8RKWTAJ45FFYKJPNR7MX5HZZ77B25ZB57Q0NJB1E7ECH4QP5BKZG63CF5M75VA633AJC7A4XWR8JJTTQDZ40KJMXE15X9KPABVZM6HSGF19P3N2SE2VSSWFXF3XH","MBPTJC2E7C7YQMAKCJN8EYBX1Z0CG8Z35G5VW3AZH3PAM6DF32AXKFX06Y9686R1CC1TP5BWX94DMN78RXSZGXFTEKPK3RSEVWQZCBR6BWB7YEEJZTV0C5MGREJE73RP40730074SPPW6CW665XV5TJA5329ZM0XC0KJ3MR9V70TDCE3M9DMB1JXPN3M97A74XG6KNJ57FKDQH4C4NV3Z3MJ276Y9MDAPDF7GM7MW7AQ7T1Y98RJ4H6163WCSN6V","Q2YNH71E69EDZ1NF8PFRS66PJYZ360SPQVQK73422944P34FGDZVJPMF59Y5KVJSB8VTJRPVMBJQX5Q8M8BHEJX1YAHDXAAWBTTBFM12CACZT72CYH6S80TJ8GYGS9ED1HBBWWT8RTZGMD8R4NMBJJRED107EASZJTH4SW32FJ04X62EA7YAMAJFTPCC5E6QJ43F0H592Y3J81NXQS66P6GQXKQMCN5W3FX8ZJ3160V542YVE2FNV3X7WD88FVX3","5H1650VJX95VFVA0G8ZNGWBCACCZ53D6SNJ2S4QVD27X2128KWC4MXRH8B3FK89QXV07NTEAJEXGDZC8BSYW11JZGF7H3D2YVXX8ZEEZBHWESCN7TNSE9AQK5NBV709PNHP9KHE0K7KEJTY2GY08CWAN1G9CQ3ZPF71NEHC7C0C47GYNVHX9PTXAYH2ZKQJSRNNSERC62CFX7NQD5TPF6WFEYC9R1AB3TWEQQF3FKY5EAE04EAEQJWSW0ZFGRCZZ","F5DZP7M59MGX6YJ3M3CEXVSJ0FGD3Q3EVHSQDSDDKSFPJ7ZBN60SYEBB293PDCFZVKC7K4HZ54E3XM7G3GECK2ENZYRCQMS6PS7VM7DYKF7S56KP0N4SE6X69Z6EDA309XPHHPDGRG1593SZ63YN63M815C2JP9M5E7H4FWYWQQNA9C81FQFNH48NVF43G3A54EEM3JV6VKB7X9H3SESC7YRA862NZF42C2FP5MCSACPQBSX0HV2Y6QRZW53BTW2","HJ9AV53HDRMNPEJJPSEPJV98XXVK1D93WT9CQNNY7B0GKY2TTAW55C83EHJQ6SHMRYEWQPBS096ZKRDFHNM5YJF09V0NFEYTTJGSMFCDYKW5GYCZRH3FGZHKEMNN3S98WV5KWDG5PT0S9TCYTDW074WPNMTH9V9KE08E6N8ATBX62PZ2X326TT3N15RG3ZKHQ09360981ANE6MVMTM2J4RXPFMA936KTXAS0EF4FTTGZA1GHS4FNG0JRFBXTNF0D","BXGHTGZ5EWJY0XKATMGECZB8QM74WH1RY4FB4KZP0VQ4STWVBY0NMQ8832YWB04GQ2B50Q5RTD61091HH1R3S2DK6QD7VJYE9BZ4EEQJTDTSSQT86DQEK2QPTXQ8W39WBTAT8PKBT037JM9DCYAC4CRPGTQWBZK3M1Q8BZHRVXYVGGVC5GWG3YQX075EQCSD9Y18N08JKNFHJKVZH6X27ABDHC323HQS30VS15BD65GZ35MH4HBFT7CAHPDZ5C4D","D3EF8ZKVNK6PCTC7KWGDGTSA3804J3N76R186NKQC3YJPW9P9B6CXDN9910S5RNEGST7MSY566PFZY2NP95WZNJTMG8988H3HFVXTXK2TST59AFBNDNTGAK3Y149WVWNDAVZ3G4NM9R75HSWC75BGNDRJ1F6DQ8QACZRAN9E4K6J3NZ3BNG5A2JY48TVXEC3E6TEDMF3E4Q9QSWQXPEHE48TJB5J7Y98WTDDWWV3S186BGM5V06PTGS3V2QRMRW1","YXS4AQF8X7VR35BBA8RBRMCJCSRJ1K2820ERJV75TZ5X3XBB4S5A1EKAGQHRF6KENMX4GEM3NT30K20FD9W03B79AKARV0KK6SMW0W1DY68KWGF69JH95RCHXCSVVV8XGVC48CBW1ZBVPFXS1BEJRDBHJV5229R5CZ9AXC3DNSS7S2QYENQZT7ZSKM9VKYGN604GT55SXD0NXJ0QCVT6TG8MTGTTKSM9D1DFKGDRMP251FCEZVG4XGZSVHKGVHGY","2QYSG97X93Z5TR1JT9FJJG05T1ZKZCPKZ4FNTBNF3DT2WPJR12QF1EPB5NSYQK068XFRKK46YGTT5GX6QEJJZ2B61A35RM30HNTP9S794V2TSME26S4RG32M6AYCNZFR6YEXBKF828ER3HMS1XAF8H475HQSM4M0004GN2S2EHMBXR62TYBEYE20GB123X5V9B31W9650S1E833Y6AH8SKQRE5JY1AK0NATPP6DBKWRC3FTEV6QBDVDGB8B3FKVB","XHTD1E2BZMY311GRBP3PJ6TNJ5S9MMWYZEPFKBF98X6Z3B9GK8EKYZ9DMN0CR9JYQ95KVWETVEKGWMF3V9VT3KK29WGDBPCX1V44J09E2AA1V72A6Y6B6KXPPESB3SM2TH0DZZC1AYQG7TNAMWTQ028ECEZAW30DE3S4ZWKE78ZZJVKP4ZXFXWN3JTRY2TX112B3TRYH94GNYJ1JKGHVG55ESYQTFN7VPPW8GMRSJRVNJZ09S4P37G21HBH46NCK","2N7GXE2T60XCGFPMTS8YJZ64G6STTNPQ4R31CCRJ9Q3F7KJK9RNW4JAQ0VP0A0SCQGR12HJ09NW0TMWKFP46XHQWRJP9WMQA8TXPP6F1SR9XQX7A8KB73EGH3BPN8X5N7YY95M7ZBD1F4SJK24HR0P0GV6BMEEQFTE86QGTP67Z7KC1JPANYM1B3MX9Z9CVESD83WX4VG459X6YR2HR8T576M0EV5K73P9397H25ZSP0NXSAMGY87R0DCQM1GFR3","7WKT07H36FAWM8W3X54AN2VAGJC5DWKP2MJMHES1NA2VFVJD3WAWJJCNWARWP17SQSEWS38HF36A63BNR5Q0Z2R7VETVASYVEYRFQYFGW3KXCVT5AS2ZHJCDMWRJ0N5EQXP0J7MNMCCCQZ8F304SKWWMAQJ8EB5Z7KKM1T0Z8WQHZACR8YTATF4XSXSSJVPGGCXNC47B11QM4RN3HDGXF9MBZZMKASBZRF8AA2EH4M1VFG8NR243ZE3ZKK3818C7","FKZQB344EWN58WPNVZ0BR5A7D30ZR58HZN0PQPVJBKWK3F4A4DPNEV3Q8QXR70E8V5WT4JX8AG9H3X5RZ74DQPKH7RT4M4747NY98P4J09R58JP7BR58KA8Q0AHS6069GHNWC0SX9GF33RV9SA5ZYA75CV37V1N5GRAPX6A0SWR76B6HYSPA94G5PY02R9B05W8Y5MDWDEY70NW4ZXWG2ZH3S68SSNP6SASAJV85KMH6CH7FZXTDYQTAR0HDB4K7","3073VTHEC9679DTAPZZ2J52N4PXFJ2B5JDQQ4FEPWCDFWMTXJK4KTSVMSF6DNMY8BH3EJDS192CK16JZG95JGDGYXMYBAFCY4X77AGA33DZSNXT32VWNVKKP6PN5E7JWRDJT8SSCRJ6C90P9YZ31SFF4PPKFPSVZFRC3PD87CKT8M9D6XDWN61D0PMXKMWGJVSNQDR8NP86MJYE8KGHSX0SWDV2J9N3X9212CXV1JDQNS3DFJ7XEX38EEKWQDSJP"],["8HRTEYDE0W9T678MM8X20QADH4XHBW7JTHJVFDJDANF90K84P7FK7TN0KJGE5BW52VQQFB10YNEQ8S9J3WVRV229RSMC9FKNRJ60968J536EYP24C5WNACGATG6AG8N4YNDQNQQM8V2KQ6DX2XVEH3Z86W9ZYKW7SS4V4B2WM1ZT9WA80SM1H73H9JN62GMMQE37XHVQZ212836WQJMFFKR29ZSYZAE45FJ14AQMP6YKF56M4F1PSATNFZ62VC87","R2CW58HWX89YHVRJ8WYRJ1A2GSC24H1BQW38VGBXP0MXYZS939BWPG8KQM4ED9M19QVXKZ4RC21RN62EC7E1SSAF5VW0BFBGER1FWW3ZHJ78FFF1TNJGRVBE2PF18W1ZXMATHZ12RRKDPSYT81YTGRGAYZ71GHYD1SKYD711P2J80ZTKC6YCWJ6172Z14VWVFA6H8JWWA8VYZ4XTARPXZRWR1Y1YE4232XYZ8X6A8HHWQXS5ZNSM0WPK8BW0KSTA","DE3DY2F0TCKEXVV65EHTWFKKAB2ANTDS435K869BXNVA8NQH4JA6X3WM0H5VAVFT3RCAVQ1WYCRWZ2PKDABAFEXF8RP1R4ABX04ZZS4XPB9K4R1T5KK2HX7GMWQX8RZ16Q40C44DJ70YTHVBD0BM6AF2R5G86SRZ8KERPS21RMPYWYBBWM8DR5YS1D3HM6CEJE6ZX6K398XJGK59E3FCHYJX0B2SCRKJB5E5G1S6PAB3QXKZ2SDGGQR7F8XSESZR","ZNXFM7CDW0M2XRNBTD1GM4FDG74G2XDMTF53N7R71J93YPMPXTT4G6CVZM9YZHCK6GQ35P9CHEKNWK9Q3VESZCYR7TDMMQYYFBNPPM8E4CVHNHFZSBSAHP6MMSWQJ07GZA9FRW7ZGDH6ZNEWNVMQK0V8GV0035C8PP2SYMH66FWMA24E3D15RMJSF4C817TD7SD4F7WG6RCBQ6Y0DDHAY4VW1TB5V4W55J3N0GEMX7AJ98T0TSZQRS6R9PSP1JA2","2J8G5KH2TYWDYHA2KX2CEPW58CRDHK05YX5TER84CGAEBAQASD9Q0ED8R67VBVMDQE2C9NG7V4T3QZ2VRPJPYGQXFPCXBQF99FXK1GBMEGCVP8Y4S4TTN8NJCRBTY6CXA03KQ00JKVJMVSWA85969C2F8YAG8GS5TBPF3D8ZT2C56D2ZD65ZB7F0E11S7B2RWWES7TXQ7HKXDWEBFMYTC2WNGZT1NET0JG21MP03KPS6BEMAX5Q5B139QJNCW8F2","K1605K54DR7EXXPBSWWFNJMXQE6QZS3BN3WWVBF2Y83WD42NMB9FZJG0HXPXVGVJTV1EFEXBAV7PY28FAXTVJHAZ06CDD13ZF7JE12D1BN6T6AT4RHN6N00A2ZJQTE1VCWGBF49Y5B75ZXNS7F9K352AR5A5ZXG21KV7VNT2ZPJ2B1YQG11QY05W920TEGSC8TW0J41HN035ZHCG8KBF5QN5RMGKSVZQV708K7DPVYM7NC2V7X2ZHZ44CBCPEXHD","MGQFD9DMYZD61RHS6KFGC5YGRG2Q56CYNX4GYBGASQ1P69N76M6P4CA3WZV163VFR71JPAXPK11BFCVVCS3A9E59WAR6R0ZWXXN5P9XJXD7DSA1PWCS0JVJ851BCMPWE54M23JGHNRJ03VE76HW8ZH45B6WGG809T8T2HQRBHBPFN3WC9NSE7NY07YWH6V3MFMVPQ2GZJ6QJP4C9D2AGM88H71PD0H65YZY07HD72F3VV1QBJX6T1GPY3NYPEHH3","KWJQX6FGX9XTEXEXYVWJ657TGZHYWHX24KEE1XA5TW5NVVQMQGQVC6HE6GA4RBC1MM0S1GWN7Q838QQEP5DQNDZS7VDBSEP7SPHC832WRN492FN8CEVSJ01AAE36HRXNM8DN6JPK160DJ4M842W9STXQRWPPF94S6HER2WZX330EZ9CECD2NKWTPTYSDGA5FVZS2GC9ERQGYP4YKZWZ8DXRJWCNVE1G7BYYPWNTHPVX0EW5F9GHT4MR29YG9YMRS","50FNFP9CQNHME6EDC0JFNXDVHW58CMC0TJRRZ0FGAYK0MAYQ9EV5WZEYBDV5Y967H72AQBJ28GXD394BDW949KGEMNSAWYE3YX5GSZZNZ9CCXEDKJJSC7W1P1Z04B9VAAM07SPWN4EMREMR9R4XXCD014YHPMMKP64C58X93FCSFJNW8XDF5FW0S2KZJHSP8FGRNQ6D62CQJCVPS615D4N52XNPWTFS1R379GVKSZ4FRR6SRTT4R3PA271HTX3ZQ","NA6QQDXM6SB52138M8CN3E4ZY7P0P9QS9AJ6EGNKYYK58XTRR4D4BANF0ARSTVZGMSJ7FP803B87J21SR2KT35V5K4FEHWVQ9WB9F9ZFMREFAA3SP3NWXNYJQQS0YA2K3RRAWJYJ2XSPQERXW71702QAEQRZQPMGXCMDKFNY9V7Q77147RQ7M87G8ZHZHX83D9C6QHKWGKTSQ0R66MZRCX29C6P6A5EGHACWVXD32Z8SA1ZPNJBDZY0PNJJM68D0","4M00E1KQVQ5KTJPXTCT3EYFN1SH975ZASNAWN7Y0NB12ANR6VZ1163GKCK9WBQJ34Q9P0G763PQ0B68WCJT2KXYXX5X3AV91BPDGGWBYB220HQ52V5VES6H7D75KYS176MA27G09X9PAGTQJ78VQHDAZCYZ5TS82D7HM5GT618605NVEYTYQYT3BA38R6V0RHYGE0CHNEXZTM0TFGDXQZ3P6CTNMYPPPM4E4PMCCQC4XR2S6CGVWYE1TXN0DC59S","N98TSJ6HGBS2N3K3MRPW6WEHBP409B4DC7PW8GMHM2QM2VGC0XQE1AQQ9AT1J4MZAK0B3RAMWF74XZT0D1CBDFABDY8M2M3X6QM7M4C8Z2DV7B2KHF3GBV4FMEG2PWAPW97QJ47383BT5XEYC4KQNXNK1K22NXYQJK0W5GS64KRFZWWKENZABG8VYZ7AYDAXMPVRSCQCCDE1RS6V8MDAVP65SAB59NSM0QQMBAPVBDTWD0P3HCZMG4F17QGTYZYP","ABT20WXHNAHYANMGCVGR9VC1QEQMS5YYRMMPS8GE04RK7XDF4CFXV9HEC1TAN77PBZJXAGX8GVZ8Y0068T84M1DQ90F2VEZGHR1JBBJ91S6RER8FKC301STT9MSF0CYBQTG5GAZK948305FBT6QRFX5BYS4NB5ZX86YMTNZ01V5C26W6Q6T78E5MHC7PH21SQ2VERSMDBWC640068HDX4PCJWBV7809DBSHR2ASJBMM32C49SG4EYVW74H4385QA","M0HBDKZV4TAYEBJJFBMMV55735T3F114RQMHBW2FRTDNNEM6NVBYR65Q25GJ1XNZJV0J7CY55CWMNEARHS2F9TYZPM0BVFZ429DVB2BTX8ZJ6Y9M1RSMVZZZM3GVE865PFEYCVG40AVC5T01Q8XGW1FDZKZTXBVCR5J7H24870S3BJB820X7MQMXDHNNT7VA4XZQJRN96JNHFC3RWB8R2X6Z4BZA9AYETNHP180MY0CJB8CJ8P9DTFHFRAY4M8WE","HV2FVXRE3NGW0WR4XMX0QZX2Z0B7MQB2ANCC95GY0FY9WD74D6CSM11YC0HNMBYCX8CTX7QJS28FGK9FC2RP79M8MKBGHHP0E3SK33AHRQ6457TSMARYKRY2SNSTV7JC8Z1KPV55EH5EH9C736G42J9W84E61JRWG8PMD24V1TS0MJZWKNP1QKSET7N40VAJXZE6B2QDPH2D7F26S4SND52B8KS1HB0NH762F41QE22ANVSXV6S2TN73Y5MXTB9S","70M04PP2WVXGK3NJCMPXGQQCCCDTRW0AF5F8N8A605DHY4CKBFFXX9F5Y512JS3CY6MD9T7K1X0ANT3N5VJRWPF9Y1S97EA2NAZ2W783DEP32Q1M3Y93VBHKCBQNM9M456VSMZA16E8SP3EGPJ9K7QVE0KYV0VWFJRXCA2CWDNNFDEKEJ6GK164SKGZ5MV1QQEDM258SKTQQ0EER895QRAA50PHNNQF1Z8MGHMZCV9WP0ZSJASVK63E4Z073TTVD","799TV24HVN9JDQBG0WFGA5FH0RNJYFJG2XF1B93W5W571CRPMEAHCAKA294YT63VV0K7C46AQYF1AVS58ZJ58CESDYWMY770P95EXPM5H38NV3F3RDTDB7EX5Q9XN0X8QRW37BTN8VBQ4PZ6Z1Y4539C7QGE2F012RBKGK47BST1TQP3XA427H1CDGT8HJBHBY8BD4TH1N7EE0XZF2QV6AJ0JCPWD0H6TKPVMGH1QYKVEKEPQBX20S8K502AYGKQ"],["23NQ8CW42D7FAY7FD7636SFA7THRQA2EGJYMFYF75FA1ZATVSMPPYSHTEC58J84PKDHRD0KPFMK811CTSGW0W274D8A3E5FKEX6P5AZ2ST0K9PK65ZP6R6CR8RMWSGQQX5VAJ2YVJ3RNV20C7YJA0CDCJNQX3JKGRX5NRY8GY3RNA38HG3SM0NW85AKZ0SXP1XRZRY0A0T3SM6E4Q6PTJMJZJ677BRZHXAGB7BEMSK6KDERXHVN9AGN4J9SZ5AY0","ZNZFHJ4X5T79G4DXBX8TPG0RV8SV4B7ZKV56CAN893MZ6Z00CNFPH6KPPXTKM8MB6MTPSCHEA0PRGRHSAKPBSAVR019GB9E75TFSXV452ZQN8Q54ZH9BJPKMAMB26X8BDQKGYK01FAWRWZXJ1TW9GVPJ9TS03WKQS64TVRNH17TTFVED3K8MFMDC9SFSJ4FZC2J19XTSWASXSY4BDE4T8Z2VGWEGDTYF0PNPMHDN2FQN2T25T6TA2DW702HM9MBC","SCC6Y84J99YQ598PR67G5VDT1N9E6S2VEZ22QWD7PQDX108ZZJ2AK16YF9PS8WSAP1PCPM0AYD1R9522XZNGWEHX92RE3R0WVM43A38450XH0EHY6XYKCK0NWJJ9XKN0FG4GACRF6X1WG4Y7AYW6FBFMBKHWDHP8BCTT0J9Q9XXZEBC88C57DMG18ABP6S248JAX9JCN0GZ4Q25AX6XYA2W2KD7CW97H23H11NS47XMC0GFKF7FDZK11JQXASJMT","PJBV9WQ064WKS9WVV0JWN3JHGNCY82T42FC0ANKNV5SEE8BBPJTQ6HXM76D8FAH00A6GNB2HMRYAAS0ZTGESRE2JFDD5HFAWW2EX9BN1QA7T6EB1G4PBFFZXVD3AN3GZKK72A4VT5AFM9QF7GHEXVWC29AHH5HH3ZHYQ1AR5TB5G7CNRCM8GA1Q61P574H0G2DWJJ35XE79D3G6SEWPCPB3VZS89B3XY9A1HV86R6BVY6C48D7FHXEA903AVVSMP","7HS65FGXB1Y1E39DHB5J0SRX8KDS7K6YBNP1XAPBQQNBM8N2T1QAVVS37XG15A2ABWK9J2CP16WCWNMG1ZCS6KEY98DXRNKNEQ099M9P392D00R8HDE1Y8C918PV0DVXKM3141CYJFXTQCYM9A5ZYKDEXNF09NTWHNDT3F990R6EWYS0TT4F4YDW9605SWTPJ2G29CKQNP13N1KKFRJS4BME8VE800YH6HTCSWTPXQ19TFXCHET6PF9EZE00RF9D","39HPW4NZCE7T1TF3ZFW6FGSSSETD2NMY5ED7T49572WAZ5FBJJSGGK8G45CQSSS488KZ2WRVM2N79ZKD78AX08X7TAW7DGWKB5KX9KRFCAF7ZZJQP5W6A1652XYNV2NWR51MS30ME0Y6RPXCMVC7K2B3HK5TFQ893HE8JJJSD2TF3AS9RGMPRBXXPCTC1R3Y5MZJQ79RKV70PVW65MA00RPMC27VGBWW5MA7FWK4X8JWQ8PHB9666MVM64AZJZSC","WFPTT5ZYQZNF2TYKSMFT6D7RP85980PTXNP6PS1HY3J5Y4ZY8DEVNPGFDP85SQ2DST4QQ1EHQQ9CHP9T1Q25XSGNKAHF9QAXX6N029SNH3C0MTG5VAQWQMCSPAYBW08EKFJS560JXX1AT9JCD0CJXZTX1P7TC4XD1JJCBDYKQ592CJZDKBCVMDN2CAG7RNXVSKQ8EWCRM7NCEF3YVWBJ7SQRE9B3BB067SVSRJQ9SB0PTGRP93WRNQ2JEGC584K8","P0VHPX17WERWA5G19P5NV2ZBWXGX3YWFTYHMSWQ2C5H82TPQ08BNDPE813NYWWT231EMTY7VRW2ZS8S447T4K5BCD7S0YQX2D92G5VRP10YTC57P16QZ37T0QZ9JENVPT6665TZ97JERST3M8SG7BD3ZDM5H0S9KCQTXXDJCR9NB1WHNJFTYZ0DJYJFDNZMTKREQG3R5VF5DQXXWKJ2GVKZG6ED2VTJR11MKYTQBMXSKP50RJYEZMVCZQ8H5KZBV","VDS1SGX5A31KBPTBPBR82C4ZD5FG2XRDM5KGVAR7X8XGXP7ZMGREXS9CYFKA9SZ3GMF0H7X4H733C81HPNDDC2NPF4443CB0KY0XSMJ34SA6TY99SE0NTZ96RZ36CZP77HRQQ93WC2EN3FBGS9WQMZEQ7GKNZSH6RBGXMF237ZGRN4FPRGX771VXY5DQXFMPTFYRDHCPWJR9FZKF7TQT0MB1K412PRFHSHM9S8FZJCHYR2PP443WF9SZWGNM2CV8","J8KEHBYBAQVMTR1XTNDY23VSTQVW5CYE2EDNRE9DBP56DV1PSC2XXFH8KKHXT8D3TM5G6MCHE0JWNHN6417G696MHY5NZ6CRAYYBNR4YBPHDF94CHBMZSXH6KD3N0AVW3F0KK88DPA9G2CZ8C82QTV8Z8C8WRRWAHRH0X6SEGK4BJPEB3WEGRMD9AFYTXCPQ0N7BXK83052V4HD6W7AB0AE7EQ789XF6C8AD4TN7ARF7MJDMTCY624B6QR5K15Y5","R5D4QJ0HM2A9E8WEVZYKG9V612D1ZRRB6RCGK4S8MDBM7NRBP7DDJGV1H7SN0JEZJSTW7DGVA7WRK0Z8HSH6VGB2NZ2CRZKZTTX15W58EB2XKJKZJYA0AR5MKTNHPP7D39PFF8BP39PJX9VRFHGXMWB84GHVMND6S2M2WWVHMBVNK2D19TJ1240NZFV6GP64416JT0QW06ZQMXVHVD4GFRESTSVBH1G78AMJ972RAHBF4DM0PJXY0PTXYWQSP2GZ","KZ0R0MPKXYKS13894TAC8SMNGYQ9F1EB9VN9S4P7VJ8KDXJEREYR64HDRAP4HBRY9D50YDKDPE9AHMW9ETR4CXK3E0YQJQ2YGPAWJ823GH7KHJXK1GTFSZ3TERT1VB31FGXC0950TY0MAHESMPHNRXSG9738C0CEJ5Z1TNBVV48WJCH2JPCKAPDMTSFYFAECZ28WJ7J9EW459NNT5H4D0DB5ZZ2CY16CCC8PBC0K4ZYP1Y2ZW5MK0N0MJTXGQ49T","YVH178SVB7QK1HM2HVSDGBZ1QJN9NRTG3RXMC9YVS74VXTW719NRFMAXKJHVZJE77HNRW53S8DSD3QTYDZ9ZNZ1185GZXP0NNP40NQFYJQSBHWVE7WDPR5KZT42BWQE1P20B3F5HCHV3VD1ZCGCZ1NF5K5P4WKT01K7XKXNGFTX9HY5YAG30THBY4S3Q3CPMQBVCBXDHW929DHRBZWHZGGGBCTVNRRNDA7J0EVBAVYYHES2PDK9YW5STCG83S5AB","MA1RKAT9SCJSXJG7T5P1QF1VW9GRBCYK03P8Z55KSCK4SN1K0MFSXR3YERD4VA5QQ1N7KKHPDAPNYHQ6QW2TPBVM932A5G42VEKZ9CH5ZH7346RKDT8BMNSFYQ799W6042CCJ3JSESFYMER8JHZNBVFWFGMKMJJ642BCP9PPA9H7B0XSSGK2CZYWK3RQX5WKZK4V40AMTRJ9JRZNX7QKXRN9W464J3X3BRYHR8Y70C42HH0HVW86CPNVKWE0Q36C","K8CP0BM60F6P218ZMC4HW307DNN3FHHEG3XMWN55KEZR4RQ86ADXGJF2FKD7QW2TVQ3AWN2KVJ6QMP6SFJHF11C6T68FWKWMQVGQWYY28591XTQ3D78FB9N06T2W3R6EERTHRQNK7X9WP2BV3VM43A39YXVJ0W0BHJ0XSZQENN218ZR4GTVDX48788WXFD6064ZXGMWGD2EKWMS4BBVWK59FVZPGDRQD6EN3TRA784HBBWE831JWBEVX3YGPX9T0","QC2WWZPKJDCFZA65QKSGKW7YTAS9RP0W4H0FP96Z5TGCCD0K9FXFX4F75MQEDNKCM0B34D8ZR46CHR97HMMEB3W2T8W6P8X5289Z729365HVDQWCGHMJSGM7AHA1HS6ZND695X67D42H7XB7NQ5X57XG2S32R767YPQJERZ0ESG3S01NGNQ0P62KM3AT28JX41GMHPEA92V1Z80RYS8GWE9CGZ6K66NVGW72SN8DJGDFVC7771HP93X6DYN0TF63","H3P6CNRKH4BSCAWG3T9RRA89EBF1F91JEYEY4RZJQ2NNCZZASY362XHME0KNM36R4SNQD956CBW15XAXVK70TZM6TBVMHJ8KKQQQKBG4Q91ZHKAS10NEVD5B36QGYM7CMJM3DVJ00KTK0ZAM8C4YRNZDZKV5CNFGDR0DDP1P38704Y3G9KFRJ455SD39J7ZYDB5GQV17ZF2PE7GY927S1KSXV4KKXQ7FRX1VZRJGAD1F3DY4KJFRZJGAT5951JNS"]]} diff --git a/src/testing/baseline/refresh_reveal.req b/src/testing/baseline/refresh_reveal.req new file mode 100644 index 000000000..3fb143960 --- /dev/null +++ b/src/testing/baseline/refresh_reveal.req @@ -0,0 +1,7 @@ +POST /refresh/reveal HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json +Content-Length: 255 + +{"session_hash":"V97SB8T670M9V71D1Q0KVQ4GSJCVQ5AAKTTH9QKT0ZJZZBFNZAV4NA8NMWRRGVPFEBEGB6ANCN9BPQASJ40TM4Y1C49648TJJ07PGSG","transfer_privs":[["EQKJA401A9NJ2YJDFZJ1EV8AYXBHWZB6NT5T0TWSJHVKVDM6W8A0"],["TKDJ4DF3GZVG0DGAB9E3RGBGSTANYB6JVVWXJGPMB2AY4VQNTBA0"]]} \ No newline at end of file diff --git a/src/testing/baseline/reserve_status.req b/src/testing/baseline/reserve_status.req new file mode 100644 index 000000000..4f988f669 --- /dev/null +++ b/src/testing/baseline/reserve_status.req @@ -0,0 +1,4 @@ +GET /reserve/status?reserve_pub=TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0 HTTP/1.1 +Host: localhost:8081 +Accept: */* + diff --git a/src/testing/baseline/reserve_withdraw.req b/src/testing/baseline/reserve_withdraw.req new file mode 100644 index 000000000..484950250 --- /dev/null +++ b/src/testing/baseline/reserve_withdraw.req @@ -0,0 +1,7 @@ +POST /reserve/withdraw HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json +Content-Length: 919 + +{"coin_ev":"Q5X8A8TCBFH7E5BMY7HSB17SHFTM1JPJGV61P2CA7Z9EXG8P2HYS69B31NZESKXHSZHNJ2DQN3CC2AWFNC6V90J577JD3TXBMAY8Y5M9V60KKT73Z1DW24JFSNAK91G1F2WT55ADP1EG7N5F9AY7A7ZJD03MPYSH0RDP7SVZS2KRPA5JRHFR4GDJ59CFNE7A43M95ZKQHQAS8","denom_pub":"51R7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30GT58S2K2HJ16H336C9N8CVK4E9N6H1MADHH61330HHM6N1K8E1H8RVKJH256D1M6E1K8RWKJGSH8S2M6DJ170TK2H266GTK8DSS64RKJDJ26D144DJ474SK0GHQ711MAD9G752M2CJ58S1KJDA570SK2E9G8N23GCJ28S146DHH610K2H1Q8CW3GGA16S146H9G68TKACSQ6914CE1H691K2E9N6RWM8H9P8CWM2H9S8GSK0H9P6D1K6H9G6X0M4C2171144HJ46N334H9J692M4H9M8MR4CCJ46GRKEGA46533CDJ38MV4CH9K892MAH1P8S2K6D9K6N246E256H244G9Q6D346GJ56S23JGHJ690KADHJ8H242H2575132CSM6X1M4G9N6RR48E9H8MVM8E9354520818CMG26C1H60R30C935452081918G2J2G0","reserve_pub":"TMZCK5CFM1KZQGY1WTF0CEZZPGA0670G94969RF79PA5106ARTK0","reserve_sig":"8427B3RTB217124EB1C37ZVJFC08KN17RHGHE9ENZQMQVJ0S11SAX6H8Z06SWCKT06DRQ9DQ8XD786XKQ94T27PYR9GC9EMT1Y02W10"} \ No newline at end of file diff --git a/src/testing/baseline/wire.req b/src/testing/baseline/wire.req new file mode 100644 index 000000000..a4f1d0749 --- /dev/null +++ b/src/testing/baseline/wire.req @@ -0,0 +1,5 @@ +GET /wire HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json + diff --git a/src/testing/baseline/wire_sepa.req b/src/testing/baseline/wire_sepa.req new file mode 100644 index 000000000..80d3d4619 --- /dev/null +++ b/src/testing/baseline/wire_sepa.req @@ -0,0 +1,5 @@ +GET /wire/sepa HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json + diff --git a/src/testing/baseline/wire_test.req b/src/testing/baseline/wire_test.req new file mode 100644 index 000000000..684352c96 --- /dev/null +++ b/src/testing/baseline/wire_test.req @@ -0,0 +1,5 @@ +GET /wire/test HTTP/1.1 +Host: localhost:8081 +Accept: */* +Content-Type: application/json + diff --git a/src/testing/test-taler-exchange-aggregator-postgres.conf b/src/testing/test-taler-exchange-aggregator-postgres.conf new file mode 100644 index 000000000..7f22acd29 --- /dev/null +++ b/src/testing/test-taler-exchange-aggregator-postgres.conf @@ -0,0 +1,98 @@ +[PATHS] +# Persistant data storage for the testcase +TALER_TEST_HOME = test_taler_exchange_httpd_home/ + +[taler] +# Currency supported by the exchange (can only be one) +CURRENCY = EUR + +[exchange] +# The DB plugin to use +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 = "https://exchange.taler.net/" + +[auditor] +BASE_URL = "http://auditor.example.com/" + +[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 + +[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 + +[account-1] + +# What is the account URL? +URL = "payto://x-taler-bank/localhost/2" +WIRE_GATEWAY_URL = "http://localhost:8082/2/" +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x +method = "x-taler-bank" +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES +TALER_BANK_AUTH_METHOD = NONE + +[bank] +HTTP_PORT = 8082 + +[fees-x-taler-bank] + +# Fees for the forseeable future... +# If you see this after 2018, update to match the next 10 years... +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 + +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 diff --git a/src/testing/test-taler-exchange-wirewatch-postgres.conf b/src/testing/test-taler-exchange-wirewatch-postgres.conf new file mode 100644 index 000000000..ae5cd7ef6 --- /dev/null +++ b/src/testing/test-taler-exchange-wirewatch-postgres.conf @@ -0,0 +1,105 @@ +[PATHS] +# Persistant data storage for the testcase +TALER_TEST_HOME = test_taler_exchange_httpd_home/ + +[taler] +# Currency supported by the exchange (can only be one) +CURRENCY = EUR + +[exchange] +# The DB plugin to use +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 + +[account-1] + +# What is the account URL? +URL = "payto://x-taler-bank/localhost/2" +WIRE_GATEWAY_URL = "http://localhost:8082/2/" + +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x + +METHOD = x-taler-bank +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json +PLUGIN = "taler_bank" +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES +TALER_BANK_AUTH_METHOD = NONE + +[bank] +HTTP_PORT = 8082 + +[fees-x-taler-bank] + +# Fees for the forseeable future... +# If you see this after 2018, update to match the next 10 years... +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 + +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 + +# Need at least one coin, otherwise Exchange +# refuses to start. +[coin_eur_ct_1] +value = EUR:0.01 +duration_overlap = 5 minutes +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 + diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c new file mode 100644 index 000000000..922361026 --- /dev/null +++ b/src/testing/test_auditor_api.c @@ -0,0 +1,710 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/test_auditor_api.c + * @brief testcase to test auditor's HTTP API interface + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_auditor_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_auditor_api.conf" + +#define CONFIG_FILE_EXPIRE_RESERVE_NOW \ + "test_auditor_api_expire_reserve_now.conf" + +/** + * Exchange configuration data. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + +/** + * Execute the taler-exchange-wirewatch command with + * our configuration file. + * + * @param label label to use for the command. + */ +#define CMD_EXEC_WIREWATCH(label) \ + TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE) + +/** + * Execute the taler-exchange-aggregator command with + * our configuration file. + * + * @param label label to use for the command. + */ +#define CMD_EXEC_AGGREGATOR(label) \ + TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE) + +/** + * Run wire transfer of funds from some user's account to the + * exchange. + * + * @param label label to use for the command. + * @param amount amount to transfer, i.e. "EUR:1" + */ +#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ + TALER_TESTING_cmd_admin_add_incoming (label, amount, \ + &bc.exchange_auth, \ + bc.user42_payto) + +/** + * Run the taler-auditor. + * + * @param label label to use for the command. + */ +#define CMD_RUN_AUDITOR(label) \ + TALER_TESTING_cmd_exec_auditor (label, CONFIG_FILE) + +/** + * Run the taler-wire-auditor. + * + * @param label label to use for the command. + */ +#define CMD_RUN_WIRE_AUDITOR(label) \ + TALER_TESTING_cmd_exec_wire_auditor (label, CONFIG_FILE) + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + /** + * Test withdraw. + */ + struct TALER_TESTING_Command withdraw[] = { + /** + * Move money to the exchange's bank account. + */ + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer + ("check-create-reserve-1", + "EUR:5.01", bc.user42_payto, bc.exchange_payto, + "create-reserve-1"), + /** + * Make a reserve exist, according to the previous transfer. + */ + CMD_EXEC_WIREWATCH ("wirewatch-1"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1", + "create-reserve-1", + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command spend[] = { + /** + * Spend the coin. + */ + TALER_TESTING_cmd_deposit ("deposit-simple", + "withdraw-coin-1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command refresh[] = { + /* Fill reserve with EUR:5, 1ct is for fees. NOTE: the old + * test-suite gave a account number of _424_ to the user at + * this step; to type less, here the _42_ number is reused. + * Does this change the tests semantics? */// + CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer + ("check-refresh-create-reserve-1", + "EUR:5.01", bc.user42_payto, bc.exchange_payto, + "refresh-create-reserve-1"), + /** + * Make previous command effective. + */ + CMD_EXEC_WIREWATCH ("wirewatch-2"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1", + "refresh-create-reserve-1", + "EUR:5", + MHD_HTTP_OK), + /** + * Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in + * full) Merchant receives EUR:0.99 due to 1 ct deposit fee. + */ + TALER_TESTING_cmd_deposit ("refresh-deposit-partial", + "refresh-withdraw-coin-1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:1\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + /** + * Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x + * EUR:0.13) */ + TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1", + "refresh-withdraw-coin-1", + MHD_HTTP_OK, + NULL), + /** + * Complete (successful) melt operation, and withdraw the coins + */ + TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1", + "refresh-melt-1", + MHD_HTTP_OK), + /** + * Try to spend a refreshed EUR:0.1 coin + */ + TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b", + "refresh-reveal-1", + 3, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:0.1", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command track[] = { + /** + * Run transfers. Note that _actual_ aggregation will NOT + * happen here, as each deposit operation is run with a + * fresh merchant public key! NOTE: this comment comes + * "verbatim" from the old test-suite, and IMO does not explain + * a lot!*/// + CMD_EXEC_AGGREGATOR ("run-aggregator"), + + /** + * Check all the transfers took place. + */ + TALER_TESTING_cmd_check_bank_transfer + ("check_bank_transfer-499c", ec.exchange_url, + "EUR:4.98", bc.exchange_payto, bc.user42_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check_bank_transfer-99c1", ec.exchange_url, + "EUR:0.98", bc.exchange_payto, bc.user42_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check_bank_transfer-99c", ec.exchange_url, + "EUR:0.08", bc.exchange_payto, bc.user43_payto), + + /* The following transactions got originated within + * the "massive deposit confirms" batch. */ + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-1", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-2", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-3", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-4", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-5", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-6", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-7", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-8", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-9", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_transfer + ("check-massive-transfer-10", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, bc.user43_payto), + TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"), + TALER_TESTING_cmd_end () + }; + + /** + * This block checks whether a wire deadline + * very far in the future does NOT get aggregated now. + */ + struct TALER_TESTING_Command unaggregation[] = { + TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"), + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated", + "EUR:5.01"), + CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"), + /* "consume" reserve creation transfer. */ + TALER_TESTING_cmd_check_bank_admin_transfer ( + "check_bank_transfer-unaggregated", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "create-reserve-unaggregated"), + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", + "create-reserve-unaggregated", + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit ("deposit-unaggregated", + "withdraw-coin-unaggregated", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_YEARS, + 3000), + "EUR:5", + MHD_HTTP_OK), + CMD_EXEC_AGGREGATOR ("aggregation-attempt"), + TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-b"), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command refund[] = { + /** + * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config. + */ + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1", + "EUR:5.01"), + /** + * Run wire-watch to trigger the reserve creation. + */ + CMD_EXEC_WIREWATCH ("wirewatch-3"), + /** + * Withdraw a 5 EUR coin, at fee of 1 ct + */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1", + "create-reserve-r1", + "EUR:5", + MHD_HTTP_OK), + /** + * Spend 5 EUR of the 5 EUR coin (in full). Merchant would + * receive EUR:4.99 due to 1 ct deposit fee. + */ + TALER_TESTING_cmd_deposit ("deposit-refund-1", + "withdraw-coin-r1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_MINUTES, + "EUR:5", + MHD_HTTP_OK), + + TALER_TESTING_cmd_refund ("refund-ok", + MHD_HTTP_OK, + "EUR:5", + "EUR:0.01", + "deposit-refund-1"), + /** + * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone + * due to refund) (merchant would receive EUR:4.98 due to + * 1 ct deposit fee) */ + TALER_TESTING_cmd_deposit ("deposit-refund-2", + "withdraw-coin-r1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"more\",\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:4.99", + MHD_HTTP_OK), + /** + * Run transfers. This will do the transfer as refund deadline was + * 0. + */ + CMD_EXEC_AGGREGATOR ("run-aggregator-3"), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command recoup[] = { + /** + * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per + * config. + */ + CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1", + "EUR:5.01"), + /** + * Run wire-watch to trigger the reserve creation. + */ + CMD_EXEC_WIREWATCH ("wirewatch-4"), + /** + * Withdraw a 5 EUR coin, at fee of 1 ct + */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1", + "recoup-create-reserve-1", + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_revoke ("revoke-1", + MHD_HTTP_OK, + "recoup-withdraw-coin-1", + CONFIG_FILE), + TALER_TESTING_cmd_recoup ("recoup-1", + MHD_HTTP_OK, + "recoup-withdraw-coin-1", + "EUR:5", + NULL), + /** + * Re-withdraw from this reserve + */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2", + "recoup-create-reserve-1", + "EUR:1", + MHD_HTTP_OK), + /** + * These commands should close the reserve because the aggregator + * is given a config file that ovverrides the reserve expiration + * time (making it now-ish) + */CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve", + "EUR:5.01"), + TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation", + CONFIG_FILE_EXPIRE_RESERVE_NOW), + TALER_TESTING_cmd_exec_aggregator ("close-reserves", + CONFIG_FILE_EXPIRE_RESERVE_NOW), + /** + * Fill reserve with EUR:2.02, as withdraw fee is 1 ct per + * config, then withdraw two coin, partially spend one, and + * then have the rest paid back. Check deposit of other coin + * fails. (Do not use EUR:5 here as the EUR:5 coin was + * revoked and we did not bother to create a new one...) + */CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2", + "EUR:2.02"), + /** + * Make previous command effective. + */ + CMD_EXEC_WIREWATCH ("wirewatch-5"), + /** + * Withdraw a 1 EUR coin, at fee of 1 ct + */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a", + "recoup-create-reserve-2", + "EUR:1", + MHD_HTTP_OK), + /** + * Withdraw a 1 EUR coin, at fee of 1 ct + */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b", + "recoup-create-reserve-2", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit ("recoup-deposit-partial", + "recoup-withdraw-coin-2a", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:0.5", + MHD_HTTP_OK), + TALER_TESTING_cmd_revoke ("revoke-2", + MHD_HTTP_OK, + "recoup-withdraw-coin-2a", + CONFIG_FILE), + TALER_TESTING_cmd_recoup ("recoup-2", + MHD_HTTP_OK, + "recoup-withdraw-coin-2a", + "EUR:0.5", + NULL), + TALER_TESTING_cmd_end () + }; + + + struct TALER_TESTING_Command massive_deposit_confirms[] = { + + /** + * Move money to the exchange's bank account. + */ + CMD_TRANSFER_TO_EXCHANGE ("massive-reserve", + "EUR:10.10"), + TALER_TESTING_cmd_check_bank_admin_transfer + ("check-massive-transfer", + "EUR:10.10", + bc.user42_payto, bc.exchange_payto, + "massive-reserve"), + CMD_EXEC_WIREWATCH ("massive-wirewatch"), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-2", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-3", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-4", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-5", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-6", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-7", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-8", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-9", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-10", + "massive-reserve", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-1", + "massive-withdraw-1", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-2", + "massive-withdraw-2", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-3", + "massive-withdraw-3", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-4", + "massive-withdraw-4", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-5", + "massive-withdraw-5", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-6", + "massive-withdraw-6", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-7", + "massive-withdraw-7", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-8", + "massive-withdraw-8", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-9", + "massive-withdraw-9", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("massive-deposit-10", + "massive-withdraw-10", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit_confirmation ("deposit-confirmation", + is->auditor, + "massive-deposit-10", + 0, + "EUR:0.99", + MHD_HTTP_OK), + CMD_RUN_AUDITOR ("massive-auditor"), + + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command commands[] = { + CMD_RUN_AUDITOR ("virgin-auditor"), + CMD_RUN_WIRE_AUDITOR ("virgin-wire-auditor"), + TALER_TESTING_cmd_exchanges_with_url ("check-exchange", + MHD_HTTP_OK, + "http://localhost:8081/"), + TALER_TESTING_cmd_batch ("massive-deposit-confirms", + massive_deposit_confirms), + TALER_TESTING_cmd_batch ("withdraw", + withdraw), + TALER_TESTING_cmd_batch ("spend", + spend), + TALER_TESTING_cmd_batch ("refresh", + refresh), + TALER_TESTING_cmd_batch ("track", + track), + TALER_TESTING_cmd_batch ("unaggregation", + unaggregation), + TALER_TESTING_cmd_batch ("refund", + refund), + TALER_TESTING_cmd_batch ("recoup", + recoup), + CMD_RUN_AUDITOR ("normal-auditor"), + CMD_RUN_WIRE_AUDITOR ("normal-wire-auditor"), + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run_with_fakebank (is, + commands, + bc.exchange_auth.wire_gateway_url); +} + + +int +main (int argc, + char *const *argv) +{ + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-auditor-api", + "INFO", + NULL); + /* Check fakebank port is available and get configuration data. */ + if (GNUNET_OK != + TALER_TESTING_prepare_fakebank (CONFIG_FILE, + "account-2", + &bc)) + return 77; + TALER_TESTING_cleanup_files (CONFIG_FILE); + /* @helpers. Run keyup, create tables, ... Note: it + * fetches the port number from config in order to see + * if it's available. */ + switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, + &ec)) + { + case GNUNET_SYSERR: + GNUNET_break (0); + return 1; + case GNUNET_NO: + return 77; + case GNUNET_OK: + if (GNUNET_OK != + /* Set up event loop and reschedule context, plus + * start/stop the exchange. It calls TALER_TESTING_setup + * which creates the 'is' object. + */ + TALER_TESTING_auditor_setup (&run, + NULL, + CONFIG_FILE)) + return 1; + break; + default: + GNUNET_break (0); + return 1; + } + return 0; +} + + +/* end of test_auditor_api.c */ diff --git a/src/testing/test_auditor_api.conf b/src/testing/test_auditor_api.conf new file mode 100644 index 000000000..7bb57c3a9 --- /dev/null +++ b/src/testing/test_auditor_api.conf @@ -0,0 +1,210 @@ + +# This file is in the public domain. +# +[PATHS] +# Persistant data storage for the testcase +TALER_TEST_HOME = test_exchange_api_home/ + +[taler] +# Currency supported by the exchange (can only be one) +CURRENCY = EUR + +[auditor] +BASE_URL = "http://localhost:8083/" + +# HTTP port the auditor listens to +PORT = 8083 + +TINY_AMOUNT = EUR:0.01 + +[exchange] + +# how long is one signkey valid? +signkey_duration = 4 weeks + +# how long are the signatures with the signkey valid? +legal_duration = 2 years + +# how long do we provide to clients denomination and signing keys +# ahead of time? +lookahead_provide = 4 weeks 1 day + +# 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/" + +# Keep it short so the test runs fast. +LOOKAHEAD_SIGN = 12 h + +[exchangedb-postgres] +CONFIG = "postgres:///talercheck" + +[auditordb-postgres] +CONFIG = "postgres:///talercheck" + +# Sections starting with "account-" configure the bank accounts +# of the exchange. The "URL" specifies the account in +# payto://-format, while the WIRE_JSON specifies the +# (possibly offline) signed version to be returned in /wire. +# WIRE_JSON is optional, as not all accounts must be +# advertised in /wire. +[account-1] +# What is the URL of our account? +URL = "payto://x-taler-bank/localhost/42" +WIRE_GATEWAY_URL = "http://localhost:8082/42/" +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json + +# Which wire plugin should we used to access the account? +METHOD = x-taler-bank + +[bank] +HTTP_PORT = 8082 + +# ENABLE_CREDIT = YES + +[account-2] +# What is the bank account (with the "Taler Bank" demo system)? +WIRE_GATEWAY_URL = "http://localhost:8082/2/" +URL = "payto://x-taler-bank/localhost/2" + +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json + +# Which wire plugin should we used to access the account? +METHOD = x-taler-bank + +# Authentication information for basic authentication +WIRE_GATEWAY_AUTH_METHOD = "basic" +USERNAME = user +PASSWORD = pass + +ENABLE_DEBIT = YES + +ENABLE_CREDIT = YES + + +# Sections starting with "fee-" configure the wire fee for the +# respective wire method. +[fees-iban] +# Fees for the forseeable future... +# If you see this after 2017, update to match the next 10 years... +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 + +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 + +[fees-x-taler-bank] +# Fees for the forseeable future... +# If you see this after 2017, update to match the next 10 years... +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 + +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 + +# 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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_auditor_api_expire_reserve_now.conf b/src/testing/test_auditor_api_expire_reserve_now.conf new file mode 100644 index 000000000..c2bf8f479 --- /dev/null +++ b/src/testing/test_auditor_api_expire_reserve_now.conf @@ -0,0 +1,4 @@ +@INLINE@ test_auditor_api.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 new file mode 100644 index 000000000..62277e828 --- /dev/null +++ b/src/testing/test_auditor_api_version.c @@ -0,0 +1,163 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/test_auditor_api_version.c + * @brief testcase to test auditor's HTTP API interface to fetch /version + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_auditor_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_auditor_api.conf" + +static struct TALER_AUDITOR_Handle *ah; + +static struct GNUNET_CURL_Context *ctx; + +static struct GNUNET_CURL_RescheduleContext *rc; + +static int global_ret; + +static struct GNUNET_SCHEDULER_Task *tt; + +static void +do_shutdown (void *cls) +{ + (void) cls; + + if (NULL != tt) + { + GNUNET_SCHEDULER_cancel (tt); + tt = NULL; + } + TALER_AUDITOR_disconnect (ah); + GNUNET_CURL_fini (ctx); + GNUNET_CURL_gnunet_rc_destroy (rc); +} + + +static void +do_timeout (void *cls) +{ + (void) cls; + tt = NULL; + global_ret = 3; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Function called with information about the auditor. + * + * @param cls closure + * @param vi basic information about the auditor + * @param compat protocol compatibility information + */ +static void +version_cb (void *cls, + const struct TALER_AUDITOR_VersionInformation *vi, + enum TALER_AUDITOR_VersionCompatibility compat) +{ + if ( (NULL != vi) && + (TALER_AUDITOR_VC_MATCH == compat) ) + global_ret = 0; + else + global_ret = 2; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls) +{ + const char *auditor_url = "http://localhost:8083/"; + + (void) cls; + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + ah = TALER_AUDITOR_connect (ctx, + auditor_url, + &version_cb, + NULL); + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &do_timeout, + NULL); +} + + +int +main (int argc, + char *const *argv) +{ + struct GNUNET_OS_Process *proc; + + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-auditor-api-version", + "INFO", + NULL); + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor-httpd", + "taler-auditor-httpd", + "-c", CONFIG_FILE, + NULL); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to run `taler-auditor-httpd`," + " is your PATH correct?\n"); + return 77; + } + GNUNET_SCHEDULER_run (&run, + NULL); + GNUNET_OS_process_kill (proc, SIGTERM); + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_destroy (proc); + return global_ret; +} + + +/* end of test_auditor_api_version.c */ diff --git a/src/testing/test_bank_api.c b/src/testing/test_bank_api.c new file mode 100644 index 000000000..e7d2aefae --- /dev/null +++ b/src/testing/test_bank_api.c @@ -0,0 +1,186 @@ +/* + This file is part of TALER + Copyright (C) 2016-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ +/** + * @file testing/test_bank_api.c + * @brief testcase to test bank's HTTP API + * interface against the fakebank + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_bank_service.h" +#include "taler_exchange_service.h" +#include +#include +#include +#include "taler_testing_lib.h" + +#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank.conf" +#define CONFIG_FILE_PYBANK "test_bank_api_pybank.conf" + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + +/** + * Handle to the Py-bank daemon. + */ +static struct GNUNET_OS_Process *bankd; + +/** + * Flag indicating whether the test is running against the + * Fakebank. Set up at runtime. + */ +static int with_fakebank; + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_WireTransferIdentifierRawP wtid; + + memset (&wtid, 42, sizeof (wtid)); + + { + struct TALER_TESTING_Command commands[] = { + TALER_TESTING_cmd_bank_credits ("history-0", + &bc.exchange_auth, + NULL, + 1), + TALER_TESTING_cmd_admin_add_incoming ("credit-1", + "KUDOS:5.01", + &bc.exchange_auth, + bc.user42_payto), + TALER_TESTING_cmd_bank_credits ("history-1c", + &bc.exchange_auth, + NULL, + 5), + TALER_TESTING_cmd_bank_debits ("history-1d", + &bc.exchange_auth, + NULL, + 5), + TALER_TESTING_cmd_admin_add_incoming ("credit-2", + "KUDOS:3.21", + &bc.exchange_auth, + bc.user42_payto), + TALER_TESTING_cmd_transfer ("debit-1", + "KUDOS:3.22", + &bc.exchange_auth, + bc.exchange_payto, + bc.user42_payto, + &wtid, + "http://exchange.example.com/"), + TALER_TESTING_cmd_bank_debits ("history-2b", + &bc.exchange_auth, + NULL, + 5), + TALER_TESTING_cmd_end () + }; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Bank serves at `%s'\n", + bc.exchange_auth.wire_gateway_url); + if (GNUNET_YES == with_fakebank) + TALER_TESTING_run_with_fakebank (is, + commands, + bc.exchange_auth.wire_gateway_url); + else + TALER_TESTING_run (is, + commands); + } +} + + +int +main (int argc, + char *const *argv) +{ + int rv; + const char *cfgfilename; + + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-bank-api", + "DEBUG", + NULL); + with_fakebank = TALER_TESTING_has_in_name (argv[0], + "_with_fakebank"); + if (GNUNET_YES == with_fakebank) + { + TALER_LOG_DEBUG ("Running against the Fakebank.\n"); + cfgfilename = CONFIG_FILE_FAKEBANK; + if (GNUNET_OK != + TALER_TESTING_prepare_fakebank (CONFIG_FILE_FAKEBANK, + "account-2", + &bc)) + { + GNUNET_break (0); + return 77; + } + } + else + { + TALER_LOG_DEBUG ("Running against the Pybank.\n"); + cfgfilename = CONFIG_FILE_PYBANK; + if (GNUNET_OK != + TALER_TESTING_prepare_bank (CONFIG_FILE_PYBANK, + "account-2", + &bc)) + { + GNUNET_break (0); + return 77; + } + + if (NULL == (bankd = TALER_TESTING_run_bank (CONFIG_FILE_PYBANK, + bc.exchange_auth. + wire_gateway_url))) + { + GNUNET_break (0); + return 77; + } + } + + rv = (GNUNET_OK == TALER_TESTING_setup (&run, + NULL, + cfgfilename, + NULL, + GNUNET_NO)) ? 0 : 1; + if (GNUNET_NO == with_fakebank) + { + + GNUNET_OS_process_kill (bankd, + SIGKILL); + GNUNET_OS_process_wait (bankd); + GNUNET_OS_process_destroy (bankd); + } + return rv; +} + + +/* end of test_bank_api.c */ diff --git a/src/testing/test_bank_api_fakebank.conf b/src/testing/test_bank_api_fakebank.conf new file mode 100644 index 000000000..5c9e5e3a5 --- /dev/null +++ b/src/testing/test_bank_api_fakebank.conf @@ -0,0 +1,17 @@ +# This file is in the public domain. + +[taler] +currency = KUDOS + +[account-2] +URL = payto://x-taler-bank/localhost/2 +METHOD = x-taler-bank +WIRE_GATEWAY_URL = "http://localhost:8081/2/" +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x + +[bank] +SERVE = http +HTTP_PORT = 8081 +DATABASE = postgres:///talercheck diff --git a/src/testing/test_bank_api_fakebank_twisted.conf b/src/testing/test_bank_api_fakebank_twisted.conf new file mode 100644 index 000000000..4455ac743 --- /dev/null +++ b/src/testing/test_bank_api_fakebank_twisted.conf @@ -0,0 +1,34 @@ + +[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 + +[taler] +currency = KUDOS + +[bank] +serve = http +http_port = 8081 +database = postgres:///talercheck + +[account-1] +URL = payto://x-taler-bank/localhost:8081/1 + +[account-2] +URL = payto://x-taler-bank/localhost:8081/2 diff --git a/src/testing/test_bank_api_pybank.conf b/src/testing/test_bank_api_pybank.conf new file mode 100644 index 000000000..1d5f4a2d1 --- /dev/null +++ b/src/testing/test_bank_api_pybank.conf @@ -0,0 +1,17 @@ +# This file is in the public domain. + +[taler] +currency = KUDOS + +[account-2] +URL = payto://x-taler-bank/localhost/Exchange +METHOD = x-taler-bank +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 diff --git a/src/testing/test_bank_api_pybank_twisted.conf b/src/testing/test_bank_api_pybank_twisted.conf new file mode 100644 index 000000000..a2085c38e --- /dev/null +++ b/src/testing/test_bank_api_pybank_twisted.conf @@ -0,0 +1,46 @@ +[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 + + +[taler] +currency = KUDOS + + +[bank] +serve = http +http_port = 8081 +database = postgres:///talercheck + + +[account-1] +URL = payto://x-taler-bank/localhost/1 + + +[account-2] +URL = payto://x-taler-bank/localhost/Exchange +METHOD = x-taler-bank +WIRE_GATEWAY_URL = "http://localhost:8888/taler-wire-gateway/Exchange/" +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x + + +[bank] +HTTP_PORT = 8081 diff --git a/src/testing/test_bank_api_twisted.c b/src/testing/test_bank_api_twisted.c new file mode 100644 index 000000000..fc167c1e1 --- /dev/null +++ b/src/testing/test_bank_api_twisted.c @@ -0,0 +1,221 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/test_bank_api_with_fakebank_twisted.c + * @author Marcello Stanisci + * @author Sree Harsha Totakura + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" +#include +#include + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank_twisted.conf" + +/** + * Separate config file for running with the pybank. + */ +#define CONFIG_FILE_PYBANK "test_bank_api_pybank_twisted.conf" + +/** + * True when the test runs against Fakebank. + */ +static int with_fakebank; + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + +/** + * (real) Twister URL. Used at startup time to check if it runs. + */ +static char *twister_url; + +/** + * Twister process. + */ +static struct GNUNET_OS_Process *twisterd; + +/** + * Python bank process handle. + */ +static struct GNUNET_OS_Process *bankd; + + +/** + * Main function that will tell + * the interpreter what commands to run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + + struct TALER_TESTING_Command commands[] = { + /** + * Can't use the "wait service" CMD here because the + * fakebank runs inside the same process of the test. + */ + TALER_TESTING_cmd_wait_service ("wait-service", + twister_url), + TALER_TESTING_cmd_bank_credits ("history-0", + &bc.exchange_auth, + NULL, + 5), + TALER_TESTING_cmd_end () + }; + + if (GNUNET_YES == with_fakebank) + TALER_TESTING_run_with_fakebank (is, + commands, + bc.exchange_auth.wire_gateway_url); + else + TALER_TESTING_run (is, + commands); +} + + +/** + * Kill, wait, and destroy convenience function. + * + * @param process process to purge. + */ +static void +purge_process (struct GNUNET_OS_Process *process) +{ + GNUNET_OS_process_kill (process, SIGINT); + GNUNET_OS_process_wait (process); + GNUNET_OS_process_destroy (process); +} + + +int +main (int argc, + char *const *argv) +{ + unsigned int ret; + const char *cfgfilename; + + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-bank-api-with-(fake)bank-twisted", + "DEBUG", + NULL); + + with_fakebank = TALER_TESTING_has_in_name (argv[0], + "_with_fakebank"); + + if (with_fakebank) + cfgfilename = CONFIG_FILE_FAKEBANK; + else + cfgfilename = CONFIG_FILE_PYBANK; + + if (NULL == (twister_url = TALER_TESTING_prepare_twister + (cfgfilename))) + { + GNUNET_break (0); + return 77; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "twister_url is %s\n", + twister_url); + if (NULL == (twisterd = TALER_TESTING_run_twister (cfgfilename))) + { + GNUNET_break (0); + GNUNET_free (twister_url); + return 77; + } + + if (GNUNET_YES == with_fakebank) + { + TALER_LOG_DEBUG ("Running against the Fakebank.\n"); + if (GNUNET_OK != + TALER_TESTING_prepare_fakebank (cfgfilename, + "account-2", + &bc)) + { + GNUNET_break (0); + GNUNET_free (twister_url); + return 77; + } + } + else + { + TALER_LOG_DEBUG ("Running against the Pybank.\n"); + if (GNUNET_OK != + TALER_TESTING_prepare_bank (cfgfilename, + "account-2", + &bc)) + { + GNUNET_break (0); + GNUNET_free (twister_url); + return 77; + } + + if (NULL == (bankd = TALER_TESTING_run_bank (cfgfilename, + bc.exchange_auth. + wire_gateway_url))) + { + GNUNET_break (0); + GNUNET_free (twister_url); + return 77; + } + } + + ret = TALER_TESTING_setup (&run, + NULL, + cfgfilename, + NULL, + GNUNET_NO); + purge_process (twisterd); + + if (GNUNET_NO == with_fakebank) + { + GNUNET_OS_process_kill (bankd, + SIGKILL); + GNUNET_OS_process_wait (bankd); + GNUNET_OS_process_destroy (bankd); + } + + GNUNET_free (twister_url); + if (GNUNET_OK == ret) + return 0; + + return 1; +} + + +/* end of test_bank_api_twisted.c */ diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c new file mode 100644 index 000000000..84d5dc9b4 --- /dev/null +++ b/src/testing/test_exchange_api.c @@ -0,0 +1,832 @@ +/* + This file is part of TALER + Copyright (C) 2014--2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/test_exchange_api.c + * @brief testcase to test exchange's HTTP API interface + * @author Sree Harsha Totakura + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_exchange_api.conf" + +#define CONFIG_FILE_EXPIRE_RESERVE_NOW \ + "test_exchange_api_expire_reserve_now.conf" + + +/** + * Exchange configuration data. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + + +/** + * Execute the taler-exchange-wirewatch command with + * our configuration file. + * + * @param label label to use for the command. + */ +#define CMD_EXEC_WIREWATCH(label) \ + TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE) + +/** + * Execute the taler-exchange-aggregator command with + * our configuration file. + * + * @param label label to use for the command. + */ +#define CMD_EXEC_AGGREGATOR(label) \ + TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE) + +/** + * Run wire transfer of funds from some user's account to the + * exchange. + * + * @param label label to use for the command. + * @param amount amount to transfer, i.e. "EUR:1" + */ +#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ + TALER_TESTING_cmd_admin_add_incoming (label, amount, \ + &bc.exchange_auth, \ + bc.user42_payto) + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + * @param is interpreter we use to run commands + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + /** + * Checks made against /wire response. + */ + struct TALER_TESTING_Command wire[] = { + /** + * Check if 'x-taler-bank' wire method is offered + * by the exchange. + */ + TALER_TESTING_cmd_wire ("wire-taler-bank-1", + "x-taler-bank", + NULL, + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + + /** + * Test withdrawal plus spending. + */ + struct TALER_TESTING_Command withdraw[] = { + /** + * Move money to the exchange's bank account. + */ + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "create-reserve-1"), + /** + * Make a reserve exist, according to the previous + * transfer. + */ + CMD_EXEC_WIREWATCH ("wirewatch-1"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1", + "create-reserve-1", + "EUR:5", + MHD_HTTP_OK), + /** + * Check the reserve is depleted. + */ + TALER_TESTING_cmd_status ("status-1", + "create-reserve-1", + "EUR:0", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command spend[] = { + /** + * Spend the coin. + */ + TALER_TESTING_cmd_deposit ("deposit-simple", + "withdraw-coin-1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:5", + MHD_HTTP_OK), + /** + * Try to overdraw. + */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2", + "create-reserve-1", + "EUR:5", + MHD_HTTP_CONFLICT), + /** + * Try to double spend using different wire details. + */ + TALER_TESTING_cmd_deposit ("deposit-double-1", + "withdraw-coin-1", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:5", + MHD_HTTP_CONFLICT), + /* Try to double spend using a different transaction id. + * The test needs the contract terms to differ. This + * is currently the case because of the "timestamp" field, + * which is set automatically by #TALER_TESTING_cmd_deposit(). + * This could theoretically fail if at some point a deposit + * command executs in less than 1 ms. */// + TALER_TESTING_cmd_deposit ("deposit-double-1", + "withdraw-coin-1", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:5", + MHD_HTTP_CONFLICT), + /** + * Try to double spend with different proposal. + */ + TALER_TESTING_cmd_deposit ("deposit-double-2", + "withdraw-coin-1", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:5", + MHD_HTTP_CONFLICT), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command refresh[] = { + /* Fill reserve with EUR:5, 1ct is for fees. */ + CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("ck-refresh-create-reserve-1", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "refresh-create-reserve-1"), + /** + * Make previous command effective. + */ + CMD_EXEC_WIREWATCH ("wirewatch-2"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1", + "refresh-create-reserve-1", + "EUR:5", + MHD_HTTP_OK), + /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin + * (in full) (merchant would receive EUR:0.99 due to 1 ct + * deposit fee) */// + TALER_TESTING_cmd_deposit ("refresh-deposit-partial", + "refresh-withdraw-coin-1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + /** + * Melt the rest of the coin's value + * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ + TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1", + "refresh-withdraw-coin-1", + MHD_HTTP_OK, + NULL), + /** + * Complete (successful) melt operation, and + * withdraw the coins + */ + TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1", + "refresh-melt-1", + MHD_HTTP_OK), + /** + * Do it again to check idempotency + */ + TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1-idempotency", + "refresh-melt-1", + MHD_HTTP_OK), + /** + * Test that /refresh/link works + */ + TALER_TESTING_cmd_refresh_link ("refresh-link-1", + "refresh-reveal-1", + MHD_HTTP_OK), + /** + * Try to spend a refreshed EUR:1 coin + */ + TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1a", + "refresh-reveal-1-idempotency", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + /** + * Try to spend a refreshed EUR:0.1 coin + */ + TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b", + "refresh-reveal-1", + 3, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:0.1", + MHD_HTTP_OK), + /* Test running a failing melt operation (same operation + * again must fail) */ + TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing", + "refresh-withdraw-coin-1", + MHD_HTTP_CONFLICT, + NULL), + /* Test running a failing melt operation (on a coin that + was itself revealed and subsequently deposited) */ + TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing-2", + "refresh-reveal-1", + MHD_HTTP_CONFLICT, + NULL), + + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command track[] = { + /* Try resolving a deposit's WTID, as we never triggered + * execution of transactions, the answer should be that + * the exchange knows about the deposit, but has no WTID yet. + */// + TALER_TESTING_cmd_track_transaction ("deposit-wtid-found", + "deposit-simple", + 0, + MHD_HTTP_ACCEPTED, + NULL), + /* Try resolving a deposit's WTID for a failed deposit. + * As the deposit failed, the answer should be that the + * exchange does NOT know about the deposit. + */// + TALER_TESTING_cmd_track_transaction ("deposit-wtid-failing", + "deposit-double-2", + 0, + MHD_HTTP_NOT_FOUND, + NULL), + /* Try resolving an undefined (all zeros) WTID; this + * should fail as obviously the exchange didn't use that + * WTID value for any transaction. + */// + TALER_TESTING_cmd_track_transfer_empty ("wire-deposit-failing", + NULL, + 0, + MHD_HTTP_NOT_FOUND), + /* Run transfers. Note that _actual_ aggregation will NOT + * happen here, as each deposit operation is run with a + * fresh merchant public key, so the aggregator will treat + * them as "different" merchants and do the wire transfers + * individually. */// + CMD_EXEC_AGGREGATOR ("run-aggregator"), + /** + * Check all the transfers took place. + */ + TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c", + ec.exchange_url, + "EUR:4.98", + bc.exchange_payto, + bc.user42_payto), + TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, + bc.user42_payto), + TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c2", + ec.exchange_url, + "EUR:0.98", + bc.exchange_payto, + bc.user42_payto), + TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c", + ec.exchange_url, + "EUR:0.08", + bc.exchange_payto, + bc.user43_payto), + TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"), + TALER_TESTING_cmd_track_transaction ("deposit-wtid-ok", + "deposit-simple", + 0, + MHD_HTTP_OK, + "check_bank_transfer-499c"), + TALER_TESTING_cmd_track_transfer ("wire-deposit-success-bank", + "check_bank_transfer-99c1", + 0, + MHD_HTTP_OK, + "EUR:0.98", + "EUR:0.01"), + TALER_TESTING_cmd_track_transfer ("wire-deposits-success-wtid", + "deposit-wtid-ok", + 0, + MHD_HTTP_OK, + "EUR:4.98", + "EUR:0.01"), + TALER_TESTING_cmd_end () + }; + + + /** + * This block checks whether a wire deadline + * very far in the future does NOT get aggregated now. + */ + struct TALER_TESTING_Command unaggregation[] = { + TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"), + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated", + "EUR:5.01"), + /* "consume" reserve creation transfer. */ + TALER_TESTING_cmd_check_bank_admin_transfer ( + "check-create-reserve-unaggregated", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "create-reserve-unaggregated"), + CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"), + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", + "create-reserve-unaggregated", + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit ("deposit-unaggregated", + "withdraw-coin-unaggregated", + 0, + bc.user43_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_relative_multiply ( + GNUNET_TIME_UNIT_YEARS, + 3000), + "EUR:5", + MHD_HTTP_OK), + CMD_EXEC_AGGREGATOR ("aggregation-attempt"), + + TALER_TESTING_cmd_check_bank_empty + ("far-future-aggregation-b"), + + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command refund[] = { + /** + * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per + * config. + */ + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-r1", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "create-reserve-r1"), + /** + * Run wire-watch to trigger the reserve creation. + */ + CMD_EXEC_WIREWATCH ("wirewatch-3"), + /* Withdraw a 5 EUR coin, at fee of 1 ct */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1", + "create-reserve-r1", + "EUR:5", + MHD_HTTP_OK), + /** + * Spend 5 EUR of the 5 EUR coin (in full) (merchant would + * receive EUR:4.99 due to 1 ct deposit fee) + */ + TALER_TESTING_cmd_deposit ("deposit-refund-1", + "withdraw-coin-r1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_MINUTES, + "EUR:5", + MHD_HTTP_OK), + /** + * Run transfers. Should do nothing as refund deadline blocks it + */ + CMD_EXEC_AGGREGATOR ("run-aggregator-refund"), + /* Check that aggregator didn't do anything, as expected. + * Note, this operation takes two commands: one to "flush" + * the preliminary transfer (used to withdraw) from the + * fakebank and the second to actually check there are not + * other transfers around. */// + TALER_TESTING_cmd_check_bank_empty ("check_bank_transfer-pre-refund"), + TALER_TESTING_cmd_refund ("refund-ok", + MHD_HTTP_OK, + "EUR:5", + "EUR:0.01", + "deposit-refund-1"), + TALER_TESTING_cmd_refund ("refund-ok-double", + MHD_HTTP_OK, + "EUR:5", + "EUR:0.01", + "deposit-refund-1"), + /* Previous /refund(s) had id == 0. */ + TALER_TESTING_cmd_refund_with_id ("refund-conflicting", + MHD_HTTP_CONFLICT, + "EUR:5", + "EUR:0.01", + "deposit-refund-1", + 1), + /** + * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone + * due to refund) (merchant would receive EUR:4.98 due to + * 1 ct deposit fee) */ + TALER_TESTING_cmd_deposit ("deposit-refund-2", + "withdraw-coin-r1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"more ice cream\",\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:4.99", + MHD_HTTP_OK), + /** + * Run transfers. This will do the transfer as refund deadline + * was 0 + */ + CMD_EXEC_AGGREGATOR ("run-aggregator-3"), + /** + * Check that deposit did run. + */ + TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-pre-refund", + ec.exchange_url, + "EUR:4.97", + bc.exchange_payto, + bc.user42_payto), + /** + * Run failing refund, as past deadline & aggregation. + */ + TALER_TESTING_cmd_refund ("refund-fail", + MHD_HTTP_GONE, + "EUR:4.99", + "EUR:0.01", + "deposit-refund-2"), + TALER_TESTING_cmd_check_bank_empty ("check-empty-after-refund"), + /** + * Test refunded coins are never executed, even past + * refund deadline + */ + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-rb", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-rb", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "create-reserve-rb"), + CMD_EXEC_WIREWATCH ("wirewatch-rb"), + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb", + "create-reserve-rb", + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit ("deposit-refund-1b", + "withdraw-coin-rb", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:5", + MHD_HTTP_OK), + /** + * Trigger refund (before aggregator had a chance to execute + * deposit, even though refund deadline was zero). + */ + TALER_TESTING_cmd_refund ("refund-ok-fast", + MHD_HTTP_OK, + "EUR:5", + "EUR:0.01", + "deposit-refund-1b"), + /** + * Run transfers. This will do the transfer as refund deadline + * was 0, except of course because the refund succeeded, the + * transfer should no longer be done. + */CMD_EXEC_AGGREGATOR ("run-aggregator-3b"), + /* check that aggregator didn't do anything, as expected */ + TALER_TESTING_cmd_check_bank_empty ("check-refund-fast-not-run"), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command recoup[] = { + /** + * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per + * config. + */ + CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("recoup-create-reserve-1", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "recoup-create-reserve-1"), + /** + * Run wire-watch to trigger the reserve creation. + */ + CMD_EXEC_WIREWATCH ("wirewatch-4"), + /* Withdraw a 5 EUR coin, at fee of 1 ct */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1", + "recoup-create-reserve-1", + "EUR:5", + MHD_HTTP_OK), + /* Make coin invalid */ + TALER_TESTING_cmd_revoke ("revoke-0-EUR:5", + MHD_HTTP_OK, + "recoup-withdraw-coin-1", + CONFIG_FILE), + /* Refund coin to bank account */ + TALER_TESTING_cmd_recoup ("recoup-1", + MHD_HTTP_OK, + "recoup-withdraw-coin-1", + "EUR:5", + NULL), + /* Check the money is back with the reserve */ + TALER_TESTING_cmd_status ("recoup-reserve-status-1", + "recoup-create-reserve-1", + "EUR:5.0", + MHD_HTTP_OK), + /* Re-withdraw from this reserve */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2", + "recoup-create-reserve-1", + "EUR:1", + MHD_HTTP_OK), + /** + * This withdrawal will test the logic to create a "recoup" + * element to insert into the reserve's history. + */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2-over", + "recoup-create-reserve-1", + "EUR:10", + MHD_HTTP_CONFLICT), + TALER_TESTING_cmd_status ("recoup-reserve-status-2", + "recoup-create-reserve-1", + "EUR:3.99", + MHD_HTTP_OK), + + /* These commands should close the reserve because + * the aggregator is given a config file that ovverrides + * the reserve expiration time (making it now-ish) */ + CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-short-lived-reserve", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "short-lived-reserve"), + TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation", + CONFIG_FILE_EXPIRE_RESERVE_NOW), + + TALER_TESTING_cmd_exec_aggregator ("close-reserves", + CONFIG_FILE_EXPIRE_RESERVE_NOW), + + TALER_TESTING_cmd_status ("short-lived-status", + "short-lived-reserve", + "EUR:0", + MHD_HTTP_OK), + TALER_TESTING_cmd_withdraw_amount ("expired-withdraw", + "short-lived-reserve", + "EUR:1", + MHD_HTTP_CONFLICT), + TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse", + ec.exchange_url, + "EUR:5", + bc.exchange_payto, + bc.user42_payto), + /* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per + * config, then withdraw two coin, partially spend one, and + * then have the rest paid back. Check deposit of other coin + * fails. Do not use EUR:5 here as the EUR:5 coin was + * revoked and we did not bother to create a new one... */// + CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2", + "EUR:2.02"), + TALER_TESTING_cmd_check_bank_admin_transfer ("ck-recoup-create-reserve-2", + "EUR:2.02", + bc.user42_payto, + bc.exchange_payto, + "recoup-create-reserve-2"), + /* Make previous command effective. */ + CMD_EXEC_WIREWATCH ("wirewatch-5"), + /* Withdraw a 1 EUR coin, at fee of 1 ct */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a", + "recoup-create-reserve-2", + "EUR:1", + MHD_HTTP_OK), + /* Withdraw a 1 EUR coin, at fee of 1 ct */ + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b", + "recoup-create-reserve-2", + "EUR:1", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit ("recoup-deposit-partial", + "recoup-withdraw-coin-2a", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:0.5", + MHD_HTTP_OK), + TALER_TESTING_cmd_revoke ("revoke-1-EUR:1", + MHD_HTTP_OK, + "recoup-withdraw-coin-2a", + CONFIG_FILE), + TALER_TESTING_cmd_recoup ("recoup-2", + MHD_HTTP_OK, + "recoup-withdraw-coin-2a", + "EUR:0.5", + NULL), + TALER_TESTING_cmd_recoup ("recoup-2b", + MHD_HTTP_CONFLICT, + "recoup-withdraw-coin-2a", + "EUR:0.5", + NULL), + TALER_TESTING_cmd_deposit ("recoup-deposit-revoked", + "recoup-withdraw-coin-2b", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_NOT_FOUND), + /* Test deposit fails after recoup, with proof in recoup */ + + /* Note that, the exchange will never return the coin's transaction + * history with recoup data, as we get a 404 on the DK! */ + TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup", + "recoup-withdraw-coin-2a", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:0.5", + MHD_HTTP_NOT_FOUND), + /* Test that revoked coins cannot be withdrawn */ + CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-3", + "EUR:1.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ( + "check-recoup-create-reserve-3", + "EUR:1.01", + bc.user42_payto, + bc.exchange_payto, + "recoup-create-reserve-3"), + CMD_EXEC_WIREWATCH ("wirewatch-6"), + TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked", + "recoup-create-reserve-3", + "EUR:1", + MHD_HTTP_NOT_FOUND), + /* check that we are empty before the rejection test */ + TALER_TESTING_cmd_check_bank_empty ("check-empty-again"), + + TALER_TESTING_cmd_end () + }; + +#define RESERVE_OPEN_CLOSE_CHUNK 4 +#define RESERVE_OPEN_CLOSE_ITERATIONS 3 + + struct TALER_TESTING_Command reserve_open_close[(RESERVE_OPEN_CLOSE_ITERATIONS + * RESERVE_OPEN_CLOSE_CHUNK) + + 1]; + for (unsigned int i = 0; + i < RESERVE_OPEN_CLOSE_ITERATIONS; + i++) + { + reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 0] + = CMD_TRANSFER_TO_EXCHANGE ("reserve-open-close-key", + "EUR:20"); + reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1] + = TALER_TESTING_cmd_exec_wirewatch ("reserve-open-close-wirewatch", + CONFIG_FILE_EXPIRE_RESERVE_NOW); + reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2] + = TALER_TESTING_cmd_exec_aggregator ("reserve-open-close-aggregation", + CONFIG_FILE_EXPIRE_RESERVE_NOW); + reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 3] + = TALER_TESTING_cmd_status ("reserve-open-close-status", + "reserve-open-close-key", + "EUR:0", + MHD_HTTP_OK); + } + reserve_open_close[RESERVE_OPEN_CLOSE_ITERATIONS * RESERVE_OPEN_CLOSE_CHUNK] + = TALER_TESTING_cmd_end (); + + { + struct TALER_TESTING_Command commands[] = { + TALER_TESTING_cmd_batch ("wire", + wire), + TALER_TESTING_cmd_batch ("withdraw", + withdraw), + TALER_TESTING_cmd_batch ("spend", + spend), + TALER_TESTING_cmd_batch ("refresh", + refresh), + TALER_TESTING_cmd_batch ("track", + track), + TALER_TESTING_cmd_batch ("unaggregation", + unaggregation), + TALER_TESTING_cmd_batch ("refund", + refund), + TALER_TESTING_cmd_batch ("recoup", + recoup), + TALER_TESTING_cmd_batch ("reserve-open-close", + reserve_open_close), + /* End the suite. */ + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run_with_fakebank (is, + commands, + bc.exchange_auth.wire_gateway_url); + } +} + + +int +main (int argc, + char *const *argv) +{ + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-exchange-api", + "INFO", + NULL); + /* Check fakebank port is available and get config */ + if (GNUNET_OK != + TALER_TESTING_prepare_fakebank (CONFIG_FILE, + "account-2", + &bc)) + return 77; + TALER_TESTING_cleanup_files (CONFIG_FILE); + /* @helpers. Run keyup, create tables, ... Note: it + * fetches the port number from config in order to see + * if it's available. */ + switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, + &ec)) + { + case GNUNET_SYSERR: + GNUNET_break (0); + return 1; + case GNUNET_NO: + return 77; + case GNUNET_OK: + if (GNUNET_OK != + /* Set up event loop and reschedule context, plus + * start/stop the exchange. It calls TALER_TESTING_setup + * which creates the 'is' object. + */ + TALER_TESTING_setup_with_exchange (&run, + NULL, + CONFIG_FILE)) + return 1; + break; + default: + GNUNET_break (0); + return 1; + } + return 0; +} + + +/* end of test_exchange_api.c */ diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf new file mode 100644 index 000000000..291e0a0e0 --- /dev/null +++ b/src/testing/test_exchange_api.conf @@ -0,0 +1,210 @@ +# This file is in the public domain. +# + +[PATHS] +# Persistant data storage for the testcase +TALER_TEST_HOME = test_exchange_api_home/ + + +[taler] +# Currency supported by the exchange (can only be one) +CURRENCY = EUR + +[auditor] +BASE_URL = "http://localhost:8083/" + +# HTTP port the auditor listens to +PORT = 8083 + + +[exchange] +# how long is one signkey valid? +signkey_duration = 4 weeks + +# how long are the signatures with the signkey valid? +legal_duration = 2 years + +# how long do we provide to clients denomination and signing keys +# ahead of time? +lookahead_provide = 4 weeks 1 day + +# 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/" + +# Keep it short so the test runs fast. +LOOKAHEAD_SIGN = 12 h + + +[exchangedb-postgres] +CONFIG = "postgres:///talercheck" + + +[auditordb-postgres] +CONFIG = "postgres:///talercheck" + +# Sections starting with "account-" configure the bank accounts +# of the exchange. The "URL" specifies the account in +# payto://-format, while the WIRE_JSON specifies the +# (possibly offline) signed version to be returned in /wire. +# WIRE_JSON is optional, as not all accounts must be +# advertised in /wire. +[account-1] +# What is the URL of our account? +URL = "payto://x-taler-bank/localhost/42" +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json +# Which wire plugin should we used to access the account? +METHOD = x-taler-bank + +WIRE_GATEWAY_URL = "http://localhost:9081/42/" + +# ENABLE_CREDIT = YES + + +[account-2] +# What is the bank account (with the "Taler Bank" demo system)? +URL = "payto://x-taler-bank/localhost/2" + +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json + +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = Exchange +PASSWORD = x + +METHOD = x-taler-bank + +WIRE_GATEWAY_URL = "http://localhost:9081/2/" + +ENABLE_DEBIT = YES + +ENABLE_CREDIT = YES + +[bank] +HTTP_PORT = 9081 + +# Sections starting with "fee-" configure the wire fee for the +# respective wire method. +[fees-iban] +# Fees for the forseeable future... +# If you see this after 2017, update to match the next 10 years... +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 + +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 + +[fees-x-taler-bank] +# Fees for the forseeable future... +# If you see this after 2017, update to match the next 10 years... +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 + +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 + +# 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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_exchange_api_expire_reserve_now.conf new file mode 100644 index 000000000..05bca956b --- /dev/null +++ b/src/testing/test_exchange_api_expire_reserve_now.conf @@ -0,0 +1,4 @@ +@INLINE@ test_exchange_api.conf + +[exchangedb] +IDLE_RESERVE_EXPIRATION_TIME = 0 s diff --git a/src/testing/test_exchange_api_home/.config/taler/account-1.json b/src/testing/test_exchange_api_home/.config/taler/account-1.json new file mode 100644 index 000000000..48093f2aa --- /dev/null +++ b/src/testing/test_exchange_api_home/.config/taler/account-1.json @@ -0,0 +1,5 @@ +{ + "url": "payto://sepa/CH9300762011623852957", + "salt": "N83T9J9202WCC8TQFDMJDWEGZNBEKA33C1ZM241VNYH88RZNTHPW509Y1M2YF7Y098R8VRESWQ05H03BK1SPAZCWE54KARDCKT5N8AG", + "master_sig": "D4V5GJ998YK7D6N0N56AD0J6MZNFEW6MRZT2CFPVQ5ME3NMQ59AA2007CXYESSFGRN70CNCFM06858QSSENCWTZM8VHEJ93YQ20ZJ1R" +} \ No newline at end of file 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 new file mode 100644 index 000000000..f39677eff --- /dev/null +++ b/src/testing/test_exchange_api_home/.config/taler/account-2.json @@ -0,0 +1,4 @@ +{ + "url": "payto://x-taler-bank/localhost/2", + "master_sig": "HEWC1XDS0QZ53YQR451VRKD4N968NXWGZXS30HJ59MJ0PESACK1ZYPYCAT15P08WD58C7D7F6EVN26D59JKA75XEBDQCM8VYFETK82R" +} \ No newline at end of file diff --git a/src/testing/test_exchange_api_home/.config/taler/sepa.json b/src/testing/test_exchange_api_home/.config/taler/sepa.json new file mode 100644 index 000000000..b435ce86b --- /dev/null +++ b/src/testing/test_exchange_api_home/.config/taler/sepa.json @@ -0,0 +1,9 @@ +{ + "name": "Max Musterman", + "bic": "COBADEFF370", + "type": "sepa", + "sig": "4EVRC2MCJPXQC8MC00831DNWEXMZAP4JQDDE1A7R6KR3MANG24RC1VQ55AX5A2E35S58VW1VSTENFTPHG5MWG9BSN8B8WXSV21KKW20", + "address": "Musterstadt", + "salt": "3KTM1ZRMWGEQPQ254S4R5R4Q8XM0ZYWTCTE01TZ76MVBSQ6RX7A5DR08WXVH1DCHR1R7ACRB7X0EVC2XDW1CBZM9WFSD9TRMZ90BR98", + "iban": "DE89370400440532013000" +} \ No newline at end of file diff --git a/src/testing/test_exchange_api_home/.config/taler/test.json b/src/testing/test_exchange_api_home/.config/taler/test.json new file mode 100644 index 000000000..eca394241 --- /dev/null +++ b/src/testing/test_exchange_api_home/.config/taler/test.json @@ -0,0 +1,8 @@ +{ + "salt": "AZPRFVJ58NM6M7J5CZQPJAH3EW5DYM52AEZ9Y1C1ER3W94QV8D8TQKF6CK8MYQRA9QMSKDQTGZ306ZS9GQ0M6R01CJ20KPP49WFDZK8", + "name": "The exchange", + "account_number": 3, + "bank_url": "http://localhost:8082/", + "type": "test", + "sig": "RPQXP9S4P8PQP7HEZQNRSZCT0ATNEP8GW0P5TPM34V5RX86FCD670V44R9NETSYDDKB8SZV7TKY9PAJYTY51D3VDWY9XXQ5BPFRXR28" +} diff --git a/src/testing/test_exchange_api_home/.config/taler/x-taler-bank.json b/src/testing/test_exchange_api_home/.config/taler/x-taler-bank.json new file mode 100644 index 000000000..a6dc167e4 --- /dev/null +++ b/src/testing/test_exchange_api_home/.config/taler/x-taler-bank.json @@ -0,0 +1,5 @@ +{ + "url": "payto://x-taler-bank/http://localhost:8082/2", + "master_sig": "KQ0BWSCNVR7HGGSAMCYK8ZM30RBS1MHMXT3QBN01PZWC9TV72FEE5RJ7T84C8134EPV6WEBXXY2MTFNE8ZXST6JEJQKR8HX6FQPVY10", + "master_pub": "98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG" +} 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 new file mode 100644 index 000000000..394926938 --- /dev/null +++ b/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv @@ -0,0 +1 @@ +pÚ^ó-Ú33ˆ€XXÁ!ˆ\0qúýµmUþ_‰ˆ \ No newline at end of file diff --git a/src/testing/test_exchange_api_interpreter_on-off.c b/src/testing/test_exchange_api_interpreter_on-off.c new file mode 100644 index 000000000..e0ef75090 --- /dev/null +++ b/src/testing/test_exchange_api_interpreter_on-off.c @@ -0,0 +1,128 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file testing/test_exchange_api_keys_cherry_picking_new.c + * @brief testcase to test exchange's /keys cherry picking ability + * @author Marcello Stanisci + * @author Christian Grothoff + */ + +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + +/** + * XXX: + * + * This test helps in finding a way to use/modify the "normal" + * cert_cb to handle reconnections from serialized states as well. + * + * 1st step: simply turn the interpreter off and on again. + * 2nd step: turn the interpreter off and give a serial state + * to reconnect. + */ + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf" + +/** + * Exchange base URL; mainly purpose is to make the compiler happy. + */ +static char *exchange_url; + +/** + * Auditor base URL; mainly purpose is to make the compiler happy. + */ +static char *auditor_url; + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + + struct TALER_TESTING_Command commands[] = { + + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run (is, + commands); +} + + +int +main (int argc, + char *const *argv) +{ + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-exchange-api-cherry-picking-new", + "DEBUG", NULL); + TALER_TESTING_cleanup_files (CONFIG_FILE); + /* @helpers. Run keyup, create tables, ... Note: it + * fetches the port number from config in order to see + * if it's available. */ + switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, + &auditor_url, + &exchange_url)) + { + case GNUNET_SYSERR: + GNUNET_break (0); + return 1; + case GNUNET_NO: + return 77; + case GNUNET_OK: + if (GNUNET_OK != + /* Set up event loop and reschedule context, plus + * start/stop the exchange. It calls TALER_TESTING_setup + * which creates the 'is' object. + */ + TALER_TESTING_setup_with_exchange (&run, + NULL, + CONFIG_FILE)) + return 1; + break; + default: + GNUNET_break (0); + return 1; + } + return 0; +} + + +/* end of test_exchange_api_keys_cherry_picking_new.c */ diff --git a/src/testing/test_exchange_api_keys_cherry_picking.c b/src/testing/test_exchange_api_keys_cherry_picking.c new file mode 100644 index 000000000..a104b805a --- /dev/null +++ b/src/testing/test_exchange_api_keys_cherry_picking.c @@ -0,0 +1,263 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/test_exchange_api_keys_cherry_picking.c + * @brief testcase to test exchange's /keys cherry picking ability + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf" + +/** + * Used to increase the number of denomination keys. + */ +#define CONFIG_FILE_EXTENDED \ + "test_exchange_api_keys_cherry_picking_extended.conf" + +/** + * Used to increase the number of denomination keys. + */ +#define CONFIG_FILE_EXTENDED_2 \ + "test_exchange_api_keys_cherry_picking_extended_2.conf" + + +#define NDKS_RIGHT_BEFORE_SERIALIZATION 46 + +/** + * Add seconds. + * + * @param base absolute time to add seconds to. + * @param relative number of seconds to add. + * @return a new absolute time, modified according to @e relative. + */ +#define ADDSECS(base, secs) \ + GNUNET_TIME_absolute_add \ + (base, \ + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \ + secs)) + +/** + * Subtract seconds. + * + * @param base absolute time to subtract seconds to. + * @param secs relative number of _seconds_ to subtract. + * @return a new absolute time, modified according to @e relative. + */ +#define SUBSECS(base, secs) \ + GNUNET_TIME_absolute_subtract \ + (base, \ + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \ + secs)) +#define JAN1971 "1971-01-01" +#define JAN2030 "2030-01-01" + +/** + * Exchange configuration data. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + + +/** + * Wrapper around the time parser. + * + * @param str human-readable time string. + * @return the parsed time from @a str. + */ +static struct GNUNET_TIME_Absolute +TTH_parse_time (const char *str) +{ + struct GNUNET_TIME_Absolute ret; + + GNUNET_assert + (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_absolute (str, + &ret)); + return ret; +} + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + * @param is[in,out] interpreter state + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_TESTING_Command keys_serialization[] = { + TALER_TESTING_cmd_serialize_keys + ("serialize-keys"), + TALER_TESTING_cmd_connect_with_state + ("reconnect-with-state", + "serialize-keys"), + /** + * Make sure we have the same keys situation as + * it was before the serialization. + */ + TALER_TESTING_cmd_check_keys_with_now + ("check-keys-after-deserialization", + 4, + NDKS_RIGHT_BEFORE_SERIALIZATION, + /** + * Pretend 5 seconds passed. + */ + ADDSECS (TTH_parse_time (JAN2030), + 5)), + /** + * Use one of the deserialized keys. + */ + TALER_TESTING_cmd_wire + ("verify-/wire-with-serialized-keys", + "x-taler-bank", + NULL, + MHD_HTTP_OK), + TALER_TESTING_cmd_end (), + }; + + struct TALER_TESTING_Command ordinary_cherry_pick[] = { + /** + * 1 DK with 80s withdraw duration, lookahead_sign is 60s + * => expect 1 DK. + */ + TALER_TESTING_cmd_check_keys ("check-keys-1", + 1, /* generation */ + 1), + /** + * The far-future now will cause "keyup" to start a fresh + * key set. The new KS will have only one key, because the + * current lookahead_sign == 60 seconds and the key's withdraw + * duration is 80 seconds. + */TALER_TESTING_cmd_exec_keyup_with_now + ("keyup-1", + CONFIG_FILE, + TTH_parse_time (JAN2030)), + /** + * Should return 1 new key, + the original one. NOTE: the + * original DK will never be 'cancelled' as for the current + * libtalerexchange logic, so it must always be counted. + */TALER_TESTING_cmd_check_keys_with_now + ("check-keys-2", + 2, /* generation */ + 2, + TTH_parse_time (JAN2030)), + TALER_TESTING_cmd_exec_keyup_with_now + ("keyup-3", + CONFIG_FILE_EXTENDED_2, + /* Taking care of not using a 'now' that equals the + * last DK timestamp, otherwise it would get silently + * overridden. */ + ADDSECS (TTH_parse_time (JAN2030), + 10)), + + /** + * Expected number of DK: + * + * 3500 (the lookahead_sign time frame, in seconds) + * - 69 (how many seconds are covered by the latest DK) + * ---- + * 3431 + * / 79 (how many seconds each DK will cover) + * ---- + * 44 (rounded up) + * + 2 (old DKs already stored locally: 1 from the + * very initial setup, and 1 from the 'keyup-1' CMD) + * ---- + * 46 + */TALER_TESTING_cmd_check_keys_with_now + ("check-keys-3", + 3, + NDKS_RIGHT_BEFORE_SERIALIZATION, + TTH_parse_time (JAN2030)), + + TALER_TESTING_cmd_end () + }; + struct TALER_TESTING_Command commands[] = { + + TALER_TESTING_cmd_batch ("ordinary-cherry-pick", + ordinary_cherry_pick), + TALER_TESTING_cmd_batch ("keys-serialization", + keys_serialization), + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run (is, + commands); +} + + +int +main (int argc, + char *const *argv) +{ + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-exchange-api-cherry-picking", + "DEBUG", + NULL); + TALER_TESTING_cleanup_files (CONFIG_FILE); + /* @helpers. Run keyup, create tables, ... Note: it + * fetches the port number from config in order to see + * if it's available. */ + switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, + &ec)) + { + case GNUNET_SYSERR: + GNUNET_break (0); + return 1; + case GNUNET_NO: + return 77; + case GNUNET_OK: + if (GNUNET_OK != + /* Set up event loop and reschedule context, plus + * start/stop the exchange. It calls TALER_TESTING_setup + * which creates the 'is' object. + */ + TALER_TESTING_setup_with_exchange (&run, + NULL, + CONFIG_FILE)) + return 1; + break; + default: + GNUNET_break (0); + return 1; + } + return 0; +} + + +/* end of test_exchange_api_keys_cherry_picking.c */ diff --git a/src/testing/test_exchange_api_keys_cherry_picking.conf b/src/testing/test_exchange_api_keys_cherry_picking.conf new file mode 100644 index 000000000..c5a69df3b --- /dev/null +++ b/src/testing/test_exchange_api_keys_cherry_picking.conf @@ -0,0 +1,184 @@ +# This file is in the public domain. +# +[PATHS] +# Persistent data storage for the testcase +TALER_TEST_HOME = test_exchange_api_keys_cherry_picking_home/ + +# Persistant 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 + +[auditor] +BASE_URL = "http://localhost:8083/" + +# HTTP port the auditor listens to +PORT = 8083 + +[exchange] + +KEYDIR = ${TALER_TEST_HOME}/.local/share/taler/exchange/live-keys/ + +# how long is one signkey valid? +signkey_duration = 5 seconds + +# how long are the signatures with the signkey valid? +legal_duration = 2 years + +# This vaule causes keys to be *RETURNED* in a /keys response. +# It's a relative time that materializes always in now+itsvalue. +# We keep it very high, so as to not introduce divergencies between +# keys that have been created and keys that are returned along /keys. +lookahead_provide = 10000 seconds + +# This value causes keys to be *CREATED*. The rule is that +# at any given time there are always N keys whose all the withdraw +# durations sum up to a time window as big as lookahead_sign. +lookahead_sign = 60 s + +# 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" + + +[account-1] +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/iban.json + +# What is the URL of our bank account? Must match WIRE_RESPONSE above! +URL = payto://x-taler-bank/localhost/42 + +METHOD = "x-taler-bank" + +WIRE_GATEWAY_URL = "http://localhost:9082/42/" + + +[account-2] +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/x-taler-bank.json + +# What is the URL of our bank account? Must match WIRE_RESPONSE above! +URL = payto://x-taler-bank/localhost/2 + +WIRE_GATEWAY_URL = "http://localhost:9082/2/" + +METHOD = "x-taler-bank" + +# Authentication information for basic authentication +TALER_BANK_AUTH_METHOD = "basic" +USERNAME = user +PASSWORD = pass + +ENABLE_DEBIT = YES + +ENABLE_CREDIT = YES + +[bank] +HTTP_PORT=8082 + +[fees-x-taler-bank] +# Fees for the forseeable future... +# If you see this after 2017, update to match the next 10 years... +WIRE-FEE-2017 = EUR:0.01 +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 +WIRE-FEE-2028 = EUR:0.01 +WIRE-FEE-2029 = EUR:0.01 +WIRE-FEE-2030 = EUR:0.01 +WIRE-FEE-2031 = EUR:0.01 +WIRE-FEE-2032 = EUR:0.01 +WIRE-FEE-2033 = EUR:0.01 +WIRE-FEE-2034 = EUR:0.01 +WIRE-FEE-2035 = EUR:0.01 + +CLOSING-FEE-2017 = EUR:0.01 +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 +CLOSING-FEE-2028 = EUR:0.01 +CLOSING-FEE-2029 = EUR:0.01 +CLOSING-FEE-2030 = EUR:0.01 +CLOSING-FEE-2031 = EUR:0.01 +CLOSING-FEE-2032 = EUR:0.01 +CLOSING-FEE-2033 = EUR:0.01 +CLOSING-FEE-2034 = EUR:0.01 +CLOSING-FEE-2035 = EUR:0.01 + + +[fees-iban] +# Fees for the forseeable future... +# If you see this after 2017, update to match the next 10 years... +WIRE-FEE-2017 = EUR:0.01 +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 + +CLOSING-FEE-2017 = EUR:0.01 +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 + +[coin_eur_1] +value = EUR:1 +duration_overlap = 1 s +duration_withdraw = 80 s +duration_spend = 80 s +duration_legal = 60 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_extended.conf b/src/testing/test_exchange_api_keys_cherry_picking_extended.conf new file mode 100644 index 000000000..c49f1edd4 --- /dev/null +++ b/src/testing/test_exchange_api_keys_cherry_picking_extended.conf @@ -0,0 +1,5 @@ +@INLINE@ test_exchange_api_keys_cherry_picking.conf + +[exchange] +# Lengthen over original value (60 s) +LOOKAHEAD_SIGN = 90 s diff --git a/src/testing/test_exchange_api_keys_cherry_picking_extended_2.conf b/src/testing/test_exchange_api_keys_cherry_picking_extended_2.conf new file mode 100644 index 000000000..8097a6cda --- /dev/null +++ b/src/testing/test_exchange_api_keys_cherry_picking_extended_2.conf @@ -0,0 +1,5 @@ +@INLINE@ test_exchange_api_keys_cherry_picking_extended.conf + +[exchange] +# Lengthen over firstly extended value (100 s) +LOOKAHEAD_SIGN = 3500 s 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 new file mode 100644 index 000000000..f39677eff --- /dev/null +++ b/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json @@ -0,0 +1,4 @@ +{ + "url": "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-keys/master.priv b/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv new file mode 100644 index 000000000..394926938 --- /dev/null +++ b/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv @@ -0,0 +1 @@ +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 new file mode 100644 index 000000000..f63d5da7e --- /dev/null +++ b/src/testing/test_exchange_api_overlapping_keys_bug.c @@ -0,0 +1,130 @@ +/* + This file is part of TALER + Copyright (C) 2018, 2019 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file testing/test_exchange_api_overlapping_keys_bug.c + * @brief testcase to test exchange's /keys cherry picking ability and + * other /keys related operations + * @author Marcello Stanisci + * @author Christian Grothoff + */ + +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf" + +/** + * Used to increase the number of denomination keys. + */ +#define CONFIG_FILE_EXTENDED \ + "test_exchange_api_keys_cherry_picking_extended.conf" + +/** + * Used to increase the number of denomination keys. + */ +#define CONFIG_FILE_EXTENDED_2 \ + "test_exchange_api_keys_cherry_picking_extended_2.conf" + +/** + * Exchange configuration data. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_TESTING_Command commands[] = { + TALER_TESTING_cmd_check_keys ("first-download", + 1, + 1), + /* Causes GET /keys?last_denom_issue=0 */ + TALER_TESTING_cmd_check_keys_with_last_denom ("second-download", + 3, + 1, + GNUNET_TIME_UNIT_ZERO_ABS), + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run (is, + commands); +} + + +int +main (int argc, + char *const *argv) +{ + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-exchange-api-overlapping-keys-bug", + "DEBUG", NULL); + TALER_TESTING_cleanup_files (CONFIG_FILE); + /* @helpers. Run keyup, create tables, ... Note: it + * fetches the port number from config in order to see + * if it's available. */ + switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, + &ec)) + { + case GNUNET_SYSERR: + GNUNET_break (0); + return 1; + case GNUNET_NO: + return 77; + case GNUNET_OK: + if (GNUNET_OK != + /* Set up event loop and reschedule context, plus + * start/stop the exchange. It calls TALER_TESTING_setup + * which creates the 'is' object. + */ + TALER_TESTING_setup_with_exchange (&run, + NULL, + CONFIG_FILE)) + return 1; + break; + default: + GNUNET_break (0); + return 1; + } + return 0; +} + + +/* end of test_exchange_api_overlapping_keys_bug.c */ diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c new file mode 100644 index 000000000..110dec166 --- /dev/null +++ b/src/testing/test_exchange_api_revocation.c @@ -0,0 +1,231 @@ +/* + This file is part of TALER + Copyright (C) 2014--2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/test_exchange_api_revocation.c + * @brief testcase to test key revocation handling via the exchange's HTTP API interface + * @author Sree Harsha Totakura + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_exchange_api.conf" + +/** + * Exchange configuration data. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_TESTING_Command revocation[] = { + /** + * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per + * config. + */ + TALER_TESTING_cmd_admin_add_incoming ("create-reserve-1", + "EUR:5.01", + &bc.exchange_auth, + bc.user42_payto), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "create-reserve-1"), + /** + * Run wire-watch to trigger the reserve creation. + */ + TALER_TESTING_cmd_exec_wirewatch ("wirewatch-4", + CONFIG_FILE), + /* Withdraw a 5 EUR coin, at fee of 1 ct */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1", + "create-reserve-1", + "EUR:5", + MHD_HTTP_OK), + /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full) + * (merchant would receive EUR:0.99 due to 1 ct deposit fee) */// + TALER_TESTING_cmd_deposit ("deposit-partial", + "withdraw-revocation-coin-1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + /** + * Melt SOME of the rest of the coin's value + * (EUR:3.17 = 3x EUR:1.03 + 7x EUR:0.13) */ + TALER_TESTING_cmd_refresh_melt ("refresh-melt-1", + "withdraw-revocation-coin-1", + MHD_HTTP_OK, + NULL), + /** + * Complete (successful) melt operation, and withdraw the coins + */ + TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1", + "refresh-melt-1", + MHD_HTTP_OK), + /* Make refreshed coin invalid */ + TALER_TESTING_cmd_revoke ("revoke-2-EUR:5", + MHD_HTTP_OK, + "refresh-melt-1", + CONFIG_FILE), + /* Refund coin to original coin */ + TALER_TESTING_cmd_recoup ("recoup-1a", + MHD_HTTP_OK, + "refresh-reveal-1#0", + "EUR:1", + "refresh-melt-1"), + TALER_TESTING_cmd_recoup ("recoup-1b", + MHD_HTTP_OK, + "refresh-reveal-1#1", + "EUR:1", + "refresh-melt-1"), + TALER_TESTING_cmd_recoup ("recoup-1c", + MHD_HTTP_OK, + "refresh-reveal-1#2", + "EUR:1", + "refresh-melt-1"), + /* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */ + /* Melt original coin AGAIN, but only create one 0.1 EUR coin; + This costs EUR:0.03 in refresh and EUR:01 in withdraw fees, + leaving EUR:3.69. */ + TALER_TESTING_cmd_refresh_melt ("refresh-melt-2", + "withdraw-revocation-coin-1", + MHD_HTTP_OK, + "EUR:0.1", + NULL), + /** + * Complete (successful) melt operation, and withdraw the coins + */ + TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-2", + "refresh-melt-2", + MHD_HTTP_OK), + /* Revokes refreshed EUR:0.1 coin */ + TALER_TESTING_cmd_revoke ("revoke-3-EUR:0.1", + MHD_HTTP_OK, + "refresh-reveal-2", + CONFIG_FILE), + /* Revoke also original coin denomination */ + TALER_TESTING_cmd_revoke ("revoke-4-EUR:5", + MHD_HTTP_OK, + "withdraw-revocation-coin-1", + CONFIG_FILE), + /* Refund coin EUR:0.1 to original coin, creating zombie! */ + TALER_TESTING_cmd_recoup ("recoup-2", + MHD_HTTP_OK, + "refresh-reveal-2", + "EUR:0.1", + "refresh-melt-2"), + /* Due to recoup, original coin is now at EUR:3.79 */ + /* Refund original (now zombie) coin to reserve */ + TALER_TESTING_cmd_recoup ("recoup-3", + MHD_HTTP_OK, + "withdraw-revocation-coin-1", + "EUR:3.79", + NULL), + /* Check the money is back with the reserve */ + TALER_TESTING_cmd_status ("recoup-reserve-status-1", + "create-reserve-1", + "EUR:3.79", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run_with_fakebank (is, + revocation, + bc.exchange_auth.wire_gateway_url); +} + + +int +main (int argc, + char *const *argv) +{ + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-exchange-api-revocation", + "INFO", + NULL); + /* Check fakebank port is available and get config */ + if (GNUNET_OK != + TALER_TESTING_prepare_fakebank (CONFIG_FILE, + "account-2", + &bc)) + return 77; + TALER_TESTING_cleanup_files (CONFIG_FILE); + /* @helpers. Run keyup, create tables, ... Note: it + * fetches the port number from config in order to see + * if it's available. */ + switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, + &ec)) + { + case GNUNET_SYSERR: + GNUNET_break (0); + return 1; + case GNUNET_NO: + return 77; + case GNUNET_OK: + if (GNUNET_OK != + /* Set up event loop and reschedule context, plus + * start/stop the exchange. It calls TALER_TESTING_setup + * which creates the 'is' object. + */ + TALER_TESTING_setup_with_exchange (&run, + NULL, + CONFIG_FILE)) + return 1; + break; + default: + GNUNET_break (0); + return 1; + } + return 0; +} + + +/* end of test_exchange_api_revocation.c */ diff --git a/src/testing/test_exchange_api_twisted.c b/src/testing/test_exchange_api_twisted.c new file mode 100644 index 000000000..106cecdc5 --- /dev/null +++ b/src/testing/test_exchange_api_twisted.c @@ -0,0 +1,332 @@ +/* + This file is part of TALER + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/test_exchange_api_twisted.c + * @brief testcase to test exchange's HTTP API interface + * @author Marcello Stanisci + * @author Sree Harsha Totakura + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" +#include +#include + +/** + * Configuration file we use. One (big) configuration is used + * for the various components for this test. + */ +#define CONFIG_FILE "test_exchange_api_twisted.conf" + +/** + * (real) Twister URL. Used at startup time to check if it runs. + */ +static char *twister_url; + +/** + * Exchange configuration data. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + +/** + * Twister process. + */ +static struct GNUNET_OS_Process *twisterd; + + +/** + * Execute the taler-exchange-wirewatch command with + * our configuration file. + * + * @param label label to use for the command. + */ +static struct TALER_TESTING_Command +CMD_EXEC_WIREWATCH (char *label) +{ + return TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE); +} + + +/** + * Run wire transfer of funds from some user's account to the + * exchange. + * + * @param label label to use for the command. + * @param amount amount to transfer, i.e. "EUR:1" + * @param url exchange_url + */ +static struct TALER_TESTING_Command +CMD_TRANSFER_TO_EXCHANGE (char *label, char *amount) +{ + return TALER_TESTING_cmd_admin_add_incoming (label, + amount, + &bc.exchange_auth, + bc.user42_payto); +} + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + /** + * This batch aims to trigger the 409 Conflict + * response from a refresh-reveal operation. + */ + struct TALER_TESTING_Command refresh_409_conflict[] = { + CMD_TRANSFER_TO_EXCHANGE + ("refresh-create-reserve", + "EUR:5.01"), + /** + * Make previous command effective. + */ + CMD_EXEC_WIREWATCH + ("wirewatch"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount + ("refresh-withdraw-coin", + "refresh-create-reserve", + "EUR:5", + MHD_HTTP_OK), + + TALER_TESTING_cmd_deposit + ("refresh-deposit-partial", + "refresh-withdraw-coin", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\ + \"value\":\"EUR:1\"}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + MHD_HTTP_OK), + + /** + * Melt the rest of the coin's value + * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */ + TALER_TESTING_cmd_refresh_melt + ("refresh-melt", + "refresh-withdraw-coin", + MHD_HTTP_OK, + NULL), + /* Trigger 409 Conflict. */ + TALER_TESTING_cmd_flip_upload + ("flip-upload", + CONFIG_FILE, + "transfer_privs.0"), + TALER_TESTING_cmd_refresh_reveal + ("refresh-(flipped-)reveal", + "refresh-melt", + MHD_HTTP_CONFLICT), + + TALER_TESTING_cmd_end () + + }; + + + /** + * NOTE: not all CMDs actually need the twister, + * so it may be better to move those into the "main" + * lib test suite. + */struct TALER_TESTING_Command refund[] = { + + CMD_TRANSFER_TO_EXCHANGE + ("create-reserve-r1", + "EUR:5.01"), + CMD_EXEC_WIREWATCH + ("wirewatch-r1"), + TALER_TESTING_cmd_withdraw_amount + ("withdraw-coin-r1", + "create-reserve-r1", + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit + ("deposit-refund-1", + "withdraw-coin-r1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\"," + "\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_MINUTES, + "EUR:5", + MHD_HTTP_OK), + TALER_TESTING_cmd_refund + ("refund-currency-missmatch", + MHD_HTTP_PRECONDITION_FAILED, + "USD:5", + "USD:0.01", + "deposit-refund-1"), + TALER_TESTING_cmd_refund + ("refund-fee-above-amount", + MHD_HTTP_BAD_REQUEST, + "EUR:5", + "EUR:10", + "deposit-refund-1"), + TALER_TESTING_cmd_flip_upload + ("flip-upload", + CONFIG_FILE, + "merchant_sig"), + TALER_TESTING_cmd_refund + ("refund-bad-sig", + MHD_HTTP_FORBIDDEN, + "EUR:5", + "EUR:0.01", + "deposit-refund-1"), + + /* This next deposit CMD is only used to provide a + * good merchant signature to the next (failing) refund + * operations. */ + + TALER_TESTING_cmd_deposit + ("deposit-refund-to-fail", + "withdraw-coin-r1", + 0, /* coin index. */ + bc.user42_payto, + /* This parameter will make any comparison about + h_contract_terms fail, when /refund will be handled. + So in other words, this is h_contract missmatch. */ + "{\"items\":[{\"name\":\"ice skate\"," + "\"value\":\"EUR:5\"}]}", + GNUNET_TIME_UNIT_MINUTES, + "EUR:5", + MHD_HTTP_CONFLICT), + TALER_TESTING_cmd_refund + ("refund-deposit-not-found", + MHD_HTTP_NOT_FOUND, + "EUR:5", + "EUR:0.01", + "deposit-refund-to-fail"), + TALER_TESTING_cmd_refund + ("refund-insufficient-funds", + MHD_HTTP_PRECONDITION_FAILED, + "EUR:50", + "EUR:0.01", + "deposit-refund-1"), + TALER_TESTING_cmd_refund + ("refund-fee-too-low", + MHD_HTTP_BAD_REQUEST, + "EUR:5", + "EUR:0.000001", + "deposit-refund-1"), + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command commands[] = { + TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict", + refresh_409_conflict), + TALER_TESTING_cmd_batch ("refund", + refund), + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run_with_fakebank (is, + commands, + bc.exchange_auth.wire_gateway_url); +} + + +/** + * Kill, wait, and destroy convenience function. + * + * @param process process to purge. + */ +static void +purge_process (struct GNUNET_OS_Process *process) +{ + GNUNET_OS_process_kill (process, SIGINT); + GNUNET_OS_process_wait (process); + GNUNET_OS_process_destroy (process); +} + + +int +main (int argc, + char *const *argv) +{ + unsigned int ret; + /* These environment variables get in the way... */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-exchange-api-twisted", + "DEBUG", NULL); + + if (GNUNET_OK != + TALER_TESTING_prepare_fakebank (CONFIG_FILE, + "account-2", + &bc)) + return 77; + + if (NULL == (twister_url = TALER_TESTING_prepare_twister + (CONFIG_FILE))) + return 77; + + TALER_TESTING_cleanup_files (CONFIG_FILE); + + switch (TALER_TESTING_prepare_exchange (CONFIG_FILE, + &ec)) + { + case GNUNET_SYSERR: + GNUNET_break (0); + return 1; + case GNUNET_NO: + return 77; + + case GNUNET_OK: + + if (NULL == (twisterd = TALER_TESTING_run_twister (CONFIG_FILE))) + return 77; + + ret = TALER_TESTING_setup_with_exchange (&run, + NULL, + CONFIG_FILE); + purge_process (twisterd); + GNUNET_free (twister_url); + + if (GNUNET_OK != ret) + return 1; + break; + default: + GNUNET_break (0); + return 1; + } + return 0; +} + + +/* end of test_exchange_api_twisted.c */ diff --git a/src/testing/test_exchange_api_twisted.conf b/src/testing/test_exchange_api_twisted.conf new file mode 100644 index 000000000..28b254e67 --- /dev/null +++ b/src/testing/test_exchange_api_twisted.conf @@ -0,0 +1,196 @@ +# This file is in the public domain. +# + +[PATHS] +# Persistant data storage for the testcase +TALER_TEST_HOME = test_exchange_api_home/ + + +[taler] +# Currency supported by the exchange (can only be one) +CURRENCY = EUR + + +[exchange] + +# how long is one signkey valid? +SIGNKEY_DURATION = 4 weeks + +# how long are the signatures with the signkey valid? +LEGAL_DURATION = 2 years + +# how long do we provide to clients denomination and signing keys +# ahead of time? +LOOKAHEAD_PROVIDE = 4 weeks 1 day + +# Keep it short so the test runs fast. +LOOKAHEAD_SIGN = 12 h + +# 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" + +[account-1] +# What is the URL of our account? +URL = "payto://x-taler-bank/localhost/42" +# This is the response we give out for the /wire request. It provides +# wallets with the bank information for transfers to the exchange. +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json +# Which wire plugin should we used to access the account? +METHOD = x-taler-bank +WIRE_GATEWAY_URL = "http://localhost:9081/42/" +WIRE_GATEWAY_AUTH_METHOD = NONE + + +[account-2] +URL = payto://x-taler-bank/localhost/2 +WIRE_GATEWAY_URL = "http://localhost:8082/2/" +WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json +WIRE_GATEWAY_AUTH_METHOD = BASIC +USERNAME = user +PASSWORD = pass +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES +METHOD = x-taler-bank + + +[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 + + +[fees-x-taler-bank] +# Fees for the forseeable future... +# If you see this after 2017, update to match the next 10 years... +WIRE-FEE-2018 = EUR:0.01 +WIRE-FEE-2019 = EUR:0.01 +WIRE-FEE-2020 = EUR:0.01 +WIRE-FEE-2021 = EUR:0.01 +WIRE-FEE-2022 = EUR:0.01 +WIRE-FEE-2023 = EUR:0.01 +WIRE-FEE-2024 = EUR:0.01 +WIRE-FEE-2025 = EUR:0.01 +WIRE-FEE-2026 = EUR:0.01 +WIRE-FEE-2027 = EUR:0.01 + +CLOSING-FEE-2018 = EUR:0.01 +CLOSING-FEE-2019 = EUR:0.01 +CLOSING-FEE-2020 = EUR:0.01 +CLOSING-FEE-2021 = EUR:0.01 +CLOSING-FEE-2022 = EUR:0.01 +CLOSING-FEE-2023 = EUR:0.01 +CLOSING-FEE-2024 = EUR:0.01 +CLOSING-FEE-2025 = EUR:0.01 +CLOSING-FEE-2026 = EUR:0.01 +CLOSING-FEE-2027 = EUR:0.01 + +[coin_eur_ct_1] +value = EUR:0.01 +duration_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_overlap = 5 minutes +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_taler_exchange_aggregator.c b/src/testing/test_taler_exchange_aggregator.c new file mode 100644 index 000000000..84695ca0e --- /dev/null +++ b/src/testing/test_taler_exchange_aggregator.c @@ -0,0 +1,524 @@ +/* + This file is part of TALER + (C) 2016-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see +*/ + +/** + * @file testing/test_taler_exchange_aggregator.c + * @brief Tests for taler-exchange-aggregator logic + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_util.h" +#include +#include "taler_json_lib.h" +#include "taler_exchangedb_lib.h" +#include +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + + +/** + * Helper structure to keep exchange configuration values. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + +/** + * Contains plugin and session. + */ +static struct TALER_TESTING_DatabaseConnection dbc; + +/** + * Return value from main(). + */ +static int result; + +/** + * Name of the configuration file to use. + */ +static char *config_filename; + +#define USER42_ACCOUNT "42" + +/** + * @return GNUNET_NO if database could not be prepared, + * otherwise GNUNET_OK + */ +static int +prepare_database (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + dbc.plugin = TALER_EXCHANGEDB_plugin_load (cfg); + if (NULL == dbc.plugin) + { + GNUNET_break (0); + result = 77; + return GNUNET_NO; + } + if (GNUNET_OK != + dbc.plugin->create_tables (dbc.plugin->cls)) + { + GNUNET_break (0); + TALER_EXCHANGEDB_plugin_unload (dbc.plugin); + dbc.plugin = NULL; + result = 77; + return GNUNET_NO; + } + dbc.session = dbc.plugin->get_session (dbc.plugin->cls); + GNUNET_assert (NULL != dbc.session); + + return GNUNET_OK; +} + + +/** + * Collects all the tests. + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_TESTING_Command all[] = { + + // check no aggregation happens on a empty database + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty-db", + config_filename), + TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), + + /* check aggregation happens on the simplest case: + one deposit into the database. */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-1", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-deposit-1", + config_filename), + + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1", + ec.exchange_url, + "EUR:0.89", + bc.exchange_payto, + bc.user42_payto), + TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-1"), + + /* check aggregation accumulates well. */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-2a", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + "EUR:0.1"), + + TALER_TESTING_cmd_insert_deposit ("do-deposit-2b", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + "EUR:0.1"), + + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-2", + config_filename), + + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-2", + ec.exchange_url, + "EUR:1.79", + bc.exchange_payto, + bc.user42_payto), + TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-2"), + + /* check that different merchants stem different aggregations. */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-3a", + &dbc, + "bob", + "4", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + "EUR:0.1"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-3b", + &dbc, + "bob", + "5", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + "EUR:0.1"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-3c", + &dbc, + "alice", + "4", + GNUNET_TIME_UNIT_ZERO, + "EUR:1", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-3", + config_filename), + + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3a", + ec.exchange_url, + "EUR:0.89", + bc.exchange_payto, + "payto://x-taler-bank/localhost/4"), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3b", + ec.exchange_url, + "EUR:0.89", + bc.exchange_payto, + "payto://x-taler-bank/localhost/4"), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3c", + ec.exchange_url, + "EUR:0.89", + bc.exchange_payto, + "payto://x-taler-bank/localhost/5"), + TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-3"), + + /* checking that aggregator waits for the deadline. */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-4a", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 5), + "EUR:0.2", + "EUR:0.1"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-4b", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 5), + "EUR:0.2", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-early", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-4-fast"), + + TALER_TESTING_cmd_sleep ("wait (5s)", 5), + + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-delayed", + config_filename), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-4", + ec.exchange_url, + "EUR:0.19", + bc.exchange_payto, + bc.user42_payto), + + // test picking all deposits at earliest deadline + TALER_TESTING_cmd_insert_deposit ("do-deposit-5a", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 10), + "EUR:0.2", + "EUR:0.1"), + + TALER_TESTING_cmd_insert_deposit ("do-deposit-5b", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 5), + "EUR:0.2", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-early", + config_filename), + + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-5-early"), + TALER_TESTING_cmd_sleep ("wait (5s)", 5), + + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-delayed", + config_filename), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-5", + ec.exchange_url, + "EUR:0.19", + bc.exchange_payto, + bc.user42_payto), + /* Test NEVER running 'tiny' unless they make up minimum unit */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-6a", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.102", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6a-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-6a-tiny"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-6b", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.102", + "EUR:0.1"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-6c", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.102", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6c-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-6c-tiny"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-6d", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.102", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6d-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-6d-tiny"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-6e", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.112", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6e", + config_filename), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-6", + ec.exchange_url, + "EUR:0.01", + bc.exchange_payto, + bc.user42_payto), + + /* Test profiteering if wire deadline is short */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-7a", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.109", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7a-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-7a-tiny"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-7b", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.119", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-profit", + config_filename), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7", + ec.exchange_url, + "EUR:0.01", + bc.exchange_payto, + bc.user42_payto), + + /* Now check profit was actually taken */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-7c", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.122", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-loss", + config_filename), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7", + ec.exchange_url, + "EUR:0.01", + bc.exchange_payto, + bc.user42_payto), + + /* Test that aggregation would happen fully if wire deadline is long */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-8a", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 5), + "EUR:0.109", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8a-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-8a-tiny"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-8b", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 5), + "EUR:0.109", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8b-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-8b-tiny"), + + /* now trigger aggregate with large transaction and short deadline */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-8c", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.122", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8", + config_filename), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-8", + ec.exchange_url, + "EUR:0.03", + bc.exchange_payto, + bc.user42_payto), + + /* Test aggregation with fees and rounding profits. */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-9a", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 5), + "EUR:0.104", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9a-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-9a-tiny"), + TALER_TESTING_cmd_insert_deposit ("do-deposit-9b", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_relative_multiply + (GNUNET_TIME_UNIT_SECONDS, + 5), + "EUR:0.105", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9b-tiny", + config_filename), + TALER_TESTING_cmd_check_bank_empty ( + "expect-empty-transactions-after-9b-tiny"), + + /* now trigger aggregate with large transaction and short deadline */ + TALER_TESTING_cmd_insert_deposit ("do-deposit-9c", + &dbc, + "bob", + USER42_ACCOUNT, + GNUNET_TIME_UNIT_ZERO, + "EUR:0.112", + "EUR:0.1"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9", + config_filename), + /* 0.009 + 0.009 + 0.022 - 0.001 - 0.002 - 0.008 = 0.029 => 0.02 */ + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-9", + ec.exchange_url, + "EUR:0.01", + bc.exchange_payto, + bc.user42_payto), + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run_with_fakebank (is, + all, + bc.exchange_auth.wire_gateway_url); +} + + +int +main (int argc, + char *const argv[]) +{ + const char *plugin_name; + char *testname; + + if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) + { + GNUNET_break (0); + return -1; + } + plugin_name++; + (void) GNUNET_asprintf (&testname, + "test-taler-exchange-aggregator-%s", + plugin_name); + (void) GNUNET_asprintf (&config_filename, + "%s.conf", + testname); + + GNUNET_log_setup ("test_taler_exchange_aggregator", + "DEBUG", + NULL); + + /* these might get in the way */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + + TALER_TESTING_cleanup_files (config_filename); + + if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename, + &ec)) + { + TALER_LOG_WARNING ("Could not prepare the exchange.\n"); + return 77; + } + + if (GNUNET_OK != TALER_TESTING_prepare_fakebank (config_filename, + "account-1", + &bc)) + { + TALER_LOG_WARNING ("Could not prepare the fakebank\n"); + return 77; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_parse_and_run (config_filename, + &prepare_database, + NULL)) + { + TALER_LOG_WARNING ("Could not prepare database for tests.\n"); + return result; + } + + result = TALER_TESTING_setup (&run, + NULL, + config_filename, + NULL, // no exchange process handle. + GNUNET_NO); // do not try to connect to the exchange + + GNUNET_free (config_filename); + GNUNET_free (testname); + dbc.plugin->drop_tables (dbc.plugin->cls); + TALER_EXCHANGEDB_plugin_unload (dbc.plugin); + return GNUNET_OK == result ? 0 : 1; +} + + +/* end of test_taler_exchange_aggregator.c */ diff --git a/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json b/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json new file mode 100644 index 000000000..f39677eff --- /dev/null +++ b/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json @@ -0,0 +1,4 @@ +{ + "url": "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-keys/master.priv b/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv new file mode 100644 index 000000000..394926938 --- /dev/null +++ b/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv @@ -0,0 +1 @@ +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 new file mode 100644 index 000000000..5a202bef0 --- /dev/null +++ b/src/testing/test_taler_exchange_wirewatch.c @@ -0,0 +1,182 @@ +/* + This file is part of TALER + (C) 2016, 2017, 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see +*/ + +/** + * @file testing/test_taler_exchange_wirewatch.c + * @brief Tests for taler-exchange-wirewatch and taler-exchange-aggregator logic; + * Performs an invalid wire transfer to the exchange, and then checks that + * wirewatch immediately sends the money back. + * Then performs a valid wire transfer, waits for the reserve to expire, + * and then checks that the aggregator sends the money back. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include +#include +#include "taler_json_lib.h" +#include +#include "taler_fakebank_lib.h" +#include "taler_testing_lib.h" + + +/** + * Bank configuration data. + */ +static struct TALER_TESTING_BankConfiguration bc; + +/** + * Helper structure to keep exchange configuration values. + */ +static struct TALER_TESTING_ExchangeConfiguration ec; + +/** + * Name of the configuration file to use. + */ +static char *config_filename; + +static struct TALER_TESTING_Command +transfer_to_exchange (const char *label, + const char *amount) +{ + return TALER_TESTING_cmd_admin_add_incoming (label, + amount, + &bc.exchange_auth, + bc.user42_payto); +} + + +/** + * Main function that will tell the interpreter what commands to + * run. + * + * @param cls closure + */ +static void +run (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + struct TALER_TESTING_Command all[] = { + TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty", + config_filename), + TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty", + config_filename), + TALER_TESTING_cmd_check_bank_empty ("expect-transfers-empty-after-dry-run"), + + transfer_to_exchange ("run-transfer-good-to-exchange", + "EUR:5"), + TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-good-transfer", + config_filename), + + TALER_TESTING_cmd_check_bank_admin_transfer ( + "clear-good-transfer-to-the-exchange", + "EUR:5", + bc.user42_payto, // debit + bc.exchange_payto, // credit + "run-transfer-good-to-exchange"), + + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-non-expired-reserve", + config_filename), + + TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-1"), + TALER_TESTING_cmd_sleep ("wait (5s)", + 5), + TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-expired-reserve", + config_filename), + TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1", + ec.exchange_url, + "EUR:4.99", + bc.exchange_payto, + bc.user42_payto), + TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-2"), + TALER_TESTING_cmd_end () + }; + + TALER_TESTING_run_with_fakebank (is, + all, + bc.exchange_auth.wire_gateway_url); +} + + +int +main (int argc, + char *const argv[]) +{ + const char *plugin_name; + + /* these might get in the way */ + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test_taler_exchange_wirewatch", + "DEBUG", + NULL); + + if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) + { + GNUNET_break (0); + return -1; + } + plugin_name++; + { + char *testname; + + GNUNET_asprintf (&testname, + "test-taler-exchange-wirewatch-%s", + plugin_name); + GNUNET_asprintf (&config_filename, + "%s.conf", + testname); + GNUNET_free (testname); + } + /* check database is working */ + { + struct GNUNET_PQ_Context *conn; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_EXECUTE_STATEMENT_END + }; + + conn = GNUNET_PQ_connect ("postgres:///talercheck", + NULL, + es, + NULL); + if (NULL == conn) + return 77; + GNUNET_PQ_disconnect (conn); + } + + TALER_TESTING_cleanup_files (config_filename); + if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename, + &ec)) + { + TALER_LOG_INFO ("Could not prepare the exchange\n"); + return 77; + } + + if (GNUNET_OK != + TALER_TESTING_prepare_fakebank (config_filename, + "account-1", + &bc)) + return 77; + + return + (GNUNET_OK == TALER_TESTING_setup_with_exchange (&run, + NULL, + config_filename)) ? 0 : 1; +} + + +/* end of test_taler_exchange_wirewatch.c */ diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c new file mode 100644 index 000000000..6115ceef6 --- /dev/null +++ b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c @@ -0,0 +1,444 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_auditor_deposit_confirmation.c + * @brief command for testing /deposit_confirmation. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_auditor_service.h" +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "deposit confirmation" CMD. + */ +struct DepositConfirmationState +{ + + /** + * Reference to any command that is able to provide a deposit. + */ + const char *deposit_reference; + + /** + * What is the deposited amount without the fee (i.e. the + * amount we expect in the deposit confirmation)? + */ + const char *amount_without_fee; + + /** + * Which coin of the @e deposit_reference should we confirm. + */ + unsigned int coin_index; + + /** + * DepositConfirmation handle while operation is running. + */ + struct TALER_AUDITOR_DepositConfirmationHandle *dc; + + /** + * Auditor connection. + */ + struct TALER_AUDITOR_Handle *auditor; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Should we retry on (transient) failures? + */ + int do_retry; + +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +deposit_confirmation_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #deposit_confirmation_run. + * + * @param cls a `struct DepositConfirmationState` + */ +static void +do_retry (void *cls) +{ + struct DepositConfirmationState *dcs = cls; + + dcs->retry_task = NULL; + deposit_confirmation_run (dcs, + NULL, + dcs->is); +} + + +/** + * Callback to analyze the /deposit-confirmation response, just used + * to check if the response code is acceptable. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param obj raw response from the auditor. + */ +static void +deposit_confirmation_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const json_t *obj) +{ + struct DepositConfirmationState *dcs = cls; + + dcs->dc = NULL; + if (dcs->expected_response_code != http_status) + { + if (GNUNET_YES == dcs->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying deposit confirmation failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + dcs->backoff = GNUNET_TIME_UNIT_ZERO; + else + dcs->backoff = EXCHANGE_LIB_BACKOFF (dcs->backoff); + dcs->retry_task = GNUNET_SCHEDULER_add_delayed (dcs->backoff, + &do_retry, + dcs); + return; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s in %s:%u\n", + http_status, + dcs->is->commands[dcs->is->ip].label, + __FILE__, + __LINE__); + json_dumpf (obj, stderr, 0); + TALER_TESTING_interpreter_fail (dcs->is); + return; + } + TALER_TESTING_interpreter_next (dcs->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +deposit_confirmation_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct DepositConfirmationState *dcs = cls; + const struct TALER_TESTING_Command *deposit_cmd; + struct GNUNET_HashCode h_wire; + struct GNUNET_HashCode h_contract_terms; + struct GNUNET_TIME_Absolute timestamp; + struct GNUNET_TIME_Absolute refund_deadline; + struct TALER_Amount amount_without_fee; + struct TALER_CoinSpendPublicKeyP coin_pub; + const struct TALER_MerchantPrivateKeyP *merchant_priv; + struct TALER_MerchantPublicKeyP merchant_pub; + const struct TALER_ExchangePublicKeyP *exchange_pub; + const struct TALER_ExchangeSignatureP *exchange_sig; + const json_t *wire_details; + const json_t *contract_terms; + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + const struct TALER_EXCHANGE_Keys *keys; + const struct TALER_EXCHANGE_SigningPublicKey *spk; + + dcs->is = is; + GNUNET_assert (NULL != dcs->deposit_reference); + deposit_cmd + = TALER_TESTING_interpreter_lookup_command (is, + dcs->deposit_reference); + if (NULL == deposit_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_pub (deposit_cmd, + dcs->coin_index, + &exchange_pub)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_sig (deposit_cmd, + dcs->coin_index, + &exchange_sig)); + keys = TALER_EXCHANGE_get_keys (dcs->is->exchange); + GNUNET_assert (NULL != keys); + spk = TALER_EXCHANGE_get_exchange_signing_key_info (keys, + exchange_pub); + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_contract_terms (deposit_cmd, + dcs->coin_index, + &contract_terms)); + /* Very unlikely to fail */ + GNUNET_assert (NULL != contract_terms); + GNUNET_assert (GNUNET_OK == + TALER_JSON_hash (contract_terms, + &h_contract_terms)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_wire_details (deposit_cmd, + dcs->coin_index, + &wire_details)); + GNUNET_assert (GNUNET_OK == + TALER_JSON_merchant_wire_signature_hash (wire_details, + &h_wire)); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_coin_priv (deposit_cmd, + dcs->coin_index, + &coin_priv)); + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin_pub.eddsa_pub); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_merchant_priv (deposit_cmd, + dcs->coin_index, + &merchant_priv)); + GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv, + &merchant_pub.eddsa_pub); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (dcs->amount_without_fee, + &amount_without_fee)); + /* timestamp is mandatory */ + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_absolute_time ("timestamp", ×tamp), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (contract_terms, + spec, + NULL, NULL)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + /* refund deadline is optional, defaults to zero */ + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_absolute_time ("refund_deadline", &refund_deadline), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (contract_terms, + spec, + NULL, NULL)) + { + refund_deadline = timestamp; + } + } + dcs->dc = TALER_AUDITOR_deposit_confirmation + (dcs->auditor, + &h_wire, + &h_contract_terms, + timestamp, + refund_deadline, + &amount_without_fee, + &coin_pub, + &merchant_pub, + exchange_pub, + exchange_sig, + &keys->master_pub, + spk->valid_from, + spk->valid_until, + spk->valid_legal, + &spk->master_sig, + &deposit_confirmation_cb, + dcs); + + if (NULL == dcs->dc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + return; +} + + +/** + * Free the state of a "deposit_confirmation" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, a `struct DepositConfirmationState` + * @param cmd the command which is being cleaned up. + */ +static void +deposit_confirmation_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct DepositConfirmationState *dcs = cls; + + if (NULL != dcs->dc) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + dcs->is->ip, + cmd->label); + TALER_AUDITOR_deposit_confirmation_cancel (dcs->dc); + dcs->dc = NULL; + } + if (NULL != dcs->retry_task) + { + GNUNET_SCHEDULER_cancel (dcs->retry_task); + dcs->retry_task = NULL; + } + GNUNET_free (dcs); +} + + +/** + * Offer internal data to other commands. + * + * @param cls closure. + * @param[out] ret set to the wanted data. + * @param trait name of the trait. + * @param index index number of the traits to be returned. + * + * @return #GNUNET_OK on success + */ +static int +deposit_confirmation_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + /* Must define this function because some callbacks + * look for certain traits on _all_ the commands. */ + return GNUNET_SYSERR; +} + + +/** + * Create a "deposit-confirmation" command. + * + * @param label command label. + * @param auditor auditor connection. + * @param deposit_reference reference to any operation that can + * provide a coin. + * @param coin_index if @a deposit_reference offers an array of + * coins, this parameter selects which one in that array. + * This value is currently ignored, as only one-coin + * deposits are implemented. + * @param amount_without_fee deposited amount without the fee + * @param expected_response_code expected HTTP response code. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_deposit_confirmation (const char *label, + struct TALER_AUDITOR_Handle *auditor, + const char *deposit_reference, + unsigned int coin_index, + const char *amount_without_fee, + unsigned int expected_response_code) +{ + struct DepositConfirmationState *dcs; + + dcs = GNUNET_new (struct DepositConfirmationState); + dcs->auditor = auditor; + dcs->deposit_reference = deposit_reference; + dcs->coin_index = coin_index; + dcs->amount_without_fee = amount_without_fee; + dcs->expected_response_code = expected_response_code; + + { + struct TALER_TESTING_Command cmd = { + .cls = dcs, + .label = label, + .run = &deposit_confirmation_run, + .cleanup = &deposit_confirmation_cleanup, + .traits = &deposit_confirmation_traits + }; + + return cmd; + } +} + + +/** + * Modify a deposit confirmation command to enable retries when we get + * transient errors from the auditor. + * + * @param cmd a deposit confirmation command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_deposit_confirmation_with_retry (struct TALER_TESTING_Command + cmd) +{ + struct DepositConfirmationState *dcs; + + GNUNET_assert (&deposit_confirmation_run == cmd.run); + dcs = cmd.cls; + dcs->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_auditor_api_cmd_deposit_confirmation.c */ diff --git a/src/testing/testing_api_cmd_auditor_exchanges.c b/src/testing/testing_api_cmd_auditor_exchanges.c new file mode 100644 index 000000000..c7acaab9a --- /dev/null +++ b/src/testing/testing_api_cmd_auditor_exchanges.c @@ -0,0 +1,361 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#include "taler_auditor_service.h" +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "deposit confirmation" CMD. + */ +struct ExchangesState +{ + + /** + * Exchanges handle while operation is running. + */ + struct TALER_AUDITOR_ListExchangesHandle *leh; + + /** + * Auditor connection. + */ + struct TALER_AUDITOR_Handle *auditor; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * URL of the exchange expected to be included in the response. + */ + const char *exchange_url; + + /** + * Should we retry on (transient) failures? + */ + int do_retry; + +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +exchanges_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #exchanges_run. + * + * @param cls a `struct ExchangesState` + */ +static void +do_retry (void *cls) +{ + struct ExchangesState *es = cls; + + es->retry_task = NULL; + exchanges_run (es, + NULL, + es->is); +} + + +/** + * Callback to analyze the /exchanges response. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param num_exchanges length of the @a ei array + * @param ei array with information about the exchanges + * @param raw_response raw response from the auditor. + */ +static void +exchanges_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + unsigned int num_exchanges, + const struct TALER_AUDITOR_ExchangeInfo *ei, + const json_t *raw_response) +{ + struct ExchangesState *es = cls; + + es->leh = NULL; + if (es->expected_response_code != http_status) + { + if (GNUNET_YES == es->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying list exchanges failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + es->backoff = GNUNET_TIME_UNIT_ZERO; + else + es->backoff = EXCHANGE_LIB_BACKOFF (es->backoff); + es->retry_task = GNUNET_SCHEDULER_add_delayed (es->backoff, + &do_retry, + es); + return; + } + } + GNUNET_log + (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s in %s:%u\n", + http_status, + es->is->commands[es->is->ip].label, + __FILE__, + __LINE__); + json_dumpf (raw_response, stderr, 0); + TALER_TESTING_interpreter_fail (es->is); + return; + } + if (NULL != es->exchange_url) + { + unsigned int found = GNUNET_NO; + + for (unsigned int i = 0; + iexchange_url, + ei[i].exchange_url)) + found = GNUNET_YES; + if (GNUNET_NO == found) + { + TALER_LOG_ERROR + ("Exchange '%s' doesn't exist at this auditor\n", + es->exchange_url); + TALER_TESTING_interpreter_fail (es->is); + return; + } + + TALER_LOG_DEBUG ("Exchange '%s' exists at this auditor!\n", + es->exchange_url); + } + TALER_TESTING_interpreter_next (es->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +exchanges_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct ExchangesState *es = cls; + + es->is = is; + es->leh = TALER_AUDITOR_list_exchanges + (is->auditor, + &exchanges_cb, + es); + + if (NULL == es->leh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + return; +} + + +/** + * Free the state of a "exchanges" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, a `struct ExchangesState` + * @param cmd the command which is being cleaned up. + */ +static void +exchanges_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct ExchangesState *es = cls; + + if (NULL != es->leh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + es->is->ip, + cmd->label); + TALER_AUDITOR_list_exchanges_cancel (es->leh); + es->leh = NULL; + } + if (NULL != es->retry_task) + { + GNUNET_SCHEDULER_cancel (es->retry_task); + es->retry_task = NULL; + } + GNUNET_free (es); +} + + +/** + * Offer internal data to other commands. + * + * @param cls closure. + * @param[out] ret set to the wanted data. + * @param trait name of the trait. + * @param index index number of the traits to be returned. + * @return #GNUNET_OK on success + */ +static int +exchanges_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + /* Must define this function because some callbacks + * look for certain traits on _all_ the commands. */ + return GNUNET_SYSERR; +} + + +/** + * Create a "list exchanges" command. + * + * @param label command label. + * @param auditor auditor connection. + * @param expected_response_code expected HTTP response code. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exchanges (const char *label, + struct TALER_AUDITOR_Handle *auditor, + unsigned int expected_response_code) +{ + struct ExchangesState *es; + + es = GNUNET_new (struct ExchangesState); + es->auditor = auditor; + es->expected_response_code = expected_response_code; + + { + struct TALER_TESTING_Command cmd = { + .cls = es, + .label = label, + .run = &exchanges_run, + .cleanup = &exchanges_cleanup, + .traits = &exchanges_traits + }; + + return cmd; + } +} + + +/** + * Create a "list exchanges" command and check whether + * a particular exchange belongs to the returned bundle. + * + * @param label command label. + * @param expected_response_code expected HTTP response code. + * @param exchange_url URL of the exchange supposed to + * be included in the response. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exchanges_with_url (const char *label, + unsigned int expected_response_code, + const char *exchange_url) +{ + struct ExchangesState *es; + + es = GNUNET_new (struct ExchangesState); + es->expected_response_code = expected_response_code; + es->exchange_url = exchange_url; + { + struct TALER_TESTING_Command cmd = { + .cls = es, + .label = label, + .run = &exchanges_run, + .cleanup = &exchanges_cleanup, + .traits = &exchanges_traits + }; + + return cmd; + } +} + + +/** + * Modify an exchanges command to enable retries when we get + * transient errors from the auditor. + * + * @param cmd a deposit confirmation command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exchanges_with_retry (struct TALER_TESTING_Command cmd) +{ + struct ExchangesState *es; + + GNUNET_assert (&exchanges_run == cmd.run); + es = cmd.cls; + es->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_auditor_api_cmd_exchanges.c */ diff --git a/src/testing/testing_api_cmd_auditor_exec_auditor.c b/src/testing/testing_api_cmd_auditor_exec_auditor.c new file mode 100644 index 000000000..4e071d0c2 --- /dev/null +++ b/src/testing/testing_api_cmd_auditor_exec_auditor.c @@ -0,0 +1,165 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ +/** + * @file testing/testing_api_cmd_auditor_exec_auditor.c + * @brief run the taler-auditor command + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "auditor" CMD. + */ +struct AuditorState +{ + + /** + * Process for the "auditor" command. + */ + struct GNUNET_OS_Process *auditor_proc; + + /** + * Configuration file used by the command. + */ + const char *config_filename; +}; + + +/** + * Run the command; calls the `taler-auditor' program. + * + * @param cls closure. + * @param cmd the commaind being run. + * @param is interpreter state. + */ +static void +auditor_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AuditorState *ks = cls; + + ks->auditor_proc + = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor", + "taler-auditor", + "-c", ks->config_filename, + NULL); + if (NULL == ks->auditor_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "auditor" CMD, and possibly kills its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +auditor_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AuditorState *ks = cls; + + if (NULL != ks->auditor_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ks->auditor_proc, + SIGKILL)); + GNUNET_OS_process_wait (ks->auditor_proc); + GNUNET_OS_process_destroy (ks->auditor_proc); + ks->auditor_proc = NULL; + } + GNUNET_free (ks); +} + + +/** + * Offer "auditor" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +auditor_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AuditorState *ks = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, &ks->auditor_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make the "exec-auditor" CMD. + * + * @param label command label. + * @param config_filename configuration filename. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_auditor (const char *label, + const char *config_filename) +{ + struct AuditorState *ks; + + ks = GNUNET_new (struct AuditorState); + ks->config_filename = config_filename; + { + struct TALER_TESTING_Command cmd = { + .cls = ks, + .label = label, + .run = &auditor_run, + .cleanup = &auditor_cleanup, + .traits = &auditor_traits + }; + + return cmd; + } +} + + +/* end of testing_auditor_api_cmd_exec_auditor.c */ diff --git a/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c b/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c new file mode 100644 index 000000000..0c537747b --- /dev/null +++ b/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c @@ -0,0 +1,166 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ +/** + * @file testing/testing_api_cmd_auditor_exec_auditor_dbinit.c + * @brief run the taler-auditor-dbinit "-r" command + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "auditor-dbinit" CMD. + */ +struct AuditorDbinitState +{ + + /** + * Process for the "auditor-dbinit" command. + */ + struct GNUNET_OS_Process *auditor_dbinit_proc; + + /** + * Configuration file used by the command. + */ + const char *config_filename; +}; + + +/** + * Run the command; calls the `taler-auditor-dbinit' program. + * + * @param cls closure. + * @param cmd the commaind being run. + * @param is interpreter state. + */ +static void +auditor_dbinit_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AuditorDbinitState *ks = cls; + + ks->auditor_dbinit_proc + = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor-dbinit", + "taler-auditor-dbinit", + "-c", ks->config_filename, + "-r", + NULL); + if (NULL == ks->auditor_dbinit_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "auditor-dbinit" CMD, and possibly kills its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +auditor_dbinit_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AuditorDbinitState *ks = cls; + + if (NULL != ks->auditor_dbinit_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ks->auditor_dbinit_proc, + SIGKILL)); + GNUNET_OS_process_wait (ks->auditor_dbinit_proc); + GNUNET_OS_process_destroy (ks->auditor_dbinit_proc); + ks->auditor_dbinit_proc = NULL; + } + GNUNET_free (ks); +} + + +/** + * Offer "auditor-dbinit" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +auditor_dbinit_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AuditorDbinitState *ks = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, &ks->auditor_dbinit_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make the "exec-auditor-dbinit" CMD. + * + * @param label command label. + * @param config_filename configuration filename. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_auditor_dbinit (const char *label, + const char *config_filename) +{ + struct AuditorDbinitState *ks; + + ks = GNUNET_new (struct AuditorDbinitState); + ks->config_filename = config_filename; + { + struct TALER_TESTING_Command cmd = { + .cls = ks, + .label = label, + .run = &auditor_dbinit_run, + .cleanup = &auditor_dbinit_cleanup, + .traits = &auditor_dbinit_traits + }; + + return cmd; + } +} + + +/* end of testing_auditor_api_cmd_exec_auditor_dbinit.c */ diff --git a/src/testing/testing_api_cmd_auditor_exec_wire_auditor.c b/src/testing/testing_api_cmd_auditor_exec_wire_auditor.c new file mode 100644 index 000000000..5e3701fc9 --- /dev/null +++ b/src/testing/testing_api_cmd_auditor_exec_wire_auditor.c @@ -0,0 +1,165 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ +/** + * @file testing/testing_api_cmd_auditor_exec_wire_auditor.c + * @brief run the taler-wire-auditor command + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "wire-auditor" CMD. + */ +struct WireAuditorState +{ + + /** + * Process for the "wire-auditor" command. + */ + struct GNUNET_OS_Process *wire_auditor_proc; + + /** + * Configuration file used by the command. + */ + const char *config_filename; +}; + + +/** + * Run the command; calls the `taler-wire-auditor' program. + * + * @param cls closure. + * @param cmd the commaind being run. + * @param is interpreter state. + */ +static void +wire_auditor_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct WireAuditorState *ks = cls; + + ks->wire_auditor_proc + = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-wire-auditor", + "taler-wire-auditor", + "-c", ks->config_filename, + NULL); + if (NULL == ks->wire_auditor_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "wire-auditor" CMD, and possibly kills its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +wire_auditor_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct WireAuditorState *ks = cls; + + if (NULL != ks->wire_auditor_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ks->wire_auditor_proc, + SIGKILL)); + GNUNET_OS_process_wait (ks->wire_auditor_proc); + GNUNET_OS_process_destroy (ks->wire_auditor_proc); + ks->wire_auditor_proc = NULL; + } + GNUNET_free (ks); +} + + +/** + * Offer "wire-auditor" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +wire_auditor_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct WireAuditorState *ks = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, &ks->wire_auditor_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make the "exec wire-auditor" CMD. + * + * @param label command label. + * @param config_filename configuration filename. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_wire_auditor (const char *label, + const char *config_filename) +{ + struct WireAuditorState *ks; + + ks = GNUNET_new (struct WireAuditorState); + ks->config_filename = config_filename; + { + struct TALER_TESTING_Command cmd = { + .cls = ks, + .label = label, + .run = &wire_auditor_run, + .cleanup = &wire_auditor_cleanup, + .traits = &wire_auditor_traits + }; + + return cmd; + } +} + + +/* end of testing_auditor_api_cmd_exec_wire_auditor.c */ diff --git a/src/testing/testing_api_cmd_bank_admin_add_incoming.c b/src/testing/testing_api_cmd_bank_admin_add_incoming.c new file mode 100644 index 000000000..2398c5be3 --- /dev/null +++ b/src/testing/testing_api_cmd_bank_admin_add_incoming.c @@ -0,0 +1,596 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_bank_admin_add_incoming.c + * @brief implementation of a bank /admin/add-incoming command + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "backoff.h" +#include "taler_json_lib.h" +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "fakebank transfer" CMD. + */ +struct AdminAddIncomingState +{ + + /** + * Label of any command that can trait-offer a reserve priv. + */ + const char *reserve_reference; + + /** + * Wire transfer amount. + */ + struct TALER_Amount amount; + + /** + * Base URL of the credited account. + */ + const char *exchange_credit_url; + + /** + * Money sender payto URL. + */ + const char *payto_debit_account; + + /** + * Username to use for authentication. + */ + struct TALER_BANK_AuthenticationData auth; + + /** + * Set (by the interpreter) to the reserve's private key + * we used to make a wire transfer subject line with. + */ + struct TALER_ReservePrivateKeyP reserve_priv; + + /** + * Reserve public key matching @e reserve_priv. + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Handle to the pending request at the fakebank. + */ + struct TALER_BANK_AdminAddIncomingHandle *aih; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Set to the wire transfer's unique ID. + */ + uint64_t serial_id; + + /** + * Timestamp of the transaction (as returned from the bank). + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Merchant instance. Sometimes used to get the tip reserve + * private key by reading the appropriate config section. + */ + const char *instance; + + /** + * Configuration filename. Used to get the tip reserve key + * filename (used to obtain a public key to write in the + * transfer subject). + */ + const char *config_filename; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Was this command modified via + * #TALER_TESTING_cmd_admin_add_incoming_with_retry to + * enable retries? + */ + int do_retry; +}; + + +/** + * Run the "fakebank transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +admin_add_incoming_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #admin_add_incoming_run. + * + * @param cls a `struct AdminAddIncomingState` + */ +static void +do_retry (void *cls) +{ + struct AdminAddIncomingState *fts = cls; + + fts->retry_task = NULL; + admin_add_incoming_run (fts, + NULL, + fts->is); +} + + +/** + * This callback will process the fakebank response to the wire + * transfer. It just checks whether the HTTP response code is + * acceptable. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for + * successful status request; 0 if the exchange's reply is + * bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success + * @param serial_id unique ID of the wire transfer + * @param timestamp time stamp of the transaction made. + * @param json raw response + */ +static void +confirmation_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t serial_id, + struct GNUNET_TIME_Absolute timestamp, + const json_t *json) +{ + struct AdminAddIncomingState *fts = cls; + struct TALER_TESTING_Interpreter *is = fts->is; + + fts->aih = NULL; + if (MHD_HTTP_OK != http_status) + { + if (GNUNET_YES == fts->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log + (GNUNET_ERROR_TYPE_INFO, + "Retrying fakebank transfer failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + fts->backoff = GNUNET_TIME_UNIT_ZERO; + else + fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); + fts->retry_task = GNUNET_SCHEDULER_add_delayed + (fts->backoff, + &do_retry, + fts); + return; + } + } + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fakebank returned HTTP status %u/%d\n", + http_status, + (int) ec); + TALER_TESTING_interpreter_fail (is); + return; + } + + fts->serial_id = serial_id; + fts->timestamp = timestamp; + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the "fakebank transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +admin_add_incoming_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AdminAddIncomingState *fts = cls; + + /* Use reserve public key as subject */ + if (NULL != fts->reserve_reference) + { + const struct TALER_TESTING_Command *ref; + const struct TALER_ReservePrivateKeyP *reserve_priv; + + ref = TALER_TESTING_interpreter_lookup_command + (is, fts->reserve_reference); + if (NULL == ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (ref, + 0, + &reserve_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv; + } + else + { + if (NULL != fts->instance) + { + char *section; + char *keys; + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct GNUNET_CONFIGURATION_Handle *cfg; + + GNUNET_assert (NULL != fts->config_filename); + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (cfg, + fts->config_filename)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_asprintf (§ion, + "instance-%s", + fts->instance); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename + (cfg, + section, + "TIP_RESERVE_PRIV_FILENAME", + &keys)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Configuration fails to specify reserve" + " private key filename in section %s\n", + section); + GNUNET_free (section); + TALER_TESTING_interpreter_fail (is); + return; + } + priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys); + GNUNET_free (keys); + if (NULL == priv) + { + GNUNET_log_config_invalid + (GNUNET_ERROR_TYPE_ERROR, + section, + "TIP_RESERVE_PRIV_FILENAME", + "Failed to read private key"); + GNUNET_free (section); + TALER_TESTING_interpreter_fail (is); + return; + } + fts->reserve_priv.eddsa_priv = *priv; + GNUNET_free (section); + GNUNET_free (priv); + GNUNET_CONFIGURATION_destroy (cfg); + } + else + { + /* No referenced reserve, no instance to take priv + * from, no explicit subject given: create new key! */ + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + + priv = GNUNET_CRYPTO_eddsa_key_create (); + fts->reserve_priv.eddsa_priv = *priv; + GNUNET_free (priv); + } + } + GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv, + &fts->reserve_pub.eddsa_pub); + fts->is = is; + fts->aih + = TALER_BANK_admin_add_incoming + (TALER_TESTING_interpreter_get_context (is), + &fts->auth, + &fts->reserve_pub, + &fts->amount, + fts->payto_debit_account, + &confirmation_cb, + fts); + if (NULL == fts->aih) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "/admin/add-incoming" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure + * @param cmd current CMD being cleaned up. + */ +static void +admin_add_incoming_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AdminAddIncomingState *fts = cls; + + if (NULL != fts->aih) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %s did not complete\n", + cmd->label); + TALER_BANK_admin_add_incoming_cancel (fts->aih); + fts->aih = NULL; + } + if (NULL != fts->retry_task) + { + GNUNET_SCHEDULER_cancel (fts->retry_task); + fts->retry_task = NULL; + } + GNUNET_free (fts); +} + + +/** + * Offer internal data from a "/admin/add-incoming" CMD to other + * commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +admin_add_incoming_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AdminAddIncomingState *fts = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_bank_row (&fts->serial_id), + TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT, + fts->payto_debit_account), + /* Used as a marker, content does not matter */ + TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT, + "payto://void/the-exchange"), + TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL, + fts->exchange_credit_url), + TALER_TESTING_make_trait_amount_obj (0, &fts->amount), + TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), + TALER_TESTING_make_trait_reserve_priv (0, + &fts->reserve_priv), + TALER_TESTING_make_trait_reserve_pub (0, + &fts->reserve_pub), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create internal state for "/admin/add-incoming" CMD. + * + * @param amount the amount to transfer. + * @param payto_debit_account which account sends money + * @param auth authentication data + * @return the internal state + */ +static struct AdminAddIncomingState * +make_fts (const char *amount, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_debit_account) +{ + struct AdminAddIncomingState *fts; + + fts = GNUNET_new (struct AdminAddIncomingState); + fts->exchange_credit_url = auth->wire_gateway_url; + fts->payto_debit_account = payto_debit_account; + fts->auth = *auth; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &fts->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s'\n", + amount); + GNUNET_assert (0); + } + return fts; +} + + +/** + * Helper function to create admin/add-incoming command. + * + * @param label command label. + * @param fts internal state to use + * @return the command. + */ +static struct TALER_TESTING_Command +make_command (const char *label, + struct AdminAddIncomingState *fts) +{ + struct TALER_TESTING_Command cmd = { + .cls = fts, + .label = label, + .run = &admin_add_incoming_run, + .cleanup = &admin_add_incoming_cleanup, + .traits = &admin_add_incoming_traits + }; + + return cmd; +} + + +/** + * Create admin/add-incoming command. + * + * @param label command label. + * @param amount amount to transfer. + * @param payto_debit_account which account sends money. + * @param auth authentication data + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming (const char *label, + const char *amount, + const struct + TALER_BANK_AuthenticationData *auth, + const char *payto_debit_account) +{ + return make_command (label, + make_fts (amount, + auth, + payto_debit_account)); +} + + +/** + * Create "/admin/add-incoming" CMD, letting the caller specify + * a reference to a command that can offer a reserve private key. + * This private key will then be used to construct the subject line + * of the wire transfer. + * + * @param label command label. + * @param amount the amount to transfer. + * @param payto_debit_account which account sends money + * @param auth authentication data + * @param ref reference to a command that can offer a reserve + * private key. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_with_ref + (const char *label, + const char *amount, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_debit_account, + const char *ref) +{ + struct AdminAddIncomingState *fts; + + fts = make_fts (amount, + auth, + payto_debit_account); + fts->reserve_reference = ref; + return make_command (label, + fts); +} + + +/** + * Create "/admin/add-incoming" CMD, letting the caller specifying + * the merchant instance. This version is useful when a tip + * reserve should be topped up, in fact the interpreter will need + * the "tipping instance" in order to get the instance public key + * and make a wire transfer subject out of it. + * + * @param label command label. + * @param amount amount to transfer. + * @param payto_debit_account which account (expressed as a number) + * gives money + * @param auth authentication data + * @param instance the instance that runs the tipping. Under this + * instance, the configuration file will provide the private + * key of the tipping reserve. This data will then used to + * construct the wire transfer subject line. + * @param config_filename configuration file to use. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_with_instance + (const char *label, + const char *amount, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_debit_account, + const char *instance, + const char *config_filename) +{ + struct AdminAddIncomingState *fts; + + fts = make_fts (amount, + auth, + payto_debit_account); + fts->instance = instance; + fts->config_filename = config_filename; + + return make_command (label, + fts); +} + + +/** + * Modify a fakebank transfer command to enable retries when the + * reserve is not yet full or we get other transient errors from the + * fakebank. + * + * @param cmd a fakebank transfer command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_admin_add_incoming_retry (struct TALER_TESTING_Command cmd) +{ + struct AdminAddIncomingState *fts; + + GNUNET_assert (&admin_add_incoming_run == cmd.run); + fts = cmd.cls; + fts->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_api_cmd_bank_admin_add_incoming.c */ diff --git a/src/testing/testing_api_cmd_bank_admin_check.c b/src/testing/testing_api_cmd_bank_admin_check.c new file mode 100644 index 000000000..ced2a8c84 --- /dev/null +++ b/src/testing/testing_api_cmd_bank_admin_check.c @@ -0,0 +1,224 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_bank_admin_check.c + * @brief command to check if a particular admin/add-incoming transfer took + * place. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" + + +/** + * State for a "bank check" CMD. + */ +struct BankAdminCheckState +{ + + /** + * Expected transferred amount. + */ + const char *amount; + + /** + * Expected debit bank account. + */ + const char *debit_payto; + + /** + * Expected credit bank account. + */ + const char *credit_payto; + + /** + * Command providing the reserve public key trait to use. + */ + const char *reserve_pub_ref; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + +}; + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +check_bank_admin_transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct BankAdminCheckState *bcs = cls; + struct TALER_Amount amount; + char *debit_account; + char *credit_account; + const char *debit_payto; + const char *credit_payto; + const struct TALER_ReservePublicKeyP *reserve_pub; + const struct TALER_TESTING_Command *cmd_ref; + + cmd_ref + = TALER_TESTING_interpreter_lookup_command (is, + bcs->reserve_pub_ref); + if (NULL == cmd_ref) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_pub (cmd_ref, + 0, + &reserve_pub)) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Command reference fails to provide reserve public key\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_LOG_INFO ("Deposit reference NOT given\n"); + debit_payto = bcs->debit_payto; + credit_payto = bcs->credit_payto; + if (GNUNET_OK != + TALER_string_to_amount (bcs->amount, + &amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + bcs->amount, + is->ip); + TALER_TESTING_interpreter_fail (is); + return; + } + debit_account = TALER_xtalerbank_account_from_payto (debit_payto); + credit_account = TALER_xtalerbank_account_from_payto (credit_payto); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "converted debit_payto (%s) to debit_account (%s)\n", + debit_payto, + debit_account); + if (GNUNET_OK != + TALER_FAKEBANK_check_credit (is->fakebank, + &amount, + debit_account, + credit_account, + reserve_pub)) + { + GNUNET_break (0); + GNUNET_free (credit_account); + GNUNET_free (debit_account); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_free (credit_account); + GNUNET_free (debit_account); + TALER_TESTING_interpreter_next (is); +} + + +/** + * Free the state of a "bank check" CMD. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +check_bank_admin_transfer_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct BankAdminCheckState *bcs = cls; + + GNUNET_free (bcs); +} + + +/** + * Offer internal data from a "bank admin check" CMD state. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +check_bank_admin_transfer_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_trait_end () + }; + + (void) cls; + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make a "bank check" CMD. It checks whether a particular wire transfer to + * the exchange (credit) has been made or not. + * + * @param label the command label. + * @param amount the amount expected to be transferred. + * @param debit_payto the account that gave money. + * @param credit_payto the account that received money. + * @param reserve_pub_ref command that provides the reserve public key to expect + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_bank_admin_transfer + (const char *label, + const char *amount, + const char *debit_payto, + const char *credit_payto, + const char *reserve_pub_ref) +{ + struct BankAdminCheckState *bcs; + + bcs = GNUNET_new (struct BankAdminCheckState); + bcs->amount = amount; + bcs->debit_payto = debit_payto; + bcs->credit_payto = credit_payto; + bcs->reserve_pub_ref = reserve_pub_ref; + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = bcs, + .run = &check_bank_admin_transfer_run, + .cleanup = &check_bank_admin_transfer_cleanup, + .traits = &check_bank_admin_transfer_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_bank_check.c b/src/testing/testing_api_cmd_bank_check.c new file mode 100644 index 000000000..9d1f3e8ef --- /dev/null +++ b/src/testing/testing_api_cmd_bank_check.c @@ -0,0 +1,305 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_bank_check.c + * @brief command to check if a particular wire transfer took + * place. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" + + +/** + * State for a "bank check" CMD. + */ +struct BankCheckState +{ + + /** + * Base URL of the exchange supposed to be + * involved in the bank transaction. + */ + const char *exchange_base_url; + + /** + * Expected transferred amount. + */ + const char *amount; + + /** + * Expected debit bank account. + */ + const char *debit_payto; + + /** + * Expected credit bank account. + */ + const char *credit_payto; + + /** + * Binary form of the wire transfer subject. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Reference to a CMD that provides all the data + * needed to issue the bank check. If NULL, that data + * must exist here in the state. + */ + const char *deposit_reference; +}; + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +check_bank_transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct BankCheckState *bcs = cls; + struct TALER_Amount amount; + char *debit_account; + char *credit_account; + const char *exchange_base_url; + const char *debit_payto; + const char *credit_payto; + + if (NULL == bcs->deposit_reference) + { + TALER_LOG_INFO ("Deposit reference NOT given\n"); + debit_payto = bcs->debit_payto; + credit_payto = bcs->credit_payto; + exchange_base_url = bcs->exchange_base_url; + + if (GNUNET_OK != + TALER_string_to_amount (bcs->amount, + &amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + bcs->amount, + is->ip); + TALER_TESTING_interpreter_fail (is); + return; + } + } + else + { + const struct TALER_TESTING_Command *deposit_cmd; + const struct TALER_Amount *amount_ptr; + + TALER_LOG_INFO ("`%s' uses reference (%s/%p)\n", + TALER_TESTING_interpreter_get_current_label + (is), + bcs->deposit_reference, + bcs->deposit_reference); + deposit_cmd + = TALER_TESTING_interpreter_lookup_command (is, + bcs->deposit_reference); + if (NULL == deposit_cmd) + TALER_TESTING_FAIL (is); + if ( (GNUNET_OK != + TALER_TESTING_get_trait_amount_obj (deposit_cmd, + 0, + &amount_ptr)) || + (GNUNET_OK != + TALER_TESTING_get_trait_payto (deposit_cmd, + TALER_TESTING_PT_DEBIT, + &debit_payto)) || + (GNUNET_OK != + TALER_TESTING_get_trait_payto (deposit_cmd, + TALER_TESTING_PT_CREDIT, + &credit_payto)) || + (GNUNET_OK != + TALER_TESTING_get_trait_url (deposit_cmd, + TALER_TESTING_UT_EXCHANGE_BASE_URL, + &exchange_base_url)) ) + TALER_TESTING_FAIL (is); + amount = *amount_ptr; + } + + + debit_account = TALER_xtalerbank_account_from_payto (debit_payto); + credit_account = TALER_xtalerbank_account_from_payto (credit_payto); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "converted debit_payto (%s) to debit_account (%s)\n", + debit_payto, + debit_account); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "converted credit_payto (%s) to credit_account (%s)\n", + credit_payto, + credit_account); + + if (GNUNET_OK != + TALER_FAKEBANK_check_debit (is->fakebank, + &amount, + debit_account, + credit_account, + exchange_base_url, + &bcs->wtid)) + { + GNUNET_break (0); + GNUNET_free (credit_account); + GNUNET_free (debit_account); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_free (credit_account); + GNUNET_free (debit_account); + TALER_TESTING_interpreter_next (is); +} + + +/** + * Free the state of a "bank check" CMD. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +check_bank_transfer_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct BankCheckState *bcs = cls; + + GNUNET_free (bcs); +} + + +/** + * Offer internal data from a "bank check" CMD state. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +check_bank_transfer_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct BankCheckState *bcs = cls; + struct TALER_WireTransferIdentifierRawP *wtid_ptr = &bcs->wtid; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_wtid (0, + wtid_ptr), + TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, + bcs->exchange_base_url), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make a "bank check" CMD. It checks whether a + * particular wire transfer has been made or not. + * + * @param label the command label. + * @param exchange_base_url base url of the exchange involved in + * the wire transfer. + * @param amount the amount expected to be transferred. + * @param debit_payto the account that gave money. + * @param credit_payto the account that received money. + * + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_bank_transfer (const char *label, + const char *exchange_base_url, + const char *amount, + const char *debit_payto, + const char *credit_payto) +{ + struct BankCheckState *bcs; + + bcs = GNUNET_new (struct BankCheckState); + bcs->exchange_base_url = exchange_base_url; + bcs->amount = amount; + bcs->debit_payto = debit_payto; + bcs->credit_payto = credit_payto; + bcs->deposit_reference = NULL; + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = bcs, + .run = &check_bank_transfer_run, + .cleanup = &check_bank_transfer_cleanup, + .traits = &check_bank_transfer_traits + }; + + return cmd; + } +} + + +/** + * Define a "bank check" CMD that takes the input + * data from another CMD that offers it. + * + * @param label command label. + * @param deposit_reference reference to a CMD that is + * able to provide the "check bank transfer" operation + * input data. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_bank_transfer_with_ref + (const char *label, + const char *deposit_reference) +{ + struct BankCheckState *bcs; + + bcs = GNUNET_new (struct BankCheckState); + bcs->deposit_reference = deposit_reference; + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = bcs, + .run = &check_bank_transfer_run, + .cleanup = &check_bank_transfer_cleanup, + .traits = &check_bank_transfer_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_bank_check_empty.c b/src/testing/testing_api_cmd_bank_check_empty.c new file mode 100644 index 000000000..a26fd9bb1 --- /dev/null +++ b/src/testing/testing_api_cmd_bank_check_empty.c @@ -0,0 +1,102 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_bank_check_empty.c + * @brief command to check if a particular wire transfer took + * place. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" + + +/** + * Cleanup the state, only defined to respect the API. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +check_bank_empty_cleanup + (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + return; +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +check_bank_empty_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Some commands (notably "bank history") could randomly + * look for traits; this way makes sure we don't segfault. + */ +static int +check_bank_empty_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + return GNUNET_SYSERR; +} + + +/** + * Checks wheter all the wire transfers got "checked" + * by the "bank check" CMD. + * + * @param label command label. + * + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_bank_empty (const char *label) +{ + struct TALER_TESTING_Command cmd = { + .label = label, + .run = &check_bank_empty_run, + .cleanup = &check_bank_empty_cleanup, + .traits = &check_bank_empty_traits + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_bank_history_credit.c b/src/testing/testing_api_cmd_bank_history_credit.c new file mode 100644 index 000000000..8fb16fc6f --- /dev/null +++ b/src/testing/testing_api_cmd_bank_history_credit.c @@ -0,0 +1,599 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_bank_history_credit.c + * @brief command to check the /history/incoming API from the bank. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_exchange_service.h" +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" + + +/** + * Item in the transaction history, as reconstructed from the + * command history. + */ +struct History +{ + + /** + * Wire details. + */ + struct TALER_BANK_CreditDetails details; + + /** + * Serial ID of the wire transfer. + */ + uint64_t row_id; + + /** + * URL to free. + */ + char *url; +}; + + +/** + * State for a "history" CMD. + */ +struct HistoryState +{ + /** + * Base URL of the account offering the "history" operation. + */ + char *account_url; + + /** + * Reference to command defining the + * first row number we want in the result. + */ + const char *start_row_reference; + + /** + * How many rows we want in the result, _at most_, + * and ascending/descending. + */ + long long num_results; + + /** + * Handle to a pending "history" operation. + */ + struct TALER_BANK_CreditHistoryHandle *hh; + + /** + * Authentication data for the operation. + */ + struct TALER_BANK_AuthenticationData auth; + + /** + * Expected number of results (= rows). + */ + uint64_t results_obtained; + + /** + * Set to GNUNET_YES if the callback detects something + * unexpected. + */ + int failed; + + /** + * Expected history. + */ + struct History *h; + + /** + * Length of @e h + */ + unsigned int total; + +}; + + +/** + * Offer internal data to other commands. + * + * @param cls closure. + * @param[out] ret set to the wanted data. + * @param trait name of the trait. + * @param index index number of the traits to be returned. + * + * @return #GNUNET_OK on success + */ +static int +history_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + (void) cls; + (void) ret; + (void) trait; + (void) index; + /* Must define this function because some callbacks + * look for certain traits on _all_ the commands. */ + return GNUNET_SYSERR; +} + + +/** + * Log which history we expected. Called when an error occurs. + * + * @param h what we expected. + * @param h_len number of entries in @a h. + * @param off position of the missmatch. + */ +static void +print_expected (struct History *h, + unsigned int h_len, + unsigned int off) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Transaction history (credit) mismatch at position %u/%u\n", + off, + h_len); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected history:\n"); + for (unsigned int i = 0; icommands[is->ip].cls; + unsigned int total; + unsigned int pos; + struct History *h; + const struct TALER_TESTING_Command *add_incoming_cmd; + int inc; + unsigned int start; + unsigned int end; + + /* @var turns GNUNET_YES whenever either no 'start' value was + * given for the history query, or the given value is found + * in the list of all the CMDs. */// + int ok; + const uint64_t *row_id_start = NULL; + + if (NULL != hs->start_row_reference) + { + TALER_LOG_INFO ("`%s': start row given via reference `%s'\n", + TALER_TESTING_interpreter_get_current_label (is), + hs->start_row_reference); + add_incoming_cmd + = TALER_TESTING_interpreter_lookup_command (is, + hs->start_row_reference); + GNUNET_assert (NULL != add_incoming_cmd); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_uint64 (add_incoming_cmd, + 0, + &row_id_start)); + } + + GNUNET_assert (0 != hs->num_results); + if (0 == is->ip) + { + TALER_LOG_DEBUG ("Checking history at FIRST transaction (EMPTY)\n"); + *rh = NULL; + return 0; + } + + if (hs->num_results > 0) + { + inc = 1; /* _inc_rement */ + start = 0; + end = is->ip - 1; + } + else + { + inc = -1; + start = is->ip - 1; + end = 0; + } + + ok = GNUNET_NO; + if (NULL == row_id_start) + ok = GNUNET_YES; + h = NULL; + total = 0; + GNUNET_array_grow (h, + total, + 4); + pos = 0; + for (unsigned int off = start; off != end + inc; off += inc) + { + const struct TALER_TESTING_Command *cmd = &is->commands[off]; + const uint64_t *row_id; + const char *credit_account; + const char *debit_account; + const struct TALER_Amount *amount; + const struct TALER_ReservePublicKeyP *reserve_pub; + const char *exchange_credit_url; + + /* The following command allows us to skip over those CMDs + * that do not offer a "row_id" trait. Such skipped CMDs are + * not interesting for building a history. */// + if ( (GNUNET_OK != + TALER_TESTING_get_trait_bank_row (cmd, + &row_id)) || + (GNUNET_OK != + TALER_TESTING_get_trait_payto (cmd, + TALER_TESTING_PT_CREDIT, + &credit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_payto (cmd, + TALER_TESTING_PT_DEBIT, + &debit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_amount_obj (cmd, + 0, + &amount)) || + (GNUNET_OK != + TALER_TESTING_get_trait_reserve_pub (cmd, + 0, + &reserve_pub)) || + (GNUNET_OK != + TALER_TESTING_get_trait_url (cmd, + TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL, + &exchange_credit_url)) ) + continue; /* not an interesting event */ + /* Seek "/history/incoming" starting row. */ + if ( (NULL != row_id_start) && + (*row_id_start == *row_id) && + (GNUNET_NO == ok) ) + { + /* Until here, nothing counted. */ + ok = GNUNET_YES; + continue; + } + /* when 'start' was _not_ given, then ok == GNUNET_YES */ + if (GNUNET_NO == ok) + continue; /* skip until we find the marker */ + if (0 != strcasecmp (hs->account_url, + exchange_credit_url)) + continue; /* account missmatch */ + if (total >= GNUNET_MAX (hs->num_results, + -hs->num_results) ) + { + TALER_LOG_DEBUG ("Hit history limit\n"); + break; + } + TALER_LOG_INFO ("Found history: %s->%s for account %s\n", + debit_account, + credit_account, + hs->account_url); + /* found matching record, make sure we have room */ + if (pos == total) + GNUNET_array_grow (h, + total, + pos * 2); + h[pos].url = GNUNET_strdup (debit_account); + h[pos].details.debit_account_url = h[pos].url; + h[pos].details.amount = *amount; + h[pos].row_id = *row_id; + h[pos].details.reserve_pub = *reserve_pub; + h[pos].details.credit_account_url = exchange_credit_url; + pos++; + } + GNUNET_assert (GNUNET_YES == ok); + GNUNET_array_grow (h, + total, + pos); + if (0 == pos) + TALER_LOG_DEBUG ("Empty credit history computed\n"); + *rh = h; + return total; +} + + +/** + * Check that the "/history/incoming" response matches the + * CMD whose offset in the list of CMDs is @a off. + * + * @param is the interpreter state. + * @param h expected history (array) + * @param total length of @a h + * @param off the offset (of the CMD list) where the command + * to check is. + * @param details the expected transaction details. + * @return #GNUNET_OK if the transaction is what we expect. + */ +static int +check_result (struct TALER_TESTING_Interpreter *is, + struct History *h, + unsigned int total, + unsigned int off, + const struct TALER_BANK_CreditDetails *details) +{ + if (off >= total) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Test says history has at most %u" + " results, but got result #%u to check\n", + total, + off); + print_expected (h, + total, + off); + return GNUNET_SYSERR; + } + if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub, + &details->reserve_pub)) || + (0 != TALER_amount_cmp (&h[off].details.amount, + &details->amount)) || + (0 != strcasecmp (h[off].details.debit_account_url, + details->debit_account_url)) ) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "expected debit_account_url: %s\n", + details->debit_account_url); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "actual debit_account_url: %s\n", + h[off].details.debit_account_url); + print_expected (h, + total, + off); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * This callback will (1) check that the HTTP response code + * is acceptable and (2) that the history is consistent. The + * consistency is checked by going through all the past CMDs, + * reconstructing then the expected history as of those, and + * finally check it against what the bank returned. + * + * @param cls closure. + * @param http_status HTTP response code, #MHD_HTTP_OK (200) + * for successful status request 0 if the bank's reply is + * bogus (fails to follow the protocol), + * #MHD_HTTP_NO_CONTENT if there are no more results; on + * success the last callback is always of this status + * (even if `abs(num_results)` were already returned). + * @param ec taler status code. + * @param row_id monotonically increasing counter corresponding to + * the transaction. + * @param details details about the wire transfer. + * @param json detailed response from the HTTPD, or NULL if + * reply was not in JSON. + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration + */ +static int +history_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t row_id, + const struct TALER_BANK_CreditDetails *details, + const json_t *json) +{ + struct TALER_TESTING_Interpreter *is = cls; + struct HistoryState *hs = is->commands[is->ip].cls; + + (void) row_id; + if (NULL == details) + { + hs->hh = NULL; + if ( (hs->results_obtained != hs->total) || + (GNUNET_YES == hs->failed) || + (MHD_HTTP_NO_CONTENT != http_status) ) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected history of length %u, got %llu;" + " HTTP status code: %u/%d, failed: %d\n", + hs->total, + (unsigned long long) hs->results_obtained, + http_status, + (int) ec, + hs->failed); + print_expected (hs->h, + hs->total, + UINT_MAX); + TALER_TESTING_interpreter_fail (is); + return GNUNET_SYSERR; + } + TALER_TESTING_interpreter_next (is); + return GNUNET_OK; + } + if (MHD_HTTP_OK != http_status) + { + hs->hh = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unwanted response code from /history/incoming: %u\n", + http_status); + TALER_TESTING_interpreter_fail (is); + return GNUNET_SYSERR; + } + + /* check current element */ + if (GNUNET_OK != check_result (is, + hs->h, + hs->total, + hs->results_obtained, + details)) + { + char *acc; + + GNUNET_break (0); + acc = json_dumps (json, + JSON_COMPACT); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Result %u was `%s'\n", + (unsigned int) hs->results_obtained++, + acc); + if (NULL != acc) + free (acc); + hs->failed = GNUNET_YES; + return GNUNET_SYSERR; + } + hs->results_obtained++; + return GNUNET_OK; +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +history_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct HistoryState *hs = cls; + uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX; + const uint64_t *row_ptr; + + (void) cmd; + /* Get row_id from trait. */ + if (NULL != hs->start_row_reference) + { + const struct TALER_TESTING_Command *history_cmd; + + history_cmd = TALER_TESTING_interpreter_lookup_command + (is, hs->start_row_reference); + + if (NULL == history_cmd) + TALER_TESTING_FAIL (is); + + if (GNUNET_OK != + TALER_TESTING_get_trait_uint64 (history_cmd, + 0, + &row_ptr)) + TALER_TESTING_FAIL (is); + else + row_id = *row_ptr; + TALER_LOG_DEBUG ("row id (from trait) is %llu\n", + (unsigned long long) row_id); + } + hs->total = build_history (is, + &hs->h); + hs->hh = TALER_BANK_credit_history (is->ctx, + &hs->auth, + row_id, + hs->num_results, + &history_cb, + is); + GNUNET_assert (NULL != hs->hh); +} + + +/** + * Free the state from a "history" CMD, and possibly cancel + * a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +history_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct HistoryState *hs = cls; + + (void) cmd; + if (NULL != hs->hh) + { + TALER_LOG_WARNING ("/history/incoming did not complete\n"); + TALER_BANK_credit_history_cancel (hs->hh); + } + GNUNET_free (hs->account_url); + for (unsigned int off = 0; offtotal; off++) + GNUNET_free (hs->h[off].url); + GNUNET_free_non_null (hs->h); + GNUNET_free (hs); +} + + +/** + * Make a "history" CMD. + * + * @param label command label. + * @param auth authentication data to talk with the wire gateway + * @param start_row_reference reference to a command that can + * offer a row identifier, to be used as the starting row + * to accept in the result. + * @param num_results how many rows we want in the result. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_bank_credits (const char *label, + const struct + TALER_BANK_AuthenticationData *auth, + const char *start_row_reference, + long long num_results) +{ + struct HistoryState *hs; + + hs = GNUNET_new (struct HistoryState); + hs->account_url = GNUNET_strdup (auth->wire_gateway_url); + hs->start_row_reference = start_row_reference; + hs->num_results = num_results; + hs->auth = *auth; + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = hs, + .run = &history_run, + .cleanup = &history_cleanup, + .traits = &history_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_credit_history.c */ diff --git a/src/testing/testing_api_cmd_bank_history_debit.c b/src/testing/testing_api_cmd_bank_history_debit.c new file mode 100644 index 000000000..dea6bee95 --- /dev/null +++ b/src/testing/testing_api_cmd_bank_history_debit.c @@ -0,0 +1,602 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_bank_history_debit.c + * @brief command to check the /history/outgoing API from the bank. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_exchange_service.h" +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" + +/** + * Item in the transaction history, as reconstructed from the + * command history. + */ +struct History +{ + + /** + * Wire details. + */ + struct TALER_BANK_DebitDetails details; + + /** + * Serial ID of the wire transfer. + */ + uint64_t row_id; + + /** + * URL to free. + */ + char *c_url; + + /** + * URL to free. + */ + char *d_url; +}; + + +/** + * State for a "history" CMD. + */ +struct HistoryState +{ + /** + * Base URL of the account offering the "history" operation. + */ + const char *account_url; + + /** + * Reference to command defining the + * first row number we want in the result. + */ + const char *start_row_reference; + + /** + * How many rows we want in the result, _at most_, + * and ascending/descending. + */ + long long num_results; + + /** + * Login data to use to authenticate. + */ + struct TALER_BANK_AuthenticationData auth; + + /** + * Handle to a pending "history" operation. + */ + struct TALER_BANK_DebitHistoryHandle *hh; + + /** + * Expected number of results (= rows). + */ + uint64_t results_obtained; + + /** + * Set to #GNUNET_YES if the callback detects something + * unexpected. + */ + int failed; + + /** + * Expected history. + */ + struct History *h; + + /** + * Length of @e h + */ + unsigned int total; + +}; + + +/** + * Offer internal data to other commands. + * + * @param cls closure. + * @param[out] ret set to the wanted data. + * @param trait name of the trait. + * @param index index number of the traits to be returned. + * + * @return #GNUNET_OK on success + */ +static int +history_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + (void) cls; + (void) ret; + (void) trait; + (void) index; + /* Must define this function because some callbacks + * look for certain traits on _all_ the commands. */ + return GNUNET_SYSERR; +} + + +/** + * Log which history we expected. Called when an error occurs. + * + * @param h what we expected. + * @param h_len number of entries in @a h. + * @param off position of the missmatch. + */ +static void +print_expected (struct History *h, + unsigned int h_len, + unsigned int off) +{ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Transaction history (debit) mismatch at position %u/%u\n", + off, + h_len); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected history:\n"); + for (unsigned int i = 0; icommands[is->ip].cls; + unsigned int total; + unsigned int pos; + struct History *h; + const struct TALER_TESTING_Command *add_incoming_cmd; + int inc; + int start; + int end; + /* #GNUNET_YES whenever either no 'start' value was given for the history + * query, or the given value is found in the list of all the CMDs. */ + int ok; + const uint64_t *row_id_start = NULL; + + if (NULL != hs->start_row_reference) + { + TALER_LOG_INFO + ("`%s': start row given via reference `%s'\n", + TALER_TESTING_interpreter_get_current_label (is), + hs->start_row_reference); + add_incoming_cmd = TALER_TESTING_interpreter_lookup_command + (is, hs->start_row_reference); + GNUNET_assert (NULL != add_incoming_cmd); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_uint64 (add_incoming_cmd, + 0, + &row_id_start)); + } + + GNUNET_assert (0 != hs->num_results); + if (0 == is->ip) + { + TALER_LOG_DEBUG ("Checking history at first CMD..\n"); + *rh = NULL; + return 0; + } + + /* AKA 'delta' */ + if (hs->num_results > 0) + { + inc = 1; /* _inc_rement: go forwards */ + start = 0; + end = is->ip; + } + else + { + inc = -1; /* decrement: we go backwards */ + start = is->ip - 1; + end = -1; /* range is exclusive, do look at 0! */ + } + + ok = GNUNET_NO; + if (NULL == row_id_start) + ok = GNUNET_YES; + h = NULL; + total = 0; + GNUNET_array_grow (h, + total, + 4); + pos = 0; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Checking commands %u to %u for debit history\n", + start, + end); + for (int off = start; off != end; off += inc) + { + const struct TALER_TESTING_Command *cmd = &is->commands[off]; + const uint64_t *row_id; + const char *debit_account; + const char *credit_account; + const struct TALER_Amount *amount; + const struct TALER_WireTransferIdentifierRawP *wtid; + const char *exchange_base_url; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Checking if command %s is relevant for debit history\n", + cmd->label); + if ( (GNUNET_OK != + TALER_TESTING_get_trait_bank_row (cmd, + &row_id)) || + (GNUNET_OK != + TALER_TESTING_get_trait_payto (cmd, + TALER_TESTING_PT_DEBIT, + &debit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_payto (cmd, + TALER_TESTING_PT_CREDIT, + &credit_account)) || + (GNUNET_OK != + TALER_TESTING_get_trait_amount_obj (cmd, + 0, + &amount)) || + (GNUNET_OK != + TALER_TESTING_get_trait_wtid (cmd, + 0, + &wtid)) || + (GNUNET_OK != + TALER_TESTING_get_trait_url (cmd, + TALER_TESTING_UT_EXCHANGE_BASE_URL, + &exchange_base_url)) ) + continue; /* not an event we care about */ + /* Seek "/history/outgoing" starting row. */ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Command %s is relevant for debit history!\n", + cmd->label); + if ( (NULL != row_id_start) && + (*row_id_start == *row_id) && + (GNUNET_NO == ok) ) + { + /* Until here, nothing counted. */ + ok = GNUNET_YES; + continue; + } + /* when 'start' was _not_ given, then ok == GNUNET_YES */ + if (GNUNET_NO == ok) + continue; /* skip until we find the marker */ + if (total >= GNUNET_MAX (hs->num_results, + -hs->num_results) ) + { + TALER_LOG_DEBUG ("Hit history limit\n"); + break; + } + TALER_LOG_INFO ("Found history: %s->%s for account %s\n", + debit_account, + credit_account, + hs->account_url); + /* found matching record, make sure we have room */ + if (pos == total) + GNUNET_array_grow (h, + total, + pos * 2); + h[pos].c_url = GNUNET_strdup (credit_account); + h[pos].d_url = GNUNET_strdup (debit_account); + h[pos].details.credit_account_url = h[pos].c_url; + h[pos].details.debit_account_url = h[pos].d_url; + h[pos].details.amount = *amount; + h[pos].row_id = *row_id; + h[pos].details.wtid = *wtid; + h[pos].details.exchange_base_url = exchange_base_url; + pos++; + } + GNUNET_assert (GNUNET_YES == ok); + GNUNET_array_grow (h, + total, + pos); + if (0 == pos) + TALER_LOG_DEBUG ("Empty debit history computed\n"); + *rh = h; + return total; +} + + +/** + * Check that the "/history/outgoing" response matches the + * CMD whose offset in the list of CMDs is @a off. + * + * @param is the interpreter state. + * @param h expected history + * @param total number of entries in @a h + * @param off the offset (of the CMD list) where the command + * to check is. + * @param details the expected transaction details. + * @return #GNUNET_OK if the transaction is what we expect. + */ +static int +check_result (struct TALER_TESTING_Interpreter *is, + struct History *h, + uint64_t total, + unsigned int off, + const struct TALER_BANK_DebitDetails *details) +{ + if (off >= total) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Test says history has at most %u" + " results, but got result #%u to check\n", + (unsigned int) total, + off); + print_expected (h, + total, + off); + return GNUNET_SYSERR; + } + if ( (0 != GNUNET_memcmp (&h[off].details.wtid, + &details->wtid)) || + (0 != TALER_amount_cmp (&h[off].details.amount, + &details->amount)) || + (0 != strcasecmp (h[off].details.credit_account_url, + details->credit_account_url)) ) + { + GNUNET_break (0); + print_expected (h, + total, + off); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * This callback will (1) check that the HTTP response code + * is acceptable and (2) that the history is consistent. The + * consistency is checked by going through all the past CMDs, + * reconstructing then the expected history as of those, and + * finally check it against what the bank returned. + * + * @param cls closure. + * @param http_status HTTP response code, #MHD_HTTP_OK (200) + * for successful status request 0 if the bank's reply is + * bogus (fails to follow the protocol), + * #MHD_HTTP_NO_CONTENT if there are no more results; on + * success the last callback is always of this status + * (even if `abs(num_results)` were already returned). + * @param ec taler status code. + * @param row_id monotonically increasing counter corresponding to + * the transaction. + * @param details details about the wire transfer. + * @param json detailed response from the HTTPD, or NULL if + * reply was not in JSON. + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration + */ +static int +history_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t row_id, + const struct TALER_BANK_DebitDetails *details, + const json_t *json) +{ + struct TALER_TESTING_Interpreter *is = cls; + struct HistoryState *hs = is->commands[is->ip].cls; + + (void) row_id; + if (NULL == details) + { + hs->hh = NULL; + if ( (hs->results_obtained != hs->total) || + (GNUNET_YES == hs->failed) || + (MHD_HTTP_NO_CONTENT != http_status) ) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected history of length %u, got %llu;" + " HTTP status code: %u/%d, failed: %d\n", + hs->total, + (unsigned long long) hs->results_obtained, + http_status, + (int) ec, + hs->failed); + print_expected (hs->h, + hs->total, + UINT_MAX); + TALER_TESTING_interpreter_fail (is); + return GNUNET_SYSERR; + } + TALER_TESTING_interpreter_next (is); + return GNUNET_OK; + } + if (MHD_HTTP_OK != http_status) + { + hs->hh = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unwanted response code from /history/outgoing: %u\n", + http_status); + TALER_TESTING_interpreter_fail (is); + return GNUNET_SYSERR; + } + + /* check current element */ + if (GNUNET_OK != check_result (is, + hs->h, + hs->total, + hs->results_obtained, + details)) + { + char *acc; + + GNUNET_break (0); + acc = json_dumps (json, + JSON_COMPACT); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Result %u was `%s'\n", + (unsigned int) hs->results_obtained++, + acc); + if (NULL != acc) + free (acc); + hs->failed = GNUNET_YES; + return GNUNET_SYSERR; + } + hs->results_obtained++; + return GNUNET_OK; +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +history_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct HistoryState *hs = cls; + uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX; + const uint64_t *row_ptr; + + (void) cmd; + /* Get row_id from trait. */ + if (NULL != hs->start_row_reference) + { + const struct TALER_TESTING_Command *history_cmd; + + history_cmd + = TALER_TESTING_interpreter_lookup_command (is, + hs->start_row_reference); + + if (NULL == history_cmd) + TALER_TESTING_FAIL (is); + if (GNUNET_OK != + TALER_TESTING_get_trait_uint64 (history_cmd, + 0, + &row_ptr)) + TALER_TESTING_FAIL (is); + else + row_id = *row_ptr; + TALER_LOG_DEBUG ("row id (from trait) is %llu\n", + (unsigned long long) row_id); + } + hs->total = build_history (is, &hs->h); + hs->hh = TALER_BANK_debit_history (is->ctx, + &hs->auth, + row_id, + hs->num_results, + &history_cb, + is); + GNUNET_assert (NULL != hs->hh); +} + + +/** + * Free the state from a "history" CMD, and possibly cancel + * a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +history_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct HistoryState *hs = cls; + + (void) cmd; + if (NULL != hs->hh) + { + TALER_LOG_WARNING ("/history/outgoing did not complete\n"); + TALER_BANK_debit_history_cancel (hs->hh); + } + for (unsigned int off = 0; offtotal; off++) + { + GNUNET_free (hs->h[off].c_url); + GNUNET_free (hs->h[off].d_url); + } + GNUNET_free_non_null (hs->h); + GNUNET_free (hs); +} + + +/** + * Make a "history" CMD. + * + * @param label command label. + * @param auth login data to use + * @param start_row_reference reference to a command that can + * offer a row identifier, to be used as the starting row + * to accept in the result. + * @param num_results how many rows we want in the result. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_bank_debits (const char *label, + const struct TALER_BANK_AuthenticationData *auth, + const char *start_row_reference, + long long num_results) +{ + struct HistoryState *hs; + + hs = GNUNET_new (struct HistoryState); + hs->account_url = auth->wire_gateway_url; + hs->start_row_reference = start_row_reference; + hs->num_results = num_results; + hs->auth = *auth; + + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = hs, + .run = &history_run, + .cleanup = &history_cleanup, + .traits = &history_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_bank_history_debit.c */ diff --git a/src/testing/testing_api_cmd_bank_transfer.c b/src/testing/testing_api_cmd_bank_transfer.c new file mode 100644 index 000000000..6aa926df8 --- /dev/null +++ b/src/testing/testing_api_cmd_bank_transfer.c @@ -0,0 +1,405 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_bank_transfer.c + * @brief implementation of a bank /transfer command + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "backoff.h" +#include "taler_json_lib.h" +#include +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "transfer" CMD. + */ +struct TransferState +{ + + /** + * Wire transfer amount. + */ + struct TALER_Amount amount; + + /** + * Base URL of the debit account. + */ + const char *account_debit_url; + + /** + * Money receiver payto URL. + */ + char *payto_debit_account; + + /** + * Money receiver account URL. + */ + const char *payto_credit_account; + + /** + * Username to use for authentication. + */ + struct TALER_BANK_AuthenticationData auth; + + /** + * Base URL of the exchange. + */ + const char *exchange_base_url; + + /** + * Wire transfer identifier to use. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Handle to the pending request at the fakebank. + */ + struct TALER_BANK_WireExecuteHandle *weh; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Set to the wire transfer's unique ID. + */ + uint64_t serial_id; + + /** + * Timestamp of the transaction (as returned from the bank). + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Configuration filename. Used to get the tip reserve key + * filename (used to obtain a public key to write in the + * transfer subject). + */ + const char *config_filename; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Was this command modified via + * #TALER_TESTING_cmd_admin_add_incoming_with_retry to + * enable retries? + */ + int do_retry; +}; + + +/** + * Run the "transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #transfer_run. + * + * @param cls a `struct TransferState` + */ +static void +do_retry (void *cls) +{ + struct TransferState *fts = cls; + + fts->retry_task = NULL; + transfer_run (fts, + NULL, + fts->is); +} + + +/** + * This callback will process the fakebank response to the wire + * transfer. It just checks whether the HTTP response code is + * acceptable. + * + * @param cls closure with the interpreter state + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for + * successful status request; 0 if the exchange's reply is + * bogus (fails to follow the protocol) + * @param ec taler-specific error code, #TALER_EC_NONE on success + * @param serial_id unique ID of the wire transfer + * @param timestamp time stamp of the transaction made. + */ +static void +confirmation_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t serial_id, + struct GNUNET_TIME_Absolute timestamp) +{ + struct TransferState *fts = cls; + struct TALER_TESTING_Interpreter *is = fts->is; + + fts->weh = NULL; + if (MHD_HTTP_OK != http_status) + { + if (GNUNET_YES == fts->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying transfer failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + fts->backoff = GNUNET_TIME_UNIT_ZERO; + else + fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); + fts->retry_task = GNUNET_SCHEDULER_add_delayed + (fts->backoff, + &do_retry, + fts); + return; + } + } + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Fakebank returned HTTP status %u/%d\n", + http_status, + (int) ec); + TALER_TESTING_interpreter_fail (is); + return; + } + + fts->serial_id = serial_id; + fts->timestamp = timestamp; + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the "transfer" CMD. + * + * @param cls closure. + * @param cmd CMD being run. + * @param is interpreter state. + */ +static void +transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct TransferState *fts = cls; + void *buf; + size_t buf_size; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Transfer of %s from %s to %s\n", + TALER_amount2s (&fts->amount), + fts->account_debit_url, + fts->payto_credit_account); + TALER_BANK_prepare_wire_transfer (fts->payto_credit_account, + &fts->amount, + fts->exchange_base_url, + &fts->wtid, + &buf, + &buf_size); + fts->is = is; + fts->weh + = TALER_BANK_execute_wire_transfer + (TALER_TESTING_interpreter_get_context (is), + &fts->auth, + buf, + buf_size, + &confirmation_cb, + fts); + GNUNET_free (buf); + if (NULL == fts->weh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "fakebank transfer" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure + * @param cmd current CMD being cleaned up. + */ +static void +transfer_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct TransferState *fts = cls; + + if (NULL != fts->weh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %s did not complete\n", + cmd->label); + TALER_BANK_execute_wire_transfer_cancel (fts->weh); + fts->weh = NULL; + } + if (NULL != fts->retry_task) + { + GNUNET_SCHEDULER_cancel (fts->retry_task); + fts->retry_task = NULL; + } + GNUNET_free (fts->payto_debit_account); + GNUNET_free (fts); +} + + +/** + * Offer internal data from a "fakebank transfer" CMD to other + * commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +transfer_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct TransferState *fts = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, + fts->exchange_base_url), + TALER_TESTING_make_trait_bank_row (&fts->serial_id), + TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT, + fts->payto_credit_account), + TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT, + fts->payto_debit_account), + TALER_TESTING_make_trait_amount_obj (0, &fts->amount), + TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), + TALER_TESTING_make_trait_wtid (0, + &fts->wtid), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create transfer command. + * + * @param label command label. + * @param amount amount to transfer. + * @param auth authentication data to use + * @param payto_debit_account which account sends money. + * @param payto_credit_account which account receives money. + * @param wtid wire transfer identifier to use + * @param exchange_base_url exchange URL to use + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_transfer (const char *label, + const char *amount, + const struct TALER_BANK_AuthenticationData *auth, + const char *payto_debit_account, + const char *payto_credit_account, + const struct TALER_WireTransferIdentifierRawP *wtid, + const char *exchange_base_url) +{ + struct TransferState *fts; + + fts = GNUNET_new (struct TransferState); + fts->account_debit_url = auth->wire_gateway_url; + fts->exchange_base_url = exchange_base_url; + fts->payto_debit_account = GNUNET_strdup (payto_debit_account); + fts->payto_credit_account = payto_credit_account; + fts->auth = *auth; + fts->wtid = *wtid; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &fts->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + amount, + label); + GNUNET_assert (0); + } + + { + struct TALER_TESTING_Command cmd = { + .cls = fts, + .label = label, + .run = &transfer_run, + .cleanup = &transfer_cleanup, + .traits = &transfer_traits + }; + + return cmd; + } +} + + +/** + * Modify a transfer command to enable retries when the reserve is not yet + * full or we get other transient errors from the bank. + * + * @param cmd a fakebank transfer command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_transfer_retry (struct TALER_TESTING_Command cmd) +{ + struct TransferState *fts; + + GNUNET_assert (&transfer_run == cmd.run); + fts = cmd.cls; + fts->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_api_cmd_transfer.c */ diff --git a/src/testing/testing_api_cmd_batch.c b/src/testing/testing_api_cmd_batch.c new file mode 100644 index 000000000..fe7c19db2 --- /dev/null +++ b/src/testing/testing_api_cmd_batch.c @@ -0,0 +1,227 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_batch.c + * @brief Implement batch-execution of CMDs. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * State for a "batch" CMD. + */ +struct BatchState +{ + /** + * CMDs batch. + */ + struct TALER_TESTING_Command *batch; + + /** + * Internal command pointer. + */ + unsigned int batch_ip; +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command being executed. + * @param is the interpreter state. + */ +static void +batch_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct BatchState *bs = cls; + + if (NULL != bs->batch[bs->batch_ip].label) + TALER_LOG_INFO ("Running batched command: %s\n", + bs->batch[bs->batch_ip].label); + + /* hit end command, leap to next top-level command. */ + if (NULL == bs->batch[bs->batch_ip].label) + { + TALER_LOG_INFO ("Exiting from batch: %s\n", + cmd->label); + TALER_TESTING_interpreter_next (is); + return; + } + + bs->batch[bs->batch_ip].run (bs->batch[bs->batch_ip].cls, + &bs->batch[bs->batch_ip], + is); +} + + +/** + * Cleanup the state from a "reserve status" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +batch_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct BatchState *bs = cls; + + for (unsigned int i = 0; + NULL != bs->batch[i].label; + i++) + bs->batch[i].cleanup (bs->batch[i].cls, + &bs->batch[i]); + GNUNET_free_non_null (bs->batch); + GNUNET_free (bs); +} + + +/** + * Offer internal data from a "batch" CMD, to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +batch_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ +#define CURRENT_CMD_INDEX 0 +#define BATCH_INDEX 1 + + struct BatchState *bs = cls; + + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_cmd + (CURRENT_CMD_INDEX, &bs->batch[bs->batch_ip]), + TALER_TESTING_make_trait_cmd + (BATCH_INDEX, bs->batch), + TALER_TESTING_trait_end () + }; + + /* Always return current command. */ + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create a "batch" command. Such command takes a + * end_CMD-terminated array of CMDs and executed them. + * Once it hits the end CMD, it passes the control + * to the next top-level CMD, regardless of it being + * another batch or ordinary CMD. + * + * @param label the command label. + * @param batch array of CMDs to execute. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_batch (const char *label, + struct TALER_TESTING_Command *batch) +{ + struct BatchState *bs; + unsigned int i; + + bs = GNUNET_new (struct BatchState); + + /* Get number of commands. */ + for (i = 0; NULL != batch[i].label; i++) + /* noop */ + ; + + bs->batch = GNUNET_new_array (i + 1, + struct TALER_TESTING_Command); + memcpy (bs->batch, + batch, + sizeof (struct TALER_TESTING_Command) * i); + { + struct TALER_TESTING_Command cmd = { + .cls = bs, + .label = label, + .run = &batch_run, + .cleanup = &batch_cleanup, + .traits = &batch_traits + }; + + return cmd; + } +} + + +/** + * Advance internal pointer to next command. + * + * @param is interpreter state. + */ +void +TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is) +{ + struct BatchState *bs = is->commands[is->ip].cls; + + if (NULL == bs->batch[bs->batch_ip].label) + { + is->ip++; + return; + } + + bs->batch_ip++; +} + + +/** + * Test if this command is a batch command. + * + * @return false if not, true if it is a batch command + */ +int +TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd) +{ + return cmd->run == &batch_run; +} + + +/** + * Obtain what command the batch is at. + * + * @return cmd current batch command + */ +struct TALER_TESTING_Command * +TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd) +{ + struct BatchState *bs = cmd->cls; + + return &bs->batch[bs->batch_ip]; +} diff --git a/src/testing/testing_api_cmd_check_keys.c b/src/testing/testing_api_cmd_check_keys.c new file mode 100644 index 000000000..6e5c694cf --- /dev/null +++ b/src/testing/testing_api_cmd_check_keys.c @@ -0,0 +1,358 @@ +/* + This file is part of TALER + (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_check_keys.c + * @brief Implementation of "check keys" test command. XXX-NOTE: + * the number of 'expected keys' is NOT the number of the + * downloaded keys, but rather the number of keys that the + * libtalerutil library keeps locally. As for the current + * design, keys are _never_ discarded by the library, + * therefore their (expected) number is monotonically + * ascending. + * + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * State for a "check keys" CMD. + */ +struct CheckKeysState +{ + /** + * This number will instruct the CMD interpreter to + * make sure that /keys was downloaded `generation` times + * _before_ running the very CMD logic. + */ + unsigned int generation; + + /** + * How many denomination keys the exchange is + * supposed to have. + */ + unsigned int num_denom_keys; + + /** + * If this value is GNUNET_YES, then the "cherry + * picking" facility is turned off; whole /keys is + * downloaded. + */ + unsigned int pull_all_keys; + + /** + * If GNUNET_YES, then the user must specify the + * last_denom_issue_date manually. This way, it is possible + * to force whatever X value here (including 0): /keys?last_denom_issue=X. + */ + unsigned int set_last_denom; + + /** + * Value X to set as the URL parameter: + * "/keys?last_denom_issue=X" is used only when `set_last_denom' + * equals GNUNET_YES. + */ + struct GNUNET_TIME_Absolute last_denom_date; + + /** + * If GNUNET_YES, then we'll provide the "/keys" request. + * with the "now" argument. + */ + int with_now; + + /** + * Fake now as passed by the user. + */ + struct GNUNET_TIME_Absolute now; + +}; + + +/** + * Run the "check keys" command. + * + * @param cls closure. + * @param cmd the command currently being executed. + * @param is the interpreter state. + */ +static void +check_keys_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct CheckKeysState *cks = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "cmd `%s' (ip: %u), key generation: %d\n", + cmd->label, + is->ip, + is->key_generation); + + if (is->key_generation < cks->generation) + { + is->working = GNUNET_NO; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Triggering GET /keys, cmd `%s'\n", + cmd->label); + + if (GNUNET_YES == cks->set_last_denom) + { + TALER_LOG_DEBUG ("Forcing last_denom_date URL argument\n"); + TALER_EXCHANGE_set_last_denom (is->exchange, + cks->last_denom_date); + } + + if (GNUNET_YES == cks->with_now) + TALER_EXCHANGE_set_now (is->exchange, + cks->now); + /* Redownload /keys. */ + GNUNET_break + (0 == TALER_EXCHANGE_check_keys_current + (is->exchange, + GNUNET_YES, + cks->pull_all_keys).abs_value_us); + return; + } + +#if 0 + /** + * Not sure this check makes sense: GET /keys is performed on + * a "maybe" basis, so it can get quite hard to track /keys + * request. Rather, this CMD should just check if /keys was + * requested AT LEAST n times before going ahead with checks. + */// + if (is->key_generation > cks->generation) + { + /* We got /keys too often, strange. Fatal. May theoretically + happen if somehow we were really unlucky and /keys expired + "naturally", but obviously with a sane configuration this + should also not be. */ + GNUNET_break (0); + TALER_LOG_ERROR ("Acutal- vs expected key" + " generation: %u vs %u\n", + is->key_generation, + cks->generation); + TALER_TESTING_interpreter_fail (is); + return; + } +#endif + /* "/keys" was updated, let's check they were OK! */ + if (cks->num_denom_keys != is->keys->num_denom_keys) + { + /* Did not get the expected number of denomination keys! */ + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Got %u keys in step %s, expected %u\n", + is->keys->num_denom_keys, + cmd->label, + cks->num_denom_keys); + TALER_TESTING_interpreter_fail (is); + return; + } + + /* Let's unset the fake now before moving on. */ + TALER_EXCHANGE_unset_now (is->exchange); + TALER_TESTING_interpreter_next (is); +} + + +/** + * Cleanup the state. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +check_keys_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct CheckKeysState *cks = cls; + + GNUNET_free (cks); +} + + +/** + * Make a "check keys" command. This type of command + * checks whether the number of denomination keys from + * @a exchange matches @a num_denom_keys. Additionally, + * it lets the user set a last denom issue date to be + * used in the request for /keys. + * + * @param label command label + * @param generation when this command is run, exactly @a + * generation /keys downloads took place. If the number + * of downloads is less than @a generation, the logic will + * first make sure that @a generation downloads are done, + * and _then_ execute the rest of the command. + * @param num_denom_keys expected number of denomination keys. + * @param last_denom_date date to be set in the "last_denom_issue" + * URL parameter of /keys. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_keys_with_last_denom (const char *label, + unsigned int generation, + unsigned int num_denom_keys, + struct GNUNET_TIME_Absolute + last_denom_date) +{ + struct CheckKeysState *cks; + + cks = GNUNET_new (struct CheckKeysState); + cks->generation = generation; + cks->num_denom_keys = num_denom_keys; + cks->set_last_denom = GNUNET_YES; + cks->last_denom_date = last_denom_date; + { + struct TALER_TESTING_Command cmd = { + .cls = cks, + .label = label, + .run = &check_keys_run, + .cleanup = &check_keys_cleanup + }; + + return cmd; + } +} + + +/** + * Make a "check keys" command. This type of command + * checks whether the number of denomination keys from + * @a exchange matches @a num_denom_keys. + * + * @param label command label + * @param generation when this command is run, exactly @a + * generation /keys downloads took place. If the number + * of downloads is less than @a generation, the logic will + * first make sure that @a generation downloads are done, + * and _then_ execute the rest of the command. + * @param num_denom_keys expected number of denomination keys. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_keys (const char *label, + unsigned int generation, + unsigned int num_denom_keys) +{ + struct CheckKeysState *cks; + + cks = GNUNET_new (struct CheckKeysState); + cks->generation = generation; + cks->num_denom_keys = num_denom_keys; + { + struct TALER_TESTING_Command cmd = { + .cls = cks, + .label = label, + .run = &check_keys_run, + .cleanup = &check_keys_cleanup + }; + + return cmd; + } +} + + +/** + * Make a "check keys" command. This type of command + * checks whether the number of denomination keys from + * @a exchange matches @a num_denom_keys. + * + * @param label command label + * @param generation when this command is run, exactly @a + * generation /keys downloads took place. If the number + * of downloads is less than @a generation, the logic will + * first make sure that @a generation downloads are done, + * and _then_ execute the rest of the command. + * @param num_denom_keys expected number of denomination keys. + * @param now timestamp to use when fetching keys + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_keys_with_now (const char *label, + unsigned int generation, + unsigned int num_denom_keys, + struct GNUNET_TIME_Absolute now) +{ + struct CheckKeysState *cks; + + cks = GNUNET_new (struct CheckKeysState); + cks->generation = generation; + cks->num_denom_keys = num_denom_keys; + cks->now = now; + cks->with_now = GNUNET_YES; + + /* Force to NOT cherry pick, otherwise they conflict. */ + cks->pull_all_keys = GNUNET_YES; + { + struct TALER_TESTING_Command cmd = { + .cls = cks, + .label = label, + .run = &check_keys_run, + .cleanup = &check_keys_cleanup + }; + + return cmd; + } +} + + +/** + * Make a "check keys" command that forcedly does NOT cherry pick; + * just redownload the whole /keys. Then checks whether the number + * of denomination keys from @a exchange matches @a num_denom_keys. + * + * @param label command label + * @param generation when this command is run, exactly @a + * generation /keys downloads took place. If the number + * of downloads is less than @a generation, the logic will + * first make sure that @a generation downloads are done, + * and _then_ execute the rest of the command. + * @param num_denom_keys expected number of denomination keys. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label, + unsigned int generation, + unsigned int num_denom_keys) +{ + struct CheckKeysState *cks; + + cks = GNUNET_new (struct CheckKeysState); + cks->generation = generation; + cks->num_denom_keys = num_denom_keys; + cks->pull_all_keys = GNUNET_YES; + { + struct TALER_TESTING_Command cmd = { + .cls = cks, + .label = label, + .run = &check_keys_run, + .cleanup = &check_keys_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_check_keys.c */ diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c new file mode 100644 index 000000000..573c68b9c --- /dev/null +++ b/src/testing/testing_api_cmd_deposit.c @@ -0,0 +1,567 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_deposit.c + * @brief command for testing /deposit. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * State for a "deposit" CMD. + */ +struct DepositState +{ + + /** + * Amount to deposit. + */ + struct TALER_Amount amount; + + /** + * Reference to any command that is able to provide a coin. + */ + const char *coin_reference; + + /** + * If @e coin_reference refers to an operation that generated + * an array of coins, this value determines which coin to pick. + */ + unsigned int coin_index; + + /** + * Wire details of who is depositing -- this would be merchant + * wire details in a normal scenario. + */ + json_t *wire_details; + + /** + * JSON string describing what a proposal is about. + */ + json_t *contract_terms; + + /** + * Refund deadline. Zero for no refunds. + */ + struct GNUNET_TIME_Absolute refund_deadline; + + /** + * Set (by the interpreter) to a fresh private key. This + * key will be used to sign the deposit request. + */ + struct TALER_MerchantPrivateKeyP merchant_priv; + + /** + * Deposit handle while operation is running. + */ + struct TALER_EXCHANGE_DepositHandle *dh; + + /** + * Timestamp of the /deposit operation. + */ + struct GNUNET_TIME_Absolute timestamp; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Should we retry on (transient) failures? + */ + int do_retry; + + /** + * Set to #GNUNET_YES if the /deposit succeeded + * and we now can provide the resulting traits. + */ + int traits_ready; + + /** + * Signing key used by the exchange to sign the + * deposit confirmation. + */ + struct TALER_ExchangePublicKeyP exchange_pub; + + /** + * Signature from the exchange on the + * deposit confirmation. + */ + struct TALER_ExchangeSignatureP exchange_sig; +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +deposit_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #deposit_run. + * + * @param cls a `struct DepositState` + */ +static void +do_retry (void *cls) +{ + struct DepositState *ds = cls; + + ds->retry_task = NULL; + deposit_run (ds, + NULL, + ds->is); +} + + +/** + * Callback to analyze the /deposit response, just used to + * check if the response code is acceptable. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param exchange_sig signature provided by the exchange + * (NULL on errors) + * @param exchange_pub public key of the exchange, + * used for signing the response. + * @param obj raw response from the exchange. + */ +static void +deposit_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const struct TALER_ExchangeSignatureP *exchange_sig, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const json_t *obj) +{ + struct DepositState *ds = cls; + + ds->dh = NULL; + if (ds->expected_response_code != http_status) + { + if (GNUNET_YES == ds->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying deposit failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + ds->backoff = GNUNET_TIME_UNIT_ZERO; + else + ds->backoff = EXCHANGE_LIB_BACKOFF (ds->backoff); + ds->retry_task + = GNUNET_SCHEDULER_add_delayed (ds->backoff, + &do_retry, + ds); + return; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s in %s:%u\n", + http_status, + ds->is->commands[ds->is->ip].label, + __FILE__, + __LINE__); + json_dumpf (obj, stderr, 0); + TALER_TESTING_interpreter_fail (ds->is); + return; + } + if (MHD_HTTP_OK == http_status) + { + ds->traits_ready = GNUNET_YES; + ds->exchange_pub = *exchange_pub; + ds->exchange_sig = *exchange_sig; + } + TALER_TESTING_interpreter_next (ds->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +deposit_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct DepositState *ds = cls; + const struct TALER_TESTING_Command *coin_cmd; + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + struct TALER_CoinSpendPublicKeyP coin_pub; + const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; + const struct TALER_DenominationSignature *denom_pub_sig; + struct TALER_CoinSpendSignatureP coin_sig; + struct GNUNET_TIME_Absolute wire_deadline; + struct GNUNET_CRYPTO_EddsaPrivateKey *merchant_priv; + struct TALER_MerchantPublicKeyP merchant_pub; + struct GNUNET_HashCode h_contract_terms; + + ds->is = is; + GNUNET_assert (ds->coin_reference); + coin_cmd = TALER_TESTING_interpreter_lookup_command + (is, + ds->coin_reference); + if (NULL == coin_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if ( (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (coin_cmd, + ds->coin_index, + &coin_priv)) || + (GNUNET_OK != + TALER_TESTING_get_trait_denom_pub (coin_cmd, + ds->coin_index, + &denom_pub)) || + (GNUNET_OK != + TALER_TESTING_get_trait_denom_sig (coin_cmd, + ds->coin_index, + &denom_pub_sig)) || + (GNUNET_OK != + TALER_JSON_hash (ds->contract_terms, + &h_contract_terms)) ) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin_pub.eddsa_pub); + + merchant_priv = GNUNET_CRYPTO_eddsa_key_create (); + ds->merchant_priv.eddsa_priv = *merchant_priv; + GNUNET_free (merchant_priv); + + if (0 != ds->refund_deadline.abs_value_us) + { + struct GNUNET_TIME_Relative refund_deadline; + + refund_deadline = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline); + wire_deadline = GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_relative_multiply (refund_deadline, 2)); + } + else + { + ds->refund_deadline = ds->timestamp; + wire_deadline = GNUNET_TIME_relative_to_absolute + (GNUNET_TIME_UNIT_ZERO); + } + GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv, + &merchant_pub.eddsa_pub); + + (void) GNUNET_TIME_round_abs (&wire_deadline); + + { + struct TALER_DepositRequestPS dr; + + memset (&dr, 0, sizeof (dr)); + dr.purpose.size = htonl + (sizeof (struct TALER_DepositRequestPS)); + dr.purpose.purpose = htonl + (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); + dr.h_contract_terms = h_contract_terms; + GNUNET_assert (GNUNET_OK == + TALER_JSON_merchant_wire_signature_hash (ds->wire_details, + &dr.h_wire)); + dr.timestamp = GNUNET_TIME_absolute_hton (ds->timestamp); + dr.refund_deadline = GNUNET_TIME_absolute_hton + (ds->refund_deadline); + TALER_amount_hton (&dr.amount_with_fee, + &ds->amount); + TALER_amount_hton (&dr.deposit_fee, + &denom_pub->fee_deposit); + dr.merchant = merchant_pub; + dr.coin_pub = coin_pub; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &dr.purpose, + &coin_sig.eddsa_signature)); + } + ds->dh = TALER_EXCHANGE_deposit (is->exchange, + &ds->amount, + wire_deadline, + ds->wire_details, + &h_contract_terms, + &coin_pub, + denom_pub_sig, + &denom_pub->key, + ds->timestamp, + &merchant_pub, + ds->refund_deadline, + &coin_sig, + &deposit_cb, + ds); + + if (NULL == ds->dh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "deposit" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, must be a `struct DepositState`. + * @param cmd the command which is being cleaned up. + */ +static void +deposit_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct DepositState *ds = cls; + + if (NULL != ds->dh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + ds->is->ip, + cmd->label); + TALER_EXCHANGE_deposit_cancel (ds->dh); + ds->dh = NULL; + } + if (NULL != ds->retry_task) + { + GNUNET_SCHEDULER_cancel (ds->retry_task); + ds->retry_task = NULL; + } + json_decref (ds->wire_details); + json_decref (ds->contract_terms); + GNUNET_free (ds); +} + + +/** + * Offer internal data from a "deposit" CMD, to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * + * @return #GNUNET_OK on success. + */ +static int +deposit_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct DepositState *ds = cls; + const struct TALER_TESTING_Command *coin_cmd; + /* Will point to coin cmd internals. */ + const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv; + + coin_cmd + = TALER_TESTING_interpreter_lookup_command (ds->is, + ds->coin_reference); + if (NULL == coin_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ds->is); + return GNUNET_NO; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (coin_cmd, + ds->coin_index, + &coin_spent_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ds->is); + return GNUNET_NO; + } + { + struct TALER_TESTING_Trait traits[] = { + /* First two traits are only available if + ds->traits is #GNUNET_YES */ + TALER_TESTING_make_trait_exchange_pub (0, + &ds->exchange_pub), + TALER_TESTING_make_trait_exchange_sig (0, + &ds->exchange_sig), + /* These traits are always available */ + TALER_TESTING_make_trait_coin_priv (0, + coin_spent_priv), + TALER_TESTING_make_trait_wire_details (0, + ds->wire_details), + TALER_TESTING_make_trait_contract_terms (0, + ds->contract_terms), + TALER_TESTING_make_trait_merchant_priv (0, + &ds->merchant_priv), + TALER_TESTING_make_trait_amount_obj (0, + &ds->amount), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait ((ds->traits_ready) + ? traits + : &traits[2], + ret, + trait, + index); + } +} + + +/** + * Create a "deposit" command. + * + * @param label command label. + * @param coin_reference reference to any operation that can + * provide a coin. + * @param coin_index if @a withdraw_reference offers an array of + * coins, this parameter selects which one in that array. + * This value is currently ignored, as only one-coin + * withdrawals are implemented. + * @param target_account_payto target account for the "deposit" + * request. + * @param contract_terms contract terms to be signed over by the + * coin. + * @param refund_deadline refund deadline, zero means 'no refunds'. + * Note, if time were absolute, then it would have come + * one day and disrupt tests meaning. + * @param amount how much is going to be deposited. + * @param expected_response_code expected HTTP response code. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_deposit (const char *label, + const char *coin_reference, + unsigned int coin_index, + const char *target_account_payto, + const char *contract_terms, + struct GNUNET_TIME_Relative refund_deadline, + const char *amount, + unsigned int expected_response_code) +{ + struct DepositState *ds; + json_t *wire_details; + + wire_details = TALER_TESTING_make_wire_details (target_account_payto); + ds = GNUNET_new (struct DepositState); + ds->coin_reference = coin_reference; + ds->coin_index = coin_index; + ds->wire_details = wire_details; + ds->contract_terms = json_loads (contract_terms, + JSON_REJECT_DUPLICATES, + NULL); + if (NULL == ds->contract_terms) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse contract terms `%s' for CMD `%s'\n", + contract_terms, + label); + GNUNET_assert (0); + } + ds->timestamp = GNUNET_TIME_absolute_get (); + (void) GNUNET_TIME_round_abs (&ds->timestamp); + + json_object_set_new (ds->contract_terms, + "timestamp", + GNUNET_JSON_from_time_abs (ds->timestamp)); + if (0 != refund_deadline.rel_value_us) + { + ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline); + (void) GNUNET_TIME_round_abs (&ds->refund_deadline); + json_object_set_new (ds->contract_terms, + "refund_deadline", + GNUNET_JSON_from_time_abs (ds->refund_deadline)); + } + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &ds->amount)); + ds->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = ds, + .label = label, + .run = &deposit_run, + .cleanup = &deposit_cleanup, + .traits = &deposit_traits + }; + + return cmd; + } +} + + +/** + * Modify a deposit command to enable retries when we get transient + * errors from the exchange. + * + * @param cmd a deposit command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd) +{ + struct DepositState *ds; + + GNUNET_assert (&deposit_run == cmd.run); + ds = cmd.cls; + ds->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_api_cmd_deposit.c */ diff --git a/src/testing/testing_api_cmd_exec_aggregator.c b/src/testing/testing_api_cmd_exec_aggregator.c new file mode 100644 index 000000000..7602cf1d5 --- /dev/null +++ b/src/testing/testing_api_cmd_exec_aggregator.c @@ -0,0 +1,166 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ +/** + * @file testing/testing_api_cmd_exec_aggregator.c + * @brief run the taler-exchange-aggregator command + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "aggregator" CMD. + */ +struct AggregatorState +{ + + /** + * Aggregator process. + */ + struct GNUNET_OS_Process *aggregator_proc; + + /** + * Configuration file used by the aggregator. + */ + const char *config_filename; +}; + + +/** + * Run the command. Use the `taler-exchange-aggregator' program. + * + * @param cls closure. + * @param cmd command being run. + * @param is interpreter state. + */ +static void +aggregator_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AggregatorState *as = cls; + + as->aggregator_proc + = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-aggregator", + "taler-exchange-aggregator", + "-c", as->config_filename, + "-t", /* exit when done */ + NULL); + if (NULL == as->aggregator_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "aggregator" CMD, and possibly kill its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +aggregator_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AggregatorState *as = cls; + + if (NULL != as->aggregator_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (as->aggregator_proc, + SIGKILL)); + GNUNET_OS_process_wait (as->aggregator_proc); + GNUNET_OS_process_destroy (as->aggregator_proc); + as->aggregator_proc = NULL; + } + GNUNET_free (as); +} + + +/** + * Offer "aggregator" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static int +aggregator_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AggregatorState *as = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, &as->aggregator_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make a "aggregator" CMD. + * + * @param label command label. + * @param config_filename configuration file for the + * aggregator to use. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_aggregator (const char *label, + const char *config_filename) +{ + struct AggregatorState *as; + + as = GNUNET_new (struct AggregatorState); + as->config_filename = config_filename; + { + struct TALER_TESTING_Command cmd = { + .cls = as, + .label = label, + .run = &aggregator_run, + .cleanup = &aggregator_cleanup, + .traits = &aggregator_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_exec_aggregator.c */ diff --git a/src/testing/testing_api_cmd_exec_auditor-sign.c b/src/testing/testing_api_cmd_exec_auditor-sign.c new file mode 100644 index 000000000..fec7da7cb --- /dev/null +++ b/src/testing/testing_api_cmd_exec_auditor-sign.c @@ -0,0 +1,232 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ + +/** + * @file testing/testing_api_cmd_exec_auditor-sign.c + * @brief run the taler-exchange-aggregator command + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "auditor sign" CMD. + */ +struct AuditorSignState +{ + + /** + * Handle to the process making the signature. + */ + struct GNUNET_OS_Process *auditor_sign_proc; + + /** + * Configuration file used by the command. + */ + const char *config_filename; + + /** + * File name of signed blob. + */ + char *signed_keys_out; +}; + + +/** + * Run the command; calls the `taler-auditor-sign' program. + * + * @param cls closure. + * @param cmd the command. + * @param is interpreter state. + */ +static void +auditor_sign_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AuditorSignState *ass = cls; + + struct GNUNET_CONFIGURATION_Handle *cfg; + char *test_home_dir; + char *exchange_master_pub; + struct GNUNET_TIME_Absolute now; + + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != GNUNET_CONFIGURATION_load + (cfg, ass->config_filename)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "paths", + "TALER_TEST_HOME", + &test_home_dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "paths", + "TALER_TEST_HOME"); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + now = GNUNET_TIME_absolute_get (); + GNUNET_asprintf + (&ass->signed_keys_out, + "%s/.local/share/taler/auditors/auditor-%llu.out", + test_home_dir, + (unsigned long long) now.abs_value_us); + GNUNET_free (test_home_dir); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "MASTER_PUBLIC_KEY", + &exchange_master_pub)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "MASTER_PUBLIC_KEY"); + GNUNET_CONFIGURATION_destroy (cfg); + + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_CONFIGURATION_destroy (cfg); + + ass->auditor_sign_proc = GNUNET_OS_start_process + (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor-sign", + "taler-auditor-sign", + "-c", ass->config_filename, + "-u", "http://auditor/", + "-m", exchange_master_pub, + "-r", "auditor.in", + "-o", ass->signed_keys_out, + NULL); + GNUNET_free (exchange_master_pub); + if (NULL == ass->auditor_sign_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "auditor sign" CMD, and possibly + * kill its process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +auditor_sign_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AuditorSignState *ass = cls; + + if (NULL != ass->auditor_sign_proc) + { + GNUNET_break (0 == GNUNET_OS_process_kill + (ass->auditor_sign_proc, SIGKILL)); + GNUNET_OS_process_wait (ass->auditor_sign_proc); + GNUNET_OS_process_destroy (ass->auditor_sign_proc); + ass->auditor_sign_proc = NULL; + } + GNUNET_free_non_null (ass->signed_keys_out); + GNUNET_free (ass); +} + + +/** + * Offer "auditor sign" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +auditor_sign_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AuditorSignState *ass = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, &ass->auditor_sign_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make a "auditor sign" CMD. + * + * @param label command label + * @param config_filename configuration filename + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_auditor_sign (const char *label, + const char *config_filename) +{ + struct AuditorSignState *ass; + + ass = GNUNET_new (struct AuditorSignState); + ass->config_filename = config_filename; + + { + struct TALER_TESTING_Command cmd = { + .cls = ass, + .label = label, + .run = &auditor_sign_run, + .cleanup = &auditor_sign_cleanup, + .traits = &auditor_sign_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_exec_auditor-sign.c */ diff --git a/src/testing/testing_api_cmd_exec_keyup.c b/src/testing/testing_api_cmd_exec_keyup.c new file mode 100644 index 000000000..cc4fb9e2e --- /dev/null +++ b/src/testing/testing_api_cmd_exec_keyup.c @@ -0,0 +1,235 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ + +/** + * @file testing/testing_api_cmd_exec_keyup.c + * @brief run the taler-exchange-keyup command + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "keyup" CMD. + */ +struct KeyupState +{ + + /** + * Process for the "keyup" command. + */ + struct GNUNET_OS_Process *keyup_proc; + + /** + * Configuration file used by the command. + */ + const char *config_filename; + + /** + * If GNUNET_YES, then the fake @e now value will be + * passed to taler-exchange-keyup via the --time + * option. + */ + unsigned int with_now; + + /** + * User-provided fake now. + */ + struct GNUNET_TIME_Absolute now; +}; + + +/** + * Run the command; calls the `taler-exchange-keyup' program. + * + * @param cls closure. + * @param cmd the commaind being run. + * @param is interpreter state. + */ +static void +keyup_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct KeyupState *ks = cls; + + if (GNUNET_YES == ks->with_now) + { + ks->keyup_proc = GNUNET_OS_start_process + (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-keyup", + "taler-exchange-keyup", + "-c", ks->config_filename, + "-o", "auditor.in", + "--time", + GNUNET_STRINGS_absolute_time_to_string (ks->now), + NULL); + } + else + ks->keyup_proc = GNUNET_OS_start_process + (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-keyup", + "taler-exchange-keyup", + "-c", ks->config_filename, + "-o", "auditor.in", + NULL); + + if (NULL == ks->keyup_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + /* This function does not tell whether the command + * succeeded or not! */ + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "keyup" CMD, and possibly kills its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +keyup_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct KeyupState *ks = cls; + + if (NULL != ks->keyup_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ks->keyup_proc, + SIGKILL)); + GNUNET_OS_process_wait (ks->keyup_proc); + GNUNET_OS_process_destroy (ks->keyup_proc); + ks->keyup_proc = NULL; + } + GNUNET_free (ks); +} + + +/** + * Offer "keyup" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * + * @return #GNUNET_OK on success. + */ +static int +keyup_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct KeyupState *ks = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, &ks->keyup_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make the "keyup" CMD, with "--timestamp" option. + * + * @param label command label. + * @param config_filename configuration filename. + * @param now Unix timestamp representing the fake "now". + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_keyup_with_now + (const char *label, + const char *config_filename, + struct GNUNET_TIME_Absolute now) +{ + struct KeyupState *ks; + + ks = GNUNET_new (struct KeyupState); + ks->config_filename = config_filename; + ks->now = now; + ks->with_now = GNUNET_YES; + { + struct TALER_TESTING_Command cmd = { + .cls = ks, + .label = label, + .run = &keyup_run, + .cleanup = &keyup_cleanup, + .traits = &keyup_traits + }; + + return cmd; + } +} + + +/** + * Make the "keyup" CMD. + * + * @param label command label. + * @param config_filename configuration filename. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_keyup (const char *label, + const char *config_filename) +{ + struct KeyupState *ks; + + ks = GNUNET_new (struct KeyupState); + ks->config_filename = config_filename; + { + struct TALER_TESTING_Command cmd = { + .cls = ks, + .label = label, + .run = &keyup_run, + .cleanup = &keyup_cleanup, + .traits = &keyup_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_exec_keyup.c */ diff --git a/src/testing/testing_api_cmd_exec_wirewatch.c b/src/testing/testing_api_cmd_exec_wirewatch.c new file mode 100644 index 000000000..44de96838 --- /dev/null +++ b/src/testing/testing_api_cmd_exec_wirewatch.c @@ -0,0 +1,167 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_exec_wirewatch.c + * @brief run the taler-exchange-wirewatch command + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "wirewatch" CMD. + */ +struct WirewatchState +{ + + /** + * Process for the wirewatcher. + */ + struct GNUNET_OS_Process *wirewatch_proc; + + /** + * Configuration file used by the wirewatcher. + */ + const char *config_filename; +}; + +/** + * Run the command; use the `taler-exchange-wirewatch' program. + * + * @param cls closure. + * @param cmd command currently being executed. + * @param is interpreter state. + */ +static void +wirewatch_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct WirewatchState *ws = cls; + + ws->wirewatch_proc + = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-wirewatch", + "taler-exchange-wirewatch", + "-c", ws->config_filename, + "-T", /* exit when done */ + NULL); + if (NULL == ws->wirewatch_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "wirewatch" CMD, and possibly + * kills its process if it did not terminate regularly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +wirewatch_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct WirewatchState *ws = cls; + + if (NULL != ws->wirewatch_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ws->wirewatch_proc, + SIGKILL)); + GNUNET_OS_process_wait (ws->wirewatch_proc); + GNUNET_OS_process_destroy (ws->wirewatch_proc); + ws->wirewatch_proc = NULL; + } + GNUNET_free (ws); +} + + +/** + * Offer "wirewatch" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +wirewatch_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct WirewatchState *ws = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (0, + &ws->wirewatch_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make a "wirewatch" CMD. + * + * @param label command label. + * @param config_filename configuration filename. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_wirewatch (const char *label, + const char *config_filename) +{ + struct WirewatchState *ws; + + ws = GNUNET_new (struct WirewatchState); + ws->config_filename = config_filename; + + { + struct TALER_TESTING_Command cmd = { + .cls = ws, + .label = label, + .run = &wirewatch_run, + .cleanup = &wirewatch_cleanup, + .traits = &wirewatch_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_exec_wirewatch.c */ diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c new file mode 100644 index 000000000..b66a4bfa9 --- /dev/null +++ b/src/testing/testing_api_cmd_insert_deposit.c @@ -0,0 +1,318 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ +/** + * @file testing/testing_api_cmd_insert_deposit.c + * @brief deposit a coin directly into the database. + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" +#include "taler_exchangedb_plugin.h" + + +/** + * State for a "insert-deposit" CMD. + */ +struct InsertDepositState +{ + /** + * Configuration file used by the command. + */ + const struct TALER_TESTING_DatabaseConnection *dbc; + + /** + * Human-readable name of the shop. + */ + const char *merchant_name; + + /** + * Merchant account name (NOT a payto-URI). + */ + const char *merchant_account; + + /** + * Deadline before which the aggregator should + * send the payment to the merchant. + */ + struct GNUNET_TIME_Relative wire_deadline; + + /** + * Amount to deposit, inclusive of deposit fee. + */ + const char *amount_with_fee; + + /** + * Deposit fee. + */ + const char *deposit_fee; +}; + +/** + * Setup (fake) information about a coin used in deposit. + * + * @param[out] issue information to initialize with "valid" data + */ +static void +fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue) +{ + memset (issue, 0, sizeof (struct + TALER_EXCHANGEDB_DenominationKeyInformationP)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount_nbo ("EUR:1", + &issue->properties.value)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount_nbo ("EUR:0.1", + &issue->properties.fee_withdraw)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount_nbo ("EUR:0.1", + &issue->properties.fee_deposit)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount_nbo ("EUR:0.1", + &issue->properties.fee_refresh)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount_nbo ("EUR:0.1", + &issue->properties.fee_refund)); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the commaind being run. + * @param is interpreter state. + */ +static void +insert_deposit_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct InsertDepositState *ids = cls; + struct TALER_EXCHANGEDB_Deposit deposit; + struct TALER_MerchantPrivateKeyP merchant_priv; + struct TALER_EXCHANGEDB_DenominationKeyInformationP issue; + struct TALER_DenominationPublicKey dpk; + struct GNUNET_CRYPTO_RsaPrivateKey *denom_priv; + struct GNUNET_HashCode hc; + + // prepare and store issue first. + fake_issue (&issue); + denom_priv = GNUNET_CRYPTO_rsa_private_key_create (1024); + dpk.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv); + GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key, + &issue.properties.denom_hash); + + if ( (GNUNET_OK != + ids->dbc->plugin->start (ids->dbc->plugin->cls, + ids->dbc->session, + "talertestinglib: denomination insertion")) || + (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + ids->dbc->plugin->insert_denomination_info (ids->dbc->plugin->cls, + ids->dbc->session, + &dpk, + &issue)) || + (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + ids->dbc->plugin->commit (ids->dbc->plugin->cls, + ids->dbc->session)) ) + { + TALER_TESTING_interpreter_fail (is); + return; + } + + /* prepare and store deposit now. */ + memset (&deposit, + 0, + sizeof (deposit)); + + GNUNET_CRYPTO_kdf (&merchant_priv, + sizeof (struct TALER_MerchantPrivateKeyP), + "merchant-priv", + strlen ("merchant-priv"), + ids->merchant_name, + strlen (ids->merchant_name), + NULL, + 0); + GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv, + &deposit.merchant_pub.eddsa_pub); + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &deposit.h_contract_terms); + if ( (GNUNET_OK != + TALER_string_to_amount (ids->amount_with_fee, + &deposit.amount_with_fee)) || + (GNUNET_OK != + TALER_string_to_amount (ids->deposit_fee, + &deposit.deposit_fee)) ) + { + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key, + &deposit.coin.denom_pub_hash); + + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &hc); + deposit.coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (denom_priv, + &hc); + { + char *str; + + GNUNET_asprintf (&str, + "payto://x-taler-bank/localhost/%s", + ids->merchant_account); + deposit.receiver_wire_account + = json_pack ("{s:s, s:s}", + "salt", "this-is-a-salt-value", + "url", str); + GNUNET_free (str); + } + + GNUNET_assert (GNUNET_OK == + TALER_JSON_merchant_wire_signature_hash ( + deposit.receiver_wire_account, + &deposit.h_wire)); + deposit.timestamp = GNUNET_TIME_absolute_get (); + GNUNET_TIME_round_abs (&deposit.timestamp); + deposit.wire_deadline = GNUNET_TIME_relative_to_absolute ( + ids->wire_deadline); + GNUNET_TIME_round_abs (&deposit.wire_deadline); + + /* finally, actually perform the DB operation */ + if ( (GNUNET_OK != + ids->dbc->plugin->start (ids->dbc->plugin->cls, + ids->dbc->session, + "libtalertesting: insert deposit")) || + (0 > + ids->dbc->plugin->ensure_coin_known (ids->dbc->plugin->cls, + ids->dbc->session, + &deposit.coin)) || + (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != + ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls, + ids->dbc->session, + &deposit)) || + (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != + ids->dbc->plugin->commit (ids->dbc->plugin->cls, + ids->dbc->session)) ) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + } + + GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig.rsa_signature); + GNUNET_CRYPTO_rsa_public_key_free (dpk.rsa_public_key); + GNUNET_CRYPTO_rsa_private_key_free (denom_priv); + json_decref (deposit.receiver_wire_account); + + TALER_TESTING_interpreter_next (is); +} + + +/** + * Free the state of a "auditor-dbinit" CMD, and possibly kills its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +insert_deposit_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct InsertDepositState *ids = cls; + + GNUNET_free (ids); +} + + +/** + * Offer "insert-deposit" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +insert_deposit_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + (void) cls; + (void) ret; + (void) trait; + (void) index; + return GNUNET_NO; +} + + +/** + * Make the "insert-deposit" CMD. + * + * @param label command label. + * @param dbc collects database plugin and session handles. + * @param merchant_name Human-readable name of the merchant. + * @param merchant_account merchant's account name (NOT a payto:// URI) + * @param wire_deadline point in time where the aggregator should have + * wired money to the merchant. + * @param amount_with_fee amount to deposit (inclusive of deposit fee) + * @param deposit_fee deposit fee + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_insert_deposit (const char *label, + const struct + TALER_TESTING_DatabaseConnection *dbc, + const char *merchant_name, + const char *merchant_account, + struct GNUNET_TIME_Relative wire_deadline, + const char *amount_with_fee, + const char *deposit_fee) +{ + struct InsertDepositState *ids; + + ids = GNUNET_new (struct InsertDepositState); + ids->dbc = dbc; + ids->merchant_name = merchant_name; + ids->merchant_account = merchant_account; + ids->wire_deadline = wire_deadline; + ids->amount_with_fee = amount_with_fee; + ids->deposit_fee = deposit_fee; + + { + struct TALER_TESTING_Command cmd = { + .cls = ids, + .label = label, + .run = &insert_deposit_run, + .cleanup = &insert_deposit_cleanup, + .traits = &insert_deposit_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_insert_deposit.c */ diff --git a/src/testing/testing_api_cmd_recoup.c b/src/testing/testing_api_cmd_recoup.c new file mode 100644 index 000000000..c12f67f6e --- /dev/null +++ b/src/testing/testing_api_cmd_recoup.c @@ -0,0 +1,619 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_recoup.c + * @brief Implement the /revoke and /recoup test commands. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * State for a "revoke" CMD. + */ +struct RevokeState +{ + /** + * Expected HTTP status code. + */ + unsigned int expected_response_code; + + /** + * Command that offers a denomination to revoke. + */ + const char *coin_reference; + + /** + * The interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * The revoke process handle. + */ + struct GNUNET_OS_Process *revoke_proc; + + /** + * Configuration file name. + */ + const char *config_filename; + + /** + * Encoding of the denomination (to revoke) public key hash. + */ + char *dhks; + +}; + + +/** + * State for a "pay back" CMD. + */ +struct RecoupState +{ + /** + * Expected HTTP status code. + */ + unsigned int expected_response_code; + + /** + * Command that offers a reserve private key, + * plus a coin to be paid back. + */ + const char *coin_reference; + + /** + * The interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Amount expected to be paid back. + */ + const char *amount; + + /** + * Handle to the ongoing operation. + */ + struct TALER_EXCHANGE_RecoupHandle *ph; + + /** + * NULL if coin was not refreshed, otherwise reference + * to the melt operation underlying @a coin_reference. + */ + const char *melt_reference; + +}; + + +/** + * Parser reference to a coin. + * + * @param coin_reference of format $LABEL['#' $INDEX]? + * @param[out] cref where we return a copy of $LABEL + * @param[out] idx where we set $INDEX + * @return #GNUNET_SYSERR if $INDEX is present but not numeric + */ +static int +parse_coin_reference (const char *coin_reference, + char **cref, + unsigned int *idx) +{ + const char *index; + + /* We allow command references of the form "$LABEL#$INDEX" or + just "$LABEL", which implies the index is 0. Figure out + which one it is. */ + index = strchr (coin_reference, '#'); + if (NULL == index) + { + *idx = 0; + *cref = GNUNET_strdup (coin_reference); + return GNUNET_OK; + } + *cref = GNUNET_strndup (coin_reference, + index - coin_reference); + if (1 != sscanf (index + 1, + "%u", + idx)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Numeric index (not `%s') required after `#' in command reference of command in %s:%u\n", + index, + __FILE__, + __LINE__); + GNUNET_free (*cref); + *cref = NULL; + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Check the result of the recoup request: checks whether + * the HTTP response code is good, and that the coin that + * was paid back belonged to the right reserve. + * + * @param cls closure + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param amount amount the exchange will wire back for this coin. + * @param timestamp what time did the exchange receive the + * /recoup request + * @param reserve_pub public key of the reserve receiving the recoup, NULL if refreshed or on error + * @param old_coin_pub public key of the dirty coin, NULL if not refreshed or on error + * @param full_response raw response from the exchange. + */ +static void +recoup_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const struct TALER_Amount *amount, + struct GNUNET_TIME_Absolute timestamp, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_CoinSpendPublicKeyP *old_coin_pub, + const json_t *full_response) +{ + struct RecoupState *ps = cls; + struct TALER_TESTING_Interpreter *is = ps->is; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + const struct TALER_TESTING_Command *reserve_cmd; + char *cref; + unsigned int idx; + + ps->ph = NULL; + if (ps->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s in %s:%u\n", + http_status, + cmd->label, + __FILE__, + __LINE__); + json_dumpf (full_response, stderr, 0); + fprintf (stderr, "\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != + parse_coin_reference (ps->coin_reference, + &cref, + &idx)) + { + TALER_TESTING_interpreter_fail (is); + return; + } + + reserve_cmd = TALER_TESTING_interpreter_lookup_command + (is, cref); + GNUNET_free (cref); + + if (NULL == reserve_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + switch (http_status) + { + case MHD_HTTP_OK: + /* first, check amount */ + { + struct TALER_Amount expected_amount; + + if (GNUNET_OK != + TALER_string_to_amount (ps->amount, &expected_amount)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (0 != TALER_amount_cmp (amount, &expected_amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Total amount missmatch to command %s\n", + cmd->label); + json_dumpf (full_response, stderr, 0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + /* now, check old_coin_pub or reserve_pub, respectively */ + if (NULL != ps->melt_reference) + { + const struct TALER_TESTING_Command *melt_cmd; + const struct TALER_CoinSpendPrivateKeyP *dirty_priv; + struct TALER_CoinSpendPublicKeyP oc; + + melt_cmd = TALER_TESTING_interpreter_lookup_command (is, + ps->melt_reference); + if (NULL == melt_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (melt_cmd, + 0, + &dirty_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv, + &oc.eddsa_pub); + if (0 != GNUNET_memcmp (&oc, + old_coin_pub)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + else + { + const struct TALER_ReservePrivateKeyP *reserve_priv; + struct TALER_ReservePublicKeyP rp; + + if (NULL == reserve_pub) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv + (reserve_cmd, idx, &reserve_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, + &rp.eddsa_pub); + if (0 != GNUNET_memcmp (reserve_pub, &rp)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unmanaged HTTP status code %u.\n", + http_status); + break; + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +recoup_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RecoupState *ps = cls; + const struct TALER_TESTING_Command *coin_cmd; + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + const struct TALER_DenominationBlindingKeyP *blinding_key; + const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; + const struct TALER_DenominationSignature *coin_sig; + struct TALER_PlanchetSecretsP planchet; + char *cref; + unsigned int idx; + + ps->is = is; + if (GNUNET_OK != + parse_coin_reference (ps->coin_reference, + &cref, + &idx)) + { + TALER_TESTING_interpreter_fail (is); + return; + } + + coin_cmd = TALER_TESTING_interpreter_lookup_command + (is, cref); + GNUNET_free (cref); + + if (NULL == coin_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv + (coin_cmd, idx, &coin_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != TALER_TESTING_get_trait_blinding_key + (coin_cmd, idx, &blinding_key)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + planchet.coin_priv = *coin_priv; + planchet.blinding_key = *blinding_key; + + if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub + (coin_cmd, idx, &denom_pub)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig + (coin_cmd, idx, &coin_sig)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Trying to get '%s..' paid back\n", + TALER_B2S (&denom_pub->h_key)); + + ps->ph = TALER_EXCHANGE_recoup (is->exchange, + denom_pub, + coin_sig, + &planchet, + NULL != ps->melt_reference, + recoup_cb, + ps); + GNUNET_assert (NULL != ps->ph); +} + + +/** + * Cleanup the state. + * + * @param cls closure, must be a `struct RevokeState`. + * @param cmd the command which is being cleaned up. + */ +static void +revoke_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RevokeState *rs = cls; + + if (NULL != rs->revoke_proc) + { + GNUNET_break (0 == GNUNET_OS_process_kill + (rs->revoke_proc, SIGKILL)); + GNUNET_OS_process_wait (rs->revoke_proc); + GNUNET_OS_process_destroy (rs->revoke_proc); + rs->revoke_proc = NULL; + } + GNUNET_free_non_null (rs->dhks); + GNUNET_free (rs); +} + + +/** + * Cleanup the "recoup" CMD state, and possibly cancel + * a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +recoup_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RecoupState *ps = cls; + if (NULL != ps->ph) + { + TALER_EXCHANGE_recoup_cancel (ps->ph); + ps->ph = NULL; + } + GNUNET_free (ps); +} + + +/** + * Offer internal data from a "revoke" CMD to other CMDs. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static int +revoke_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RevokeState *rs = cls; + struct TALER_TESTING_Trait traits[] = { + /* Needed by the handler which waits the proc' + * death and calls the next command */ + TALER_TESTING_make_trait_process (0, &rs->revoke_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Run the "revoke" command. The core of the function + * is to call the "keyup" utility passing it the base32 + * encoding of the denomination to revoke. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +revoke_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RevokeState *rs = cls; + const struct TALER_TESTING_Command *coin_cmd; + const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; + + rs->is = is; + /* Get denom pub from trait */ + coin_cmd = TALER_TESTING_interpreter_lookup_command + (is, rs->coin_reference); + + if (NULL == coin_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_denom_pub + (coin_cmd, 0, &denom_pub)); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Trying to revoke denom '%s..'\n", + TALER_B2S (&denom_pub->h_key)); + + rs->dhks = GNUNET_STRINGS_data_to_string_alloc + (&denom_pub->h_key, sizeof (struct GNUNET_HashCode)); + + rs->revoke_proc = GNUNET_OS_start_process + (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-keyup", + "taler-exchange-keyup", + "-c", rs->config_filename, + "-r", rs->dhks, + NULL); + + if (NULL == rs->revoke_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Revoke is ongoing..\n"); + + is->reload_keys = GNUNET_OK; + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Make a "recoup" command. + * + * @param label the command label + * @param expected_response_code expected HTTP status code + * @param coin_reference reference to any command which + * offers a coin & reserve private key. + * @param amount denomination to pay back. + * @param melt_reference NULL if coin was not refreshed + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_recoup (const char *label, + unsigned int expected_response_code, + const char *coin_reference, + const char *amount, + const char *melt_reference) +{ + struct RecoupState *ps; + + ps = GNUNET_new (struct RecoupState); + ps->expected_response_code = expected_response_code; + ps->coin_reference = coin_reference; + ps->amount = amount; + ps->melt_reference = melt_reference; + { + struct TALER_TESTING_Command cmd = { + .cls = ps, + .label = label, + .run = &recoup_run, + .cleanup = &recoup_cleanup + }; + + return cmd; + } +} + + +/** + * Make a "revoke" command. + * + * @param label the command label. + * @param expected_response_code expected HTTP status code. + * @param coin_reference reference to a CMD that will offer the + * denomination to revoke. + * @param config_filename configuration file name. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_revoke (const char *label, + unsigned int expected_response_code, + const char *coin_reference, + const char *config_filename) +{ + + struct RevokeState *rs; + + rs = GNUNET_new (struct RevokeState); + rs->expected_response_code = expected_response_code; + rs->coin_reference = coin_reference; + rs->config_filename = config_filename; + { + struct TALER_TESTING_Command cmd = { + .cls = rs, + .label = label, + .run = &revoke_run, + .cleanup = &revoke_cleanup, + .traits = &revoke_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c new file mode 100644 index 000000000..73b74dafb --- /dev/null +++ b/src/testing/testing_api_cmd_refresh.c @@ -0,0 +1,1410 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_refresh.c + * @brief commands for testing all "refresh" features. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" +#include "taler_signatures.h" +#include "backoff.h" + + +/** + * Information about a fresh coin generated by the refresh + * operation. + */ +struct TALER_TESTING_FreshCoinData +{ + + /** + * If @e amount is NULL, this specifies the denomination key to + * use. Otherwise, this will be set (by the interpreter) to the + * denomination PK matching @e amount. + */ + const struct TALER_EXCHANGE_DenomPublicKey *pk; + + /** + * Set (by the interpreter) to the exchange's signature over the + * coin's public key. + */ + struct TALER_DenominationSignature sig; + + /** + * Set (by the interpreter) to the coin's private key. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + + /** + * The blinding key (needed for recoup operations). + */ + struct TALER_DenominationBlindingKeyP blinding_key; + +}; + + +/** + * State for a "refresh melt" command. + */ +struct RefreshMeltState +{ + + /** + * Reference to reserve_withdraw operations for coin to + * be used for the /refresh/melt operation. + */ + const char *coin_reference; + + /** + * "Crypto data" used in the refresh operation. + */ + char *refresh_data; + + /** + * Reference to a previous melt command. + */ + const char *melt_reference; + + /** + * Melt handle while operation is running. + */ + struct TALER_EXCHANGE_RefreshMeltHandle *rmh; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Array of the denomination public keys + * corresponding to the @e num_fresh_coins; + */ + struct TALER_EXCHANGE_DenomPublicKey *fresh_pks; + + /** + * Private key of the dirty coin being melted. + */ + const struct TALER_CoinSpendPrivateKeyP *melt_priv; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Number of bytes in @e refresh_data. + */ + size_t refresh_data_length; + + /** + * Amounts to be generated during melt. + */ + const char **melt_fresh_amounts; + + /** + * Number of fresh coins generated by the melt. + */ + unsigned int num_fresh_coins; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * if set to #GNUNET_YES, then two /refresh/melt operations + * will be performed. This is needed to trigger the logic + * that manages those already-made requests. Note: it + * is not possible to just copy-and-paste a test refresh melt + * CMD to have the same effect, because every data preparation + * generates new planchets that (in turn) make the whole "hash" + * different from any previous one, therefore NOT allowing the + * exchange to pick any previous /rerfesh/melt operation from + * the database. + */ + unsigned int double_melt; + + /** + * Should we retry on (transient) failures? + */ + int do_retry; + + /** + * Set by the melt callback as it comes from the exchange. + */ + uint16_t noreveal_index; +}; + + +/** + * State for a "refresh reveal" CMD. + */ +struct RefreshRevealState +{ + /** + * Link to a "refresh melt" command. + */ + const char *melt_reference; + + /** + * Reveal handle while operation is running. + */ + struct TALER_EXCHANGE_RefreshRevealHandle *rrh; + + /** + * Convenience struct to keep in one place all the + * data related to one fresh coin, set by the reveal callback + * as it comes from the exchange. + */ + struct TALER_TESTING_FreshCoinData *fresh_coins; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Number of fresh coins withdrawn, set by the + * reveal callback as it comes from the exchange, + * it is the length of the @e fresh_coins array. + */ + unsigned int num_fresh_coins; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Should we retry on (transient) failures? + */ + int do_retry; + +}; + + +/** + * State for a "refresh link" CMD. + */ +struct RefreshLinkState +{ + /** + * Link to a "refresh reveal" command. + */ + const char *reveal_reference; + + /** + * Handle to the ongoing operation. + */ + struct TALER_EXCHANGE_RefreshLinkHandle *rlh; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Should we retry on (transient) failures? + */ + int do_retry; + +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +refresh_reveal_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #refresh_reveal_run. + * + * @param cls a `struct RefreshRevealState` + */ +static void +do_reveal_retry (void *cls) +{ + struct RefreshRevealState *rrs = cls; + + rrs->retry_task = NULL; + refresh_reveal_run (rrs, + NULL, + rrs->is); +} + + +/** + * "refresh reveal" request callback; it checks that the response + * code is expected and copies into its command's state the data + * coming from the exchange, namely the fresh coins. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param num_coins number of fresh coins created, length of the + * @a sigs and @a coin_privs arrays, 0 if the operation + * failed. + * @param coin_privs array of @a num_coins private keys for the + * coins that were created, NULL on error. + * @param sigs array of signature over @a num_coins coins, + * NULL on error. + * @param full_response raw exchange response. + */ +static void +reveal_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + unsigned int num_coins, + const struct TALER_PlanchetSecretsP *coin_privs, + const struct TALER_DenominationSignature *sigs, + const json_t *full_response) +{ + struct RefreshRevealState *rrs = cls; + const struct TALER_TESTING_Command *melt_cmd; + + rrs->rrh = NULL; + if (rrs->expected_response_code != http_status) + { + if (GNUNET_YES == rrs->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying refresh reveal failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + rrs->backoff = GNUNET_TIME_UNIT_ZERO; + else + rrs->backoff = EXCHANGE_LIB_BACKOFF (rrs->backoff); + rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff, + &do_reveal_retry, + rrs); + return; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d to command %s in %s:%u\n", + http_status, + (int) ec, + rrs->is->commands[rrs->is->ip].label, + __FILE__, + __LINE__); + json_dumpf (full_response, stderr, 0); + TALER_TESTING_interpreter_fail (rrs->is); + return; + } + melt_cmd = TALER_TESTING_interpreter_lookup_command + (rrs->is, rrs->melt_reference); + if (NULL == melt_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rrs->is); + return; + } + rrs->num_fresh_coins = num_coins; + switch (http_status) + { + case MHD_HTTP_OK: + rrs->fresh_coins = GNUNET_new_array (num_coins, + struct TALER_TESTING_FreshCoinData); + for (unsigned int i = 0; ifresh_coins[i]; + + if (GNUNET_OK != + TALER_TESTING_get_trait_denom_pub (melt_cmd, + i, + &fc->pk)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rrs->is); + return; + } + fc->coin_priv = coin_privs[i].coin_priv; + fc->blinding_key = coin_privs[i].blinding_key; + fc->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup + (sigs[i].rsa_signature); + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Unknown HTTP status %d\n", + http_status); + } + TALER_TESTING_interpreter_next (rrs->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +refresh_reveal_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RefreshRevealState *rrs = cls; + struct RefreshMeltState *rms; + const struct TALER_TESTING_Command *melt_cmd; + + rrs->is = is; + melt_cmd = TALER_TESTING_interpreter_lookup_command + (is, rrs->melt_reference); + + if (NULL == melt_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rrs->is); + return; + } + rms = melt_cmd->cls; + rrs->rrh = TALER_EXCHANGE_refresh_reveal + (is->exchange, + rms->refresh_data_length, + rms->refresh_data, + rms->noreveal_index, + &reveal_cb, rrs); + + if (NULL == rrs->rrh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state from a "refresh reveal" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +refresh_reveal_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RefreshRevealState *rrs = cls; + + if (NULL != rrs->rrh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + rrs->is->ip, + cmd->label); + + TALER_EXCHANGE_refresh_reveal_cancel (rrs->rrh); + rrs->rrh = NULL; + } + if (NULL != rrs->retry_task) + { + GNUNET_SCHEDULER_cancel (rrs->retry_task); + rrs->retry_task = NULL; + } + + for (unsigned int j = 0; j < rrs->num_fresh_coins; j++) + GNUNET_CRYPTO_rsa_signature_free (rrs->fresh_coins[j].sig.rsa_signature); + + GNUNET_free_non_null (rrs->fresh_coins); + rrs->fresh_coins = NULL; + rrs->num_fresh_coins = 0; + GNUNET_free (rrs); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +refresh_link_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #refresh_link_run. + * + * @param cls a `struct RefreshLinkState` + */ +static void +do_link_retry (void *cls) +{ + struct RefreshLinkState *rls = cls; + + rls->retry_task = NULL; + refresh_link_run (rls, + NULL, + rls->is); +} + + +/** + * "refresh link" operation callback, checks that HTTP response + * code is expected _and_ that all the linked coins were actually + * withdrawn by the "refresh reveal" CMD. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code + * @param num_coins number of fresh coins created, length of the + * @a sigs and @a coin_privs arrays, 0 if the operation + * failed. + * @param coin_privs array of @a num_coins private keys for the + * coins that were created, NULL on error. + * @param sigs array of signature over @a num_coins coins, NULL on + * error. + * @param pubs array of public keys for the @a sigs, + * NULL on error. + * @param full_response raw response from the exchange. + */ +static void +link_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + unsigned int num_coins, + const struct TALER_CoinSpendPrivateKeyP *coin_privs, + const struct TALER_DenominationSignature *sigs, + const struct TALER_DenominationPublicKey *pubs, + const json_t *full_response) +{ + + struct RefreshLinkState *rls = cls; + const struct TALER_TESTING_Command *reveal_cmd; + struct TALER_TESTING_Command *link_cmd + = &rls->is->commands[rls->is->ip]; + unsigned int found; + const unsigned int *num_fresh_coins; + + rls->rlh = NULL; + if (rls->expected_response_code != http_status) + { + if (GNUNET_YES == rls->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying refresh link failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + rls->backoff = GNUNET_TIME_UNIT_ZERO; + else + rls->backoff = EXCHANGE_LIB_BACKOFF (rls->backoff); + rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff, + &do_link_retry, + rls); + return; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d to command %s in %s:%u\n", + http_status, + (int) ec, + link_cmd->label, + __FILE__, + __LINE__); + json_dumpf (full_response, stderr, 0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + reveal_cmd = TALER_TESTING_interpreter_lookup_command + (rls->is, rls->reveal_reference); + + if (NULL == reveal_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + + switch (http_status) + { + case MHD_HTTP_OK: + /* check that number of coins returned matches */ + if (GNUNET_OK != TALER_TESTING_get_trait_uint + (reveal_cmd, 0, &num_fresh_coins)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + if (num_coins != *num_fresh_coins) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected number of fresh coins: %d vs %d in %s:%u\n", + num_coins, + *num_fresh_coins, + __FILE__, + __LINE__); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + /* check that the coins match */ + for (unsigned int i = 0; iis); + return; + } + + for (unsigned int i = 0; ikey.rsa_public_key, + pubs[j].rsa_public_key)) ) + { + found++; + break; + } + } + if (found != num_coins) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Only %u/%u coins match expectations\n", + found, num_coins); + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown HTTP response code %u.\n", + http_status); + } + TALER_TESTING_interpreter_next (rls->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +refresh_link_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RefreshLinkState *rls = cls; + struct RefreshRevealState *rrs; + struct RefreshMeltState *rms; + const struct TALER_TESTING_Command *reveal_cmd; + const struct TALER_TESTING_Command *melt_cmd; + const struct TALER_TESTING_Command *coin_cmd; + + rls->is = is; + reveal_cmd = TALER_TESTING_interpreter_lookup_command + (rls->is, rls->reveal_reference); + + if (NULL == reveal_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + rrs = reveal_cmd->cls; + melt_cmd = TALER_TESTING_interpreter_lookup_command + (rls->is, rrs->melt_reference); + + if (NULL == melt_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + + /* find reserve_withdraw command */ + { + rms = melt_cmd->cls; + coin_cmd = TALER_TESTING_interpreter_lookup_command + (rls->is, rms->coin_reference); + if (NULL == coin_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + } + + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv + (coin_cmd, 0, &coin_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } + + /* finally, use private key from withdraw sign command */ + rls->rlh = TALER_EXCHANGE_refresh_link + (is->exchange, coin_priv, &link_cb, rls); + + if (NULL == rls->rlh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rls->is); + return; + } +} + + +/** + * Free the state of the "refresh link" CMD, and possibly + * cancel a operation thereof. + * + * @param cls closure + * @param cmd the command which is being cleaned up. + */ +static void +refresh_link_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RefreshLinkState *rls = cls; + + if (NULL != rls->rlh) + { + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + rls->is->ip, + cmd->label); + TALER_EXCHANGE_refresh_link_cancel (rls->rlh); + rls->rlh = NULL; + } + if (NULL != rls->retry_task) + { + GNUNET_SCHEDULER_cancel (rls->retry_task); + rls->retry_task = NULL; + } + GNUNET_free (rls); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +refresh_melt_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #refresh_melt_run. + * + * @param cls a `struct RefreshMeltState` + */ +static void +do_melt_retry (void *cls) +{ + struct RefreshMeltState *rms = cls; + + rms->retry_task = NULL; + refresh_melt_run (rms, + NULL, + rms->is); +} + + +/** + * Callback for a "refresh melt" operation; checks if the HTTP + * response code is okay and re-run the melt operation if the + * CMD was set to do so. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param noreveal_index choice by the exchange in the + * cut-and-choose protocol, UINT16_MAX on error. + * @param exchange_pub public key the exchange used for signing. + * @param full_response raw response body from the exchange. + */ +static void +melt_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint32_t noreveal_index, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const json_t *full_response) +{ + struct RefreshMeltState *rms = cls; + + rms->rmh = NULL; + if (rms->expected_response_code != http_status) + { + if (GNUNET_YES == rms->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying refresh melt failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + rms->backoff = GNUNET_TIME_UNIT_ZERO; + else + rms->backoff = EXCHANGE_LIB_BACKOFF (rms->backoff); + rms->retry_task = GNUNET_SCHEDULER_add_delayed + (rms->backoff, + &do_melt_retry, + rms); + return; + } + } + GNUNET_log + (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d to command %s in %s:%u\n", + http_status, + (int) ec, + rms->is->commands[rms->is->ip].label, + __FILE__, + __LINE__); + json_dumpf (full_response, stderr, 0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + rms->noreveal_index = noreveal_index; + + if (GNUNET_YES == rms->double_melt) + { + TALER_LOG_DEBUG ("Doubling the melt (%s)\n", + rms->is->commands[rms->is->ip].label); + rms->rmh = TALER_EXCHANGE_refresh_melt + (rms->is->exchange, rms->refresh_data_length, + rms->refresh_data, &melt_cb, rms); + rms->double_melt = GNUNET_NO; + return; + } + TALER_TESTING_interpreter_next (rms->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +refresh_melt_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RefreshMeltState *rms = cls; + unsigned int num_fresh_coins; + const char *default_melt_fresh_amounts[] = { + "EUR:1", "EUR:1", "EUR:1", "EUR:0.1", + NULL + }; + const char **melt_fresh_amounts; + + if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts)) + melt_fresh_amounts = default_melt_fresh_amounts; + rms->is = is; + rms->noreveal_index = UINT16_MAX; + for (num_fresh_coins = 0; + NULL != melt_fresh_amounts[num_fresh_coins]; + num_fresh_coins++) + ; + rms->num_fresh_coins = num_fresh_coins; + rms->fresh_pks = GNUNET_new_array + (num_fresh_coins, + struct TALER_EXCHANGE_DenomPublicKey); + { + struct TALER_Amount melt_amount; + struct TALER_Amount fresh_amount; + const struct TALER_DenominationSignature *melt_sig; + const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub; + const struct TALER_TESTING_Command *coin_command; + + if (NULL == (coin_command + = TALER_TESTING_interpreter_lookup_command + (is, rms->coin_reference))) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + + if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv + (coin_command, 0, &rms->melt_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + + if (GNUNET_OK != + TALER_TESTING_get_trait_denom_sig (coin_command, + 0, + &melt_sig)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub + (coin_command, 0, &melt_denom_pub)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + /* Melt amount starts with the melt fee of the old coin; we'll add the + values and withdraw fees of the fresh coins next */ + melt_amount = melt_denom_pub->fee_refresh; + for (unsigned int i = 0; iis); + return; + } + fresh_pk = TALER_TESTING_find_pk + (TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount); + if (NULL == fresh_pk) + { + GNUNET_break (0); + /* Subroutine logs specific error */ + TALER_TESTING_interpreter_fail (rms->is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&melt_amount, + &melt_amount, + &fresh_amount)); + GNUNET_assert (GNUNET_OK == + TALER_amount_add (&melt_amount, + &melt_amount, + &fresh_pk->fee_withdraw)); + rms->fresh_pks[i] = *fresh_pk; + /* Make a deep copy of the RSA key */ + rms->fresh_pks[i].key.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pk->key.rsa_public_key); + } + rms->refresh_data + = TALER_EXCHANGE_refresh_prepare (rms->melt_priv, + &melt_amount, + melt_sig, + melt_denom_pub, + num_fresh_coins, + rms->fresh_pks, + &rms->refresh_data_length); + + if (NULL == rms->refresh_data) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + rms->rmh = TALER_EXCHANGE_refresh_melt (is->exchange, + rms->refresh_data_length, + rms->refresh_data, + &melt_cb, + rms); + + if (NULL == rms->rmh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + } +} + + +/** + * Free the "refresh melt" CMD state, and possibly cancel a + * pending operation thereof. + * + * @param cls closure, must be a `struct RefreshMeltState`. + * @param cmd the command which is being cleaned up. + */ +static void +refresh_melt_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RefreshMeltState *rms = cls; + + if (NULL != rms->rmh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + rms->is->ip, rms->is->commands[rms->is->ip].label); + TALER_EXCHANGE_refresh_melt_cancel (rms->rmh); + rms->rmh = NULL; + } + if (NULL != rms->retry_task) + { + GNUNET_SCHEDULER_cancel (rms->retry_task); + rms->retry_task = NULL; + } + if (NULL != rms->fresh_pks) + { + for (unsigned int i = 0; i < rms->num_fresh_coins; i++) + GNUNET_CRYPTO_rsa_public_key_free (rms->fresh_pks[i].key.rsa_public_key); + } + GNUNET_free_non_null (rms->fresh_pks); + rms->fresh_pks = NULL; + GNUNET_free_non_null (rms->refresh_data); + rms->refresh_data = NULL; + rms->refresh_data_length = 0; + GNUNET_free_non_null (rms->melt_fresh_amounts); + GNUNET_free (rms); +} + + +/** + * Offer internal data to the "refresh melt" CMD. + * + * @param cls closure. + * @param[out] ret result (could be anything). + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +refresh_melt_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RefreshMeltState *rms = cls; + + if (index >= rms->num_fresh_coins) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + { + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]), + TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); + } +} + + +/** + * Parse list of amounts for melt operation. + * + * @param[in,out] rms where to store the list + * @param ap NULL-termianted list of amounts to be melted (one per fresh coin) + * @return #GNUNET_OK on success + */ +static int +parse_amounts (struct RefreshMeltState *rms, + va_list ap) +{ + unsigned int len; + unsigned int off; + const char *amount; + + len = 0; + off = 0; + while (NULL != (amount = va_arg (ap, const char *))) + { + if (len == off) + { + struct TALER_Amount a; + + GNUNET_array_grow (rms->melt_fresh_amounts, + len, + off + 16); + if (GNUNET_OK != + TALER_string_to_amount (amount, &a)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at index %u\n", + amount, off); + GNUNET_free (rms->melt_fresh_amounts); + rms->melt_fresh_amounts = NULL; + return GNUNET_SYSERR; + } + rms->melt_fresh_amounts[off++] = amount; + } + } + if (0 == off) + return GNUNET_OK; /* no amounts given == use defaults! */ + /* ensure NULL-termination */ + GNUNET_array_grow (rms->melt_fresh_amounts, + len, + off + 1); + return GNUNET_OK; +} + + +/** + * Create a "refresh melt" command. + * + * @param label command label. + * @param coin_reference reference to a command + * that will provide a coin to refresh. + * @param expected_response_code expected HTTP code. + * @param ... NULL-terminated list of amounts to be melted + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refresh_melt (const char *label, + const char *coin_reference, + unsigned int expected_response_code, + ...) +{ + struct RefreshMeltState *rms; + va_list ap; + + rms = GNUNET_new (struct RefreshMeltState); + rms->coin_reference = coin_reference; + rms->expected_response_code = expected_response_code; + va_start (ap, expected_response_code); + GNUNET_assert (GNUNET_OK == + parse_amounts (rms, ap)); + va_end (ap); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = rms, + .run = &refresh_melt_run, + .cleanup = &refresh_melt_cleanup, + .traits = &refresh_melt_traits + }; + + return cmd; + } +} + + +/** + * Create a "refresh melt" CMD that does TWO /refresh/melt + * requests. This was needed to test the replay of a valid melt + * request, see #5312. + * + * @param label command label + * @param coin_reference reference to a command that will provide + * a coin to refresh + * @param expected_response_code expected HTTP code + * @param ... NULL-terminated list of amounts to be melted + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refresh_melt_double (const char *label, + const char *coin_reference, + unsigned int expected_response_code, + ...) +{ + struct RefreshMeltState *rms; + va_list ap; + + rms = GNUNET_new (struct RefreshMeltState); + rms->coin_reference = coin_reference; + rms->expected_response_code = expected_response_code; + rms->double_melt = GNUNET_YES; + va_start (ap, expected_response_code); + GNUNET_assert (GNUNET_OK == + parse_amounts (rms, ap)); + va_end (ap); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = rms, + .run = &refresh_melt_run, + .cleanup = &refresh_melt_cleanup, + .traits = &refresh_melt_traits + }; + + return cmd; + } +} + + +/** + * Modify a "refresh melt" command to enable retries. + * + * @param cmd command + * @return modified command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refresh_melt_with_retry (struct TALER_TESTING_Command cmd) +{ + struct RefreshMeltState *rms; + + GNUNET_assert (&refresh_melt_run == cmd.run); + rms = cmd.cls; + rms->do_retry = GNUNET_YES; + return cmd; +} + + +/** + * Offer internal data from a "refresh reveal" CMD. + * + * @param cls closure. + * @param[out] ret result (could be anything). + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +refresh_reveal_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct RefreshRevealState *rrs = cls; + unsigned int num_coins = rrs->num_fresh_coins; +#define NUM_TRAITS ((num_coins * 4) + 3) + struct TALER_TESTING_Trait traits[NUM_TRAITS]; + + /* Making coin privs traits */ + for (unsigned int i = 0; ifresh_coins[i].coin_priv); + + /* Making denom pubs traits */ + for (unsigned int i = 0; ifresh_coins[i].pk); + + /* Making denom sigs traits */ + for (unsigned int i = 0; ifresh_coins[i].sig); + /* blinding key traits */ + for (unsigned int i = 0; ifresh_coins[i].blinding_key), + + /* number of fresh coins */ + traits[(num_coins * 4)] = TALER_TESTING_make_trait_uint + (0, &rrs->num_fresh_coins); + + /* whole array of fresh coins */ + traits[(num_coins * 4) + 1] + = TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins), + + /* end of traits */ + traits[(num_coins * 4) + 2] = TALER_TESTING_trait_end (); + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create a "refresh reveal" command. + * + * @param label command label. + * @param melt_reference reference to a "refresh melt" command. + * @param expected_response_code expected HTTP response code. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refresh_reveal (const char *label, + const char *melt_reference, + unsigned int expected_response_code) +{ + struct RefreshRevealState *rrs; + + rrs = GNUNET_new (struct RefreshRevealState); + rrs->melt_reference = melt_reference; + rrs->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = rrs, + .label = label, + .run = &refresh_reveal_run, + .cleanup = &refresh_reveal_cleanup, + .traits = &refresh_reveal_traits + }; + + return cmd; + } +} + + +/** + * Modify a "refresh reveal" command to enable retries. + * + * @param cmd command + * @return modified command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd) +{ + struct RefreshRevealState *rrs; + + GNUNET_assert (&refresh_reveal_run == cmd.run); + rrs = cmd.cls; + rrs->do_retry = GNUNET_YES; + return cmd; +} + + +/** + * Create a "refresh link" command. + * + * @param label command label. + * @param reveal_reference reference to a "refresh reveal" CMD. + * @param expected_response_code expected HTTP response code + * @return the "refresh link" command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refresh_link (const char *label, + const char *reveal_reference, + unsigned int expected_response_code) +{ + struct RefreshLinkState *rrs; + + rrs = GNUNET_new (struct RefreshLinkState); + rrs->reveal_reference = reveal_reference; + rrs->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = rrs, + .label = label, + .run = &refresh_link_run, + .cleanup = &refresh_link_cleanup + }; + + return cmd; + } +} + + +/** + * Modify a "refresh link" command to enable retries. + * + * @param cmd command + * @return modified command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refresh_link_with_retry (struct TALER_TESTING_Command cmd) +{ + struct RefreshLinkState *rls; + + GNUNET_assert (&refresh_link_run == cmd.run); + rls = cmd.cls; + rls->do_retry = GNUNET_YES; + return cmd; +} diff --git a/src/testing/testing_api_cmd_refund.c b/src/testing/testing_api_cmd_refund.c new file mode 100644 index 000000000..0150086e0 --- /dev/null +++ b/src/testing/testing_api_cmd_refund.c @@ -0,0 +1,332 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_refund.c + * @brief Implement the /refund test command, plus other + * corollary commands (?). + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * State for a "refund" CMD. + */ +struct RefundState +{ + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Amount to be refunded. + */ + const char *refund_amount; + + /** + * Expected refund fee. + */ + const char *refund_fee; + + /** + * Reference to any command that can provide a coin to refund. + */ + const char *coin_reference; + + /** + * Refund transaction identifier. + */ + uint64_t refund_transaction_id; + + /** + * Connection to the exchange. + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * Handle to the refund operation. + */ + struct TALER_EXCHANGE_RefundHandle *rh; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * Check the result for the refund request, just check if the + * response code is acceptable. + * + * @param cls closure + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param exchange_pub public key the exchange + * used for signing @a obj. + * @param obj response object. + */ +static void +refund_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const json_t *obj) +{ + + struct RefundState *rs = cls; + struct TALER_TESTING_Command *refund_cmd; + + refund_cmd = &rs->is->commands[rs->is->ip]; + rs->rh = NULL; + if (rs->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s in %s:%u\n", + http_status, + refund_cmd->label, + __FILE__, + __LINE__); + json_dumpf (obj, stderr, 0); + TALER_TESTING_interpreter_fail (rs->is); + return; + } + TALER_TESTING_interpreter_next (rs->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +refund_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct RefundState *rs = cls; + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + struct TALER_CoinSpendPublicKeyP coin; + const json_t *contract_terms; + struct GNUNET_HashCode h_contract_terms; + struct TALER_Amount refund_fee; + struct TALER_Amount refund_amount; + const struct TALER_MerchantPrivateKeyP *merchant_priv; + const struct TALER_TESTING_Command *coin_cmd; + + rs->exchange = is->exchange; + rs->is = is; + + if (GNUNET_OK != + TALER_string_to_amount (rs->refund_amount, + &refund_amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u/%s\n", + rs->refund_amount, + is->ip, + cmd->label); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_string_to_amount (rs->refund_fee, + &refund_fee)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u/%s\n", + rs->refund_fee, + is->ip, + cmd->label); + TALER_TESTING_interpreter_fail (is); + return; + } + + coin_cmd = TALER_TESTING_interpreter_lookup_command (is, + rs->coin_reference); + if (NULL == coin_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_contract_terms (coin_cmd, + 0, + &contract_terms)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_JSON_hash (contract_terms, + &h_contract_terms)); + + /* Hunting for a coin .. */ + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (coin_cmd, + 0, + &coin_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin.eddsa_pub); + if (GNUNET_OK != + TALER_TESTING_get_trait_merchant_priv (coin_cmd, + 0, + &merchant_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + rs->rh = TALER_EXCHANGE_refund (rs->exchange, + &refund_amount, + &refund_fee, + &h_contract_terms, + &coin, + rs->refund_transaction_id, + merchant_priv, + &refund_cb, + rs); + GNUNET_assert (NULL != rs->rh); +} + + +/** + * Free the state from a "refund" CMD, and possibly cancel + * a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +refund_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct RefundState *rs = cls; + + if (NULL != rs->rh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + rs->is->ip, + cmd->label); + TALER_EXCHANGE_refund_cancel (rs->rh); + rs->rh = NULL; + } + GNUNET_free (rs); +} + + +/** + * Create a "refund" command. + * + * @param label command label. + * @param expected_response_code expected HTTP status code. + * @param refund_amount the amount to ask a refund for. + * @param refund_fee expected refund fee. + * @param coin_reference reference to a command that can + * provide a coin to be refunded. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refund (const char *label, + unsigned int expected_response_code, + const char *refund_amount, + const char *refund_fee, + const char *coin_reference) +{ + struct RefundState *rs; + + rs = GNUNET_new (struct RefundState); + + rs->expected_response_code = expected_response_code; + rs->refund_amount = refund_amount; + rs->refund_fee = refund_fee; + rs->coin_reference = coin_reference; + { + struct TALER_TESTING_Command cmd = { + .cls = rs, + .label = label, + .run = &refund_run, + .cleanup = &refund_cleanup + }; + + return cmd; + } +} + + +/** + * Create a "refund" command, allow to specify refund transaction + * id. Mainly used to create conflicting requests. + * + * @param label command label. + * @param expected_response_code expected HTTP status code. + * @param refund_amount the amount to ask a refund for. + * @param refund_fee expected refund fee. + * @param coin_reference reference to a command that can + * provide a coin to be refunded. + * @param refund_transaction_id transaction id to use + * in the request. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_refund_with_id + (const char *label, + unsigned int expected_response_code, + const char *refund_amount, + const char *refund_fee, + const char *coin_reference, + uint64_t refund_transaction_id) +{ + struct RefundState *rs; + + rs = GNUNET_new (struct RefundState); + rs->expected_response_code = expected_response_code; + rs->refund_amount = refund_amount; + rs->refund_fee = refund_fee; + rs->coin_reference = coin_reference; + rs->refund_transaction_id = refund_transaction_id; + { + struct TALER_TESTING_Command cmd = { + .cls = rs, + .label = label, + .run = &refund_run, + .cleanup = &refund_cleanup + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_serialize_keys.c b/src/testing/testing_api_cmd_serialize_keys.c new file mode 100644 index 000000000..296a2ddc7 --- /dev/null +++ b/src/testing/testing_api_cmd_serialize_keys.c @@ -0,0 +1,295 @@ +/* + This file is part of TALER + (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_serialize_keys.c + * @brief Lets tests use the keys serialization API. + * @author Marcello Stanisci + */ +#include "platform.h" +#include +#include "taler_testing_lib.h" + + +/** + * Internal state for a serialize-keys CMD. + */ +struct SerializeKeysState +{ + /** + * Serialized keys. + */ + json_t *keys; + + /** + * Exchange URL. Needed because the exchange gets disconnected + * from, after keys serialization. This value is then needed by + * subsequent commands that have to reconnect to the exchagne. + */ + char *exchange_url; +}; + + +/** + * Internal state for a connect-with-state CMD. + */ +struct ConnectWithStateState +{ + + /** + * Reference to a CMD that offers a serialized key-state + * that will be used in the reconnection. + */ + const char *state_reference; + + /** + * If set to GNUNET_YES, then the /keys callback has already + * been passed the control to the next CMD. This is necessary + * because it is not uncommon that the /keys callback gets + * invoked multiple times, and without this flag, we would keep + * going "next" CMD upon every invocation (causing impredictable + * behaviour as for the instruction pointer.) + */ + unsigned int consumed; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +serialize_keys_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct SerializeKeysState *sks = cls; + + sks->keys = TALER_EXCHANGE_serialize_data (is->exchange); + if (NULL == sks->keys) + TALER_TESTING_interpreter_fail (is); + + sks->exchange_url = GNUNET_strdup + (TALER_EXCHANGE_get_base_url (is->exchange)); + TALER_EXCHANGE_disconnect (is->exchange); + is->exchange = NULL; + is->working = GNUNET_NO; + TALER_TESTING_interpreter_next (is); +} + + +/** + * Cleanup the state of a "serialize keys" CMD. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +serialize_keys_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct SerializeKeysState *sks = cls; + + if (NULL != sks->keys) + { + json_decref (sks->keys); + } + GNUNET_free_non_null (sks->exchange_url); + GNUNET_free (sks); +} + + +/** + * Offer serialized keys as trait. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +serialize_keys_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct SerializeKeysState *sks = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_exchange_keys (0, sks->keys), + TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, + sks->exchange_url), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +connect_with_state_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct ConnectWithStateState *cwss = cls; + const struct TALER_TESTING_Command *state_cmd; + const json_t *serialized_keys; + const char *exchange_url; + + /* This command usually gets rescheduled after serialized + * reconnection. */ + if (GNUNET_YES == cwss->consumed) + { + TALER_TESTING_interpreter_next (is); + return; + } + + cwss->is = is; + state_cmd = TALER_TESTING_interpreter_lookup_command + (is, cwss->state_reference); + + /* Command providing serialized keys not found. */ + if (NULL == state_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_exchange_keys (state_cmd, + 0, + &serialized_keys)); + { + char *dump; + + dump = json_dumps (serialized_keys, + JSON_INDENT (1)); + TALER_LOG_DEBUG ("Serialized key-state: %s\n", + dump); + free (dump); + } + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_url (state_cmd, + TALER_TESTING_UT_EXCHANGE_BASE_URL, + &exchange_url)); + is->exchange = TALER_EXCHANGE_connect (is->ctx, + exchange_url, + TALER_TESTING_cert_cb, + cwss, + TALER_EXCHANGE_OPTION_DATA, + serialized_keys, + TALER_EXCHANGE_OPTION_END); + cwss->consumed = GNUNET_YES; +} + + +/** + * Cleanup the state of a "connect with state" CMD. Just + * a placeholder to avoid jumping on an invalid address. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +connect_with_state_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct ConnectWithStateState *cwss = cls; + + GNUNET_free (cwss); +} + + +/** + * Make a serialize-keys CMD. It will ask for + * keys serialization __and__ disconnect from the + * exchange. + * + * @param label CMD label + * @return the CMD. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_serialize_keys (const char *label) +{ + struct SerializeKeysState *sks; + + sks = GNUNET_new (struct SerializeKeysState); + { + struct TALER_TESTING_Command cmd = { + .cls = sks, + .label = label, + .run = serialize_keys_run, + .cleanup = serialize_keys_cleanup, + .traits = serialize_keys_traits + }; + + return cmd; + } +} + + +/** + * Make a connect-with-state CMD. This command + * will use a serialized key state to reconnect + * to the exchange. + * + * @param label command label + * @param state_reference label of a CMD offering + * a serialized key state. + * @return the CMD. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_connect_with_state (const char *label, + const char *state_reference) +{ + struct ConnectWithStateState *cwss; + + cwss = GNUNET_new (struct ConnectWithStateState); + cwss->state_reference = state_reference; + cwss->consumed = GNUNET_NO; + { + struct TALER_TESTING_Command cmd = { + .cls = cwss, + .label = label, + .run = connect_with_state_run, + .cleanup = connect_with_state_cleanup + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_signal.c b/src/testing/testing_api_cmd_signal.c new file mode 100644 index 000000000..b2116ebf6 --- /dev/null +++ b/src/testing/testing_api_cmd_signal.c @@ -0,0 +1,115 @@ +/* + This file is part of TALER + (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_signal.c + * @brief command(s) to send signals to processes. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * State for a "signal" CMD. + */ +struct SignalState +{ + /** + * The process to send the signal to. + */ + struct GNUNET_OS_Process *process; + + /** + * The signal to send to the process. + */ + int signal; +}; + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +signal_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct SignalState *ss = cls; + + GNUNET_break (0 == GNUNET_OS_process_kill + (ss->process, ss->signal)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Signaling '%d'..\n", + ss->signal); + sleep (6); + TALER_TESTING_interpreter_next (is); +} + + +/** + * Cleanup the state from a "signal" CMD. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +signal_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct SignalState *ss = cls; + + GNUNET_free (ss); +} + + +/** + * Create a "signal" CMD. + * + * @param label command label. + * @param process handle to the process to signal. + * @param signal signal to send. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_signal (const char *label, + struct GNUNET_OS_Process *process, + int signal) +{ + struct SignalState *ss; + + ss = GNUNET_new (struct SignalState); + ss->process = process; + ss->signal = signal; + + + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &signal_run, + .cleanup = &signal_cleanup + }; + + return cmd; +} diff --git a/src/testing/testing_api_cmd_sleep.c b/src/testing/testing_api_cmd_sleep.c new file mode 100644 index 000000000..91c13a1e2 --- /dev/null +++ b/src/testing/testing_api_cmd_sleep.c @@ -0,0 +1,133 @@ +/* + This file is part of TALER + (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_sleep.c + * @brief command(s) to sleep for a bit + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * State for a "sleep" CMD. + */ +struct SleepState +{ + + /** + * How long should we sleep? + */ + unsigned int duration; +}; + + +/** + * No traits to offer, just provide a stub to be called when + * some CMDs iterates through the list of all the commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the trait to return. + * @return #GNUNET_OK on success. + */ +static int +sleep_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + (void) cls; + (void) ret; + (void) trait; + (void) index; + return GNUNET_NO; +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +sleep_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct SleepState *ss = cls; + + sleep (ss->duration); + TALER_TESTING_interpreter_next (is); +} + + +/** + * Cleanup the state from a "sleep" CMD. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +sleep_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct SleepState *ss = cls; + + (void) cmd; + GNUNET_free (ss); +} + + +/** + * Sleep for @a duration_s seconds. + * + * @param label command label. + * @param duration_s number of seconds to sleep + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_sleep (const char *label, + unsigned int duration_s) +{ + struct SleepState *ss; + + ss = GNUNET_new (struct SleepState); + ss->duration = duration_s; + + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &sleep_run, + .cleanup = &sleep_cleanup, + .traits = &sleep_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_sleep.c */ diff --git a/src/testing/testing_api_cmd_status.c b/src/testing/testing_api_cmd_status.c new file mode 100644 index 000000000..1c652b6d4 --- /dev/null +++ b/src/testing/testing_api_cmd_status.c @@ -0,0 +1,237 @@ +/* + This file is part of TALER + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#include "taler_testing_lib.h" + + +/** + * State for a "status" CMD. + */ +struct StatusState +{ + /** + * Label to the command which created the reserve to check, + * needed to resort the reserve key. + */ + const char *reserve_reference; + + /** + * Handle to the "reserve status" operation. + */ + struct TALER_EXCHANGE_ReserveStatusHandle *rsh; + + /** + * Expected reserve balance. + */ + const char *expected_balance; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * Check that the reserve balance and HTTP response code are + * both acceptable. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param json original JSON response from the exchange + * @param balance current balance in the reserve, NULL on error. + * @param history_length number of entries in the transaction + * history, 0 on error. + * @param history detailed transaction history, NULL on error. + */ +static void +reserve_status_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const json_t *json, + const struct TALER_Amount *balance, + unsigned int history_length, + const struct TALER_EXCHANGE_ReserveHistory *history) +{ + struct StatusState *ss = cls; + struct TALER_Amount eb; + + ss->rsh = NULL; + if (ss->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected HTTP response code: %d in %s:%u\n", + http_status, + __FILE__, + __LINE__); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (ss->expected_balance, + &eb)); + + if (0 != TALER_amount_cmp (&eb, + balance)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected amount in reserve: %s\n", + TALER_amount_to_string (balance)); + TALER_TESTING_interpreter_fail (ss->is); + return; + } + + /** + * TODO (#6049): We should check that reserve history is consistent. Every + * command which relates to reserve 'x' should be added in a linked list of + * all commands that relate to the same reserve 'x'. + * + * API-wise, any command that relates to a reserve should offer a + * method called e.g. "compare_with_history" that takes an element + * of the array returned by "/reserve/status" and checks if that + * element correspond to itself (= the command exposing the check- + * method). + * + * IDEA: Maybe realize this via another trait, some kind of + * "reserve history update trait" which returns information about + * how the command changes the history (provided only by commands + * that change reserve balances)? + */// + TALER_TESTING_interpreter_next (ss->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command being executed. + * @param is the interpreter state. + */ +static void +status_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct StatusState *ss = cls; + const struct TALER_TESTING_Command *create_reserve; + const struct TALER_ReservePublicKeyP *reserve_pubp; + + ss->is = is; + create_reserve + = TALER_TESTING_interpreter_lookup_command (is, + ss->reserve_reference); + + if (NULL == create_reserve) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_pub (create_reserve, + 0, + &reserve_pubp)) + { + GNUNET_break (0); + TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + ss->rsh = TALER_EXCHANGE_reserve_status (is->exchange, + reserve_pubp, + &reserve_status_cb, + ss); +} + + +/** + * Cleanup the state from a "reserve status" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +status_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct StatusState *ss = cls; + + if (NULL != ss->rsh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + ss->is->ip, + cmd->label); + TALER_EXCHANGE_reserve_status_cancel (ss->rsh); + ss->rsh = NULL; + } + GNUNET_free (ss); +} + + +/** + * Create a "reserve status" command. + * + * @param label the command label. + * @param reserve_reference reference to the reserve to check. + * @param expected_balance expected balance for the reserve. + * @param expected_response_code expected HTTP response code. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_status (const char *label, + const char *reserve_reference, + const char *expected_balance, + unsigned int expected_response_code) +{ + struct StatusState *ss; + + GNUNET_assert (NULL != reserve_reference); + ss = GNUNET_new (struct StatusState); + ss->reserve_reference = reserve_reference; + ss->expected_balance = expected_balance; + ss->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = ss, + .label = label, + .run = &status_run, + .cleanup = &status_cleanup + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_track.c b/src/testing/testing_api_cmd_track.c new file mode 100644 index 000000000..e5c7160f6 --- /dev/null +++ b/src/testing/testing_api_cmd_track.c @@ -0,0 +1,805 @@ +/* + This file is part of TALER + Copyright (C) 2014-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file testing/testing_api_cmd_track.c + * @brief Implement the testing CMDs for the /track operations. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + +/** + * State for a "track transaction" CMD. + */ +struct TrackTransactionState +{ + + /** + * If non NULL, will provide a WTID to be compared against + * the one returned by the "track transaction" operation. + */ + const char *bank_transfer_reference; + + /** + * The WTID associated by the transaction being tracked. + */ + struct TALER_WireTransferIdentifierRawP wtid; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Reference to any operation that can provide a transaction. + * Will be the transaction to track. + */ + const char *transaction_reference; + + /** + * Index of the coin involved in the transaction. Recall: + * at the exchange, the tracking is done _per coin_. + */ + unsigned int coin_index; + + /** + * Handle to the "track transaction" pending operation. + */ + struct TALER_EXCHANGE_TrackTransactionHandle *tth; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * State for a "track transfer" CMD. + */ +struct TrackTransferState +{ + + /** + * Expected amount for the WTID being tracked. + */ + const char *expected_total_amount; + + /** + * Expected fee for this WTID. + */ + const char *expected_wire_fee; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Reference to any operation that can provide a WTID. + * Will be the WTID to track. + */ + const char *wtid_reference; + + /** + * Reference to any operation that can provide wire details. + * Those wire details will then be matched against the credit + * bank account of the tracked WTID. This way we can test that + * a wire transfer paid back one particular bank account. + */ + const char *wire_details_reference; + + /** + * Reference to any operation that can provide an amount. + * This way we can check that the transferred amount matches + * our expectations. + */ + const char *total_amount_reference; + + /** + * Index to the WTID to pick, in case @a wtid_reference has + * many on offer. + */ + unsigned int index; + + /** + * Handle to a pending "track transfer" operation. + */ + struct TALER_EXCHANGE_TrackTransferHandle *tth; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * Checks what is returned by the "track transaction" operation. + * Checks that the HTTP response code is acceptable, and - if the + * right reference is non NULL - that the wire transfer subject + * line matches our expectations. + * + * @param cls closure. + * @param http_status HTTP status code we got. + * @param ec taler-specific error code. + * @param exchange_pub public key of the exchange + * @param json original json reply (may include signatures, those + * have then been validated already). + * @param wtid wire transfer identifier, NULL if exchange did not + * execute the transaction yet. + * @param execution_time actual or planned execution time for the + * wire transfer. + * @param coin_contribution contribution to the total amount of + * the deposited coin (can be NULL). + */ +static void +deposit_wtid_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const json_t *json, + const struct TALER_WireTransferIdentifierRawP *wtid, + struct GNUNET_TIME_Absolute execution_time, + const struct TALER_Amount *coin_contribution) +{ + struct TrackTransactionState *tts = cls; + struct TALER_TESTING_Interpreter *is = tts->is; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + + (void) coin_contribution; + (void) exchange_pub; + tts->tth = NULL; + if (tts->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s in %s:%u\n", + http_status, + cmd->label, + __FILE__, + __LINE__); + json_dumpf (json, stderr, 0); + TALER_TESTING_interpreter_fail (is); + return; + } + switch (http_status) + { + case MHD_HTTP_OK: + tts->wtid = *wtid; + if (NULL != tts->bank_transfer_reference) + { + const struct TALER_TESTING_Command *bank_transfer_cmd; + const struct TALER_WireTransferIdentifierRawP *wtid_want; + + /* _this_ wire transfer subject line. */ + bank_transfer_cmd = TALER_TESTING_interpreter_lookup_command + (is, tts->bank_transfer_reference); + if (NULL == bank_transfer_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != + TALER_TESTING_get_trait_wtid + (bank_transfer_cmd, 0, &wtid_want)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + /* Compare that expected and gotten subjects match. */ + if (0 != GNUNET_memcmp (wtid, + wtid_want)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + } + break; + case MHD_HTTP_ACCEPTED: + /* allowed, nothing to check here */ + break; + case MHD_HTTP_NOT_FOUND: + /* allowed, nothing to check here */ + break; + default: + GNUNET_break (0); + break; + } + TALER_TESTING_interpreter_next (tts->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +track_transaction_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct TrackTransactionState *tts = cls; + const struct TALER_TESTING_Command *transaction_cmd; + const struct TALER_CoinSpendPrivateKeyP *coin_priv; + struct TALER_CoinSpendPublicKeyP coin_pub; + const json_t *contract_terms; + const json_t *wire_details; + struct GNUNET_HashCode h_wire_details; + struct GNUNET_HashCode h_contract_terms; + const struct TALER_MerchantPrivateKeyP *merchant_priv; + + tts->is = is; + transaction_cmd + = TALER_TESTING_interpreter_lookup_command (tts->is, + tts->transaction_reference); + if (NULL == transaction_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_priv (transaction_cmd, + tts->coin_index, + &coin_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + + GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, + &coin_pub.eddsa_pub); + + /* Get the strings.. */ + if (GNUNET_OK != + TALER_TESTING_get_trait_wire_details (transaction_cmd, + 0, + &wire_details)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + + if (GNUNET_OK != + TALER_TESTING_get_trait_contract_terms (transaction_cmd, + 0, + &contract_terms)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + + if ( (NULL == wire_details) || + (NULL == contract_terms) ) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + + /* Should not fail here, json has been parsed already */ + GNUNET_assert + ( (GNUNET_OK == + TALER_JSON_merchant_wire_signature_hash (wire_details, + &h_wire_details)) && + (GNUNET_OK == + TALER_JSON_hash (contract_terms, + &h_contract_terms)) ); + + if (GNUNET_OK != + TALER_TESTING_get_trait_merchant_priv (transaction_cmd, + 0, + &merchant_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + + tts->tth = TALER_EXCHANGE_track_transaction (is->exchange, + merchant_priv, + &h_wire_details, + &h_contract_terms, + &coin_pub, + &deposit_wtid_cb, + tts); + GNUNET_assert (NULL != tts->tth); +} + + +/** + * Cleanup the state from a "track transaction" CMD, and possibly + * cancel a operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +track_transaction_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct TrackTransactionState *tts = cls; + + if (NULL != tts->tth) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + tts->is->ip, + cmd->label); + TALER_EXCHANGE_track_transaction_cancel (tts->tth); + tts->tth = NULL; + } + GNUNET_free (tts); +} + + +/** + * Offer internal data from a "track transaction" CMD. + * + * @param cls closure. + * @param[out] ret result (could be anything). + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static int +track_transaction_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct TrackTransactionState *tts = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_wtid (0, &tts->wtid), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Create a "track transaction" command. + * + * @param label the command label. + * @param transaction_reference reference to a deposit operation, + * will be used to get the input data for the track. + * @param coin_index index of the coin involved in the transaction. + * @param expected_response_code expected HTTP response code. + * @param bank_transfer_reference reference to a command that + * can offer a WTID so as to check that against what WTID + * the tracked operation has. Set as NULL if not needed. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_track_transaction (const char *label, + const char *transaction_reference, + unsigned int coin_index, + unsigned int expected_response_code, + const char *bank_transfer_reference) +{ + struct TrackTransactionState *tts; + + tts = GNUNET_new (struct TrackTransactionState); + tts->transaction_reference = transaction_reference; + tts->expected_response_code = expected_response_code; + tts->bank_transfer_reference = bank_transfer_reference; + tts->coin_index = coin_index; + { + struct TALER_TESTING_Command cmd = { + .cls = tts, + .label = label, + .run = &track_transaction_run, + .cleanup = &track_transaction_cleanup, + .traits = &track_transaction_traits + }; + + return cmd; + } +} + + +/** + * Cleanup the state for a "track transfer" CMD, and possibly + * cancel a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +track_transfer_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + + struct TrackTransferState *tts = cls; + + if (NULL != tts->tth) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + tts->is->ip, + cmd->label); + TALER_EXCHANGE_track_transfer_cancel (tts->tth); + tts->tth = NULL; + } + GNUNET_free (tts); +} + + +/** + * Check whether the HTTP response code from a "track transfer" + * operation is acceptable, and all other values like total amount, + * wire fees and hashed wire details as well. + * + * @param cls closure. + * @param http_status HTTP status code we got. + * @param ec taler-specific error code. + * @param exchange_pub public key the exchange used for signing + * the response. + * @param json original json reply (may include signatures, those + * have then been validated already). + * @param h_wire hash of the wire transfer address the transfer + * went to, or NULL on error. + * @param execution_time time when the exchange claims to have + * performed the wire transfer. + * @param total_amount total amount of the wire transfer, or NULL + * if the exchange could not provide any @a wtid (set only + * if @a http_status is "200 OK"). + * @param wire_fee wire fee that was charged by the exchange. + * @param details_length length of the @a details array. + * @param details array with details about the combined + * transactions. + */ +static void +track_transfer_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const json_t *json, + const struct GNUNET_HashCode *h_wire, + struct GNUNET_TIME_Absolute execution_time, + const struct TALER_Amount *total_amount, + const struct TALER_Amount *wire_fee, + unsigned int details_length, + const struct TALER_TrackTransferDetails *details) +{ + struct TrackTransferState *tts = cls; + struct TALER_TESTING_Interpreter *is = tts->is; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + struct TALER_Amount expected_amount; + + (void) exchange_pub; + tts->tth = NULL; + if (tts->expected_response_code != http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u to command %s in %s:%u\n", + http_status, + cmd->label, + __FILE__, + __LINE__); + json_dumpf (json, stderr, 0); + TALER_TESTING_interpreter_fail (is); + return; + } + + switch (http_status) + { + case MHD_HTTP_OK: + if (NULL == tts->expected_total_amount) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (NULL == tts->expected_wire_fee) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != + TALER_string_to_amount (tts->expected_total_amount, + &expected_amount)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (0 != TALER_amount_cmp (total_amount, + &expected_amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Total amount missmatch to command %s - " + "%s vs %s\n", + cmd->label, + TALER_amount_to_string (total_amount), + TALER_amount_to_string (&expected_amount)); + json_dumpf (json, stderr, 0); + fprintf (stderr, "\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != + TALER_string_to_amount (tts->expected_wire_fee, + &expected_amount)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (0 != TALER_amount_cmp (wire_fee, + &expected_amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire fee missmatch to command %s\n", + cmd->label); + json_dumpf (json, stderr, 0); + TALER_TESTING_interpreter_fail (is); + return; + } + + /** + * Optionally checking: (1) wire-details for this transfer + * match the ones from a referenced "deposit" operation - + * or any operation that could provide wire-details. (2) + * Total amount for this transfer matches the one from any + * referenced command that could provide one. + */if (NULL != tts->wire_details_reference) + { + const struct TALER_TESTING_Command *wire_details_cmd; + const json_t *wire_details; + struct GNUNET_HashCode h_wire_details; + + if (NULL == (wire_details_cmd + = TALER_TESTING_interpreter_lookup_command + (is, tts->wire_details_reference))) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != + TALER_TESTING_get_trait_wire_details (wire_details_cmd, + 0, + &wire_details)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_assert + (GNUNET_OK == + TALER_JSON_merchant_wire_signature_hash (wire_details, + &h_wire_details)); + + if (0 != GNUNET_memcmp (&h_wire_details, + h_wire)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire hash missmath to command %s\n", + cmd->label); + json_dumpf (json, stderr, 0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + if (NULL != tts->total_amount_reference) + { + const struct TALER_TESTING_Command *total_amount_cmd; + const struct TALER_Amount *total_amount_from_reference; + + if (NULL == (total_amount_cmd + = TALER_TESTING_interpreter_lookup_command + (is, tts->total_amount_reference))) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (GNUNET_OK != + TALER_TESTING_get_trait_amount_obj (total_amount_cmd, + 0, + &total_amount_from_reference)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + if (0 != TALER_amount_cmp (total_amount, + total_amount_from_reference)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Amount missmath to command %s\n", + cmd->label); + json_dumpf (json, stderr, 0); + TALER_TESTING_interpreter_fail (is); + return; + } + } + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command under execution. + * @param is the interpreter state. + */ +static void +track_transfer_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + /* looking for a wtid to track .. */ + struct TrackTransferState *tts = cls; + struct TALER_WireTransferIdentifierRawP wtid; + const struct TALER_WireTransferIdentifierRawP *wtid_ptr; + + /* If no reference is given, we'll use a all-zeros + * WTID */ + memset (&wtid, 0, sizeof (wtid)); + wtid_ptr = &wtid; + + tts->is = is; + if (NULL != tts->wtid_reference) + { + const struct TALER_TESTING_Command *wtid_cmd; + + wtid_cmd = TALER_TESTING_interpreter_lookup_command + (tts->is, tts->wtid_reference); + + if (NULL == wtid_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + + if (GNUNET_OK != TALER_TESTING_get_trait_wtid + (wtid_cmd, tts->index, &wtid_ptr)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (tts->is); + return; + } + GNUNET_assert (NULL != wtid_ptr); + } + tts->tth = TALER_EXCHANGE_track_transfer (is->exchange, + wtid_ptr, + &track_transfer_cb, + tts); + GNUNET_assert (NULL != tts->tth); +} + + +/** + * Make a "track transfer" CMD where no "expected"-arguments, + * except the HTTP response code, are given. The best use case + * is when what matters to check is the HTTP response code, e.g. + * when a bogus WTID was passed. + * + * @param label the command label + * @param wtid_reference reference to any command which can provide + * a wtid. If NULL is given, then a all zeroed WTID is + * used that will at 99.9999% probability NOT match any + * existing WTID known to the exchange. + * @param index index number of the WTID to track, in case there + * are multiple on offer. + * @param expected_response_code expected HTTP response code. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_track_transfer_empty (const char *label, + const char *wtid_reference, + unsigned int index, + unsigned int expected_response_code) +{ + struct TrackTransferState *tts; + + tts = GNUNET_new (struct TrackTransferState); + tts->wtid_reference = wtid_reference; + tts->index = index; + tts->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = tts, + .label = label, + .run = &track_transfer_run, + .cleanup = &track_transfer_cleanup + }; + + return cmd; + } +} + + +/** + * Make a "track transfer" command, specifying which amount and + * wire fee are expected. + * + * @param label the command label. + * @param wtid_reference reference to any command which can provide + * a wtid. Will be the one tracked. + * @param index in case there are multiple WTID offered, this + * parameter selects a particular one. + * @param expected_response_code expected HTTP response code. + * @param expected_total_amount how much money we expect being moved + * with this wire-transfer. + * @param expected_wire_fee expected wire fee. + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_track_transfer (const char *label, + const char *wtid_reference, + unsigned int index, + unsigned int expected_response_code, + const char *expected_total_amount, + const char *expected_wire_fee) +{ + struct TrackTransferState *tts; + + tts = GNUNET_new (struct TrackTransferState); + tts->wtid_reference = wtid_reference; + tts->index = index; + tts->expected_response_code = expected_response_code; + tts->expected_total_amount = expected_total_amount; + tts->expected_wire_fee = expected_wire_fee; + { + struct TALER_TESTING_Command cmd = { + .cls = tts, + .label = label, + .run = &track_transfer_run, + .cleanup = &track_transfer_cleanup + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_track.c */ diff --git a/src/testing/testing_api_cmd_wait.c b/src/testing/testing_api_cmd_wait.c new file mode 100644 index 000000000..5558f7b95 --- /dev/null +++ b/src/testing/testing_api_cmd_wait.c @@ -0,0 +1,133 @@ +/* + This file is part of TALER + (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_wait.c + * @brief command(s) to wait on some process + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * Cleanup the state from a "wait service" CMD. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +wait_service_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + (void) cls; + (void) cmd; + /* nothing to clean. */ + return; +} + + +/** + * No traits to offer, just provide a stub to be called when + * some CMDs iterates through the list of all the commands. + * + * @param cls closure. + * @param[out] ret result. + * @param trait name of the trait. + * @param index index number of the trait to return. + * @return #GNUNET_OK on success. + */ +static int +wait_service_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + (void) cls; + (void) ret; + (void) trait; + (void) index; + return GNUNET_NO; +} + + +/** + * Run a "wait service" CMD. + * + * @param cls closure. + * @param cmd the command being run. + * @param is the interpreter state. + */ +static void +wait_service_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + unsigned int iter = 0; + const char *url = cmd->cls; + char *wget_cmd; + + GNUNET_asprintf (&wget_cmd, + "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null", + url); + do + { + fprintf (stderr, "."); + + if (10 == iter++) + { + TALER_LOG_ERROR ("Could not reach the proxied service\n"); + TALER_TESTING_interpreter_fail (is); + GNUNET_free (wget_cmd); + return; + } + } + while (0 != system (wget_cmd)); + + GNUNET_free (wget_cmd); + TALER_TESTING_interpreter_next (is); +} + + +/** + * This CMD simply tries to connect via HTTP to the + * service addressed by @a url. It attemps 10 times + * before giving up and make the test fail. + * + * @param label label for the command. + * @param url complete URL to connect to. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_wait_service (const char *label, + const char *url) +{ + struct TALER_TESTING_Command cmd = { + .label = label, + .run = wait_service_run, + .cleanup = wait_service_cleanup, + .traits = wait_service_traits, + .cls = (void *) url + }; + + return cmd; +} + + +/* end of testing_api_cmd_sleep.c */ diff --git a/src/testing/testing_api_cmd_wire.c b/src/testing/testing_api_cmd_wire.c new file mode 100644 index 000000000..5d1f2454f --- /dev/null +++ b/src/testing/testing_api_cmd_wire.c @@ -0,0 +1,234 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_wire.c + * @brief command for testing /wire. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" + + +/** + * State for a "wire" CMD. + */ +struct WireState +{ + + /** + * Handle to the /wire operation. + */ + struct TALER_EXCHANGE_WireHandle *wh; + + /** + * Which wire-method we expect is offered by the exchange. + */ + const char *expected_method; + + /** + * Flag indicating if the expected method is actually + * offered. + */ + unsigned int method_found; + + /** + * Fee we expect is charged for this wire-transfer method. + */ + const char *expected_fee; + + /** + * Expected HTTP response code. + */ + unsigned int expected_response_code; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; +}; + + +/** + * Check whether the HTTP response code is acceptable, that + * the expected wire method is offered by the exchange, and + * that the wire fee is acceptable too. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param accounts_len length of the @a accounts array. + * @param accounts list of wire accounts of the exchange, + * NULL on error. + */ +static void +wire_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + unsigned int accounts_len, + const struct TALER_EXCHANGE_WireAccount *accounts) +{ + struct WireState *ws = cls; + struct TALER_TESTING_Command *cmd = \ + &ws->is->commands[ws->is->ip]; + struct TALER_Amount expected_fee; + + TALER_LOG_DEBUG ("Checking parsed /wire response\n"); + ws->wh = NULL; + if (ws->expected_response_code != http_status) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ws->is); + return; + } + + if (MHD_HTTP_OK == http_status) + { + for (unsigned int i = 0; iexpected_method, + method)) + { + ws->method_found = GNUNET_OK; + if (NULL != ws->expected_fee) + { + GNUNET_assert + (GNUNET_OK == + TALER_string_to_amount (ws->expected_fee, + &expected_fee)); + const struct TALER_EXCHANGE_WireAggregateFees *waf; + for (waf = accounts[i].fees; + NULL != waf; + waf = waf->next) + { + if (0 != TALER_amount_cmp (&waf->wire_fee, + &expected_fee)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire fee missmatch to command %s\n", + cmd->label); + TALER_TESTING_interpreter_fail (ws->is); + GNUNET_free (method); + return; + } + } + } + } + TALER_LOG_DEBUG ("Freeing method '%s'\n", + method); + GNUNET_free (method); + } + if (GNUNET_OK != ws->method_found) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "/wire does not offer method '%s'\n", + ws->expected_method); + TALER_TESTING_interpreter_fail (ws->is); + return; + } + } + + TALER_TESTING_interpreter_next (ws->is); +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +wire_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct WireState *ws = cls; + ws->is = is; + ws->wh = TALER_EXCHANGE_wire (is->exchange, + &wire_cb, + ws); +} + + +/** + * Cleanup the state of a "wire" CMD, and possibly cancel a + * pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +wire_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct WireState *ws = cls; + + if (NULL != ws->wh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %u (%s) did not complete\n", + ws->is->ip, + cmd->label); + TALER_EXCHANGE_wire_cancel (ws->wh); + ws->wh = NULL; + } + GNUNET_free (ws); +} + + +/** + * Create a "wire" command. + * + * @param label the command label. + * @param expected_method which wire-transfer method is expected + * to be offered by the exchange. + * @param expected_fee the fee the exchange should charge. + * @param expected_response_code the HTTP response the exchange + * should return. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_wire (const char *label, + const char *expected_method, + const char *expected_fee, + unsigned int expected_response_code) +{ + struct WireState *ws; + + ws = GNUNET_new (struct WireState); + ws->expected_method = expected_method; + ws->expected_fee = expected_fee; + ws->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = ws, + .label = label, + .run = &wire_run, + .cleanup = &wire_cleanup + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c new file mode 100644 index 000000000..b62420557 --- /dev/null +++ b/src/testing/testing_api_cmd_withdraw.c @@ -0,0 +1,534 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_cmd_withdraw.c + * @brief main interpreter loop for testcases + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" +#include "backoff.h" + + +/** + * State for a "withdraw" CMD. + */ +struct WithdrawState +{ + + /** + * Which reserve should we withdraw from? + */ + const char *reserve_reference; + + /** + * String describing the denomination value we should withdraw. + * A corresponding denomination key must exist in the exchange's + * offerings. Can be NULL if @e pk is set instead. + */ + struct TALER_Amount amount; + + /** + * If @e amount is NULL, this specifies the denomination key to + * use. Otherwise, this will be set (by the interpreter) to the + * denomination PK matching @e amount. + */ + struct TALER_EXCHANGE_DenomPublicKey *pk; + + /** + * Exchange base URL. Only used as offered trait. + */ + char *exchange_url; + + /** + * Interpreter state (during command). + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Set (by the interpreter) to the exchange's signature over the + * coin's public key. + */ + struct TALER_DenominationSignature sig; + + /** + * Private key material of the coin, set by the interpreter. + */ + struct TALER_PlanchetSecretsP ps; + + /** + * Withdraw handle (while operation is running). + */ + struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh; + + /** + * Task scheduled to try later. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * How long do we wait until we retry? + */ + struct GNUNET_TIME_Relative backoff; + + /** + * Expected HTTP response code to the request. + */ + unsigned int expected_response_code; + + /** + * Was this command modified via + * #TALER_TESTING_cmd_withdraw_with_retry to + * enable retries? + */ + int do_retry; +}; + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the commaind being run. + * @param is interpreter state. + */ +static void +withdraw_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is); + + +/** + * Task scheduled to re-try #withdraw_run. + * + * @param cls a `struct WithdrawState` + */ +static void +do_retry (void *cls) +{ + struct WithdrawState *ws = cls; + + ws->retry_task = NULL; + withdraw_run (ws, + NULL, + ws->is); +} + + +/** + * "reserve withdraw" operation callback; checks that the + * response code is expected and store the exchange signature + * in the state. + * + * @param cls closure. + * @param http_status HTTP response code. + * @param ec taler-specific error code. + * @param sig signature over the coin, NULL on error. + * @param full_response raw response. + */ +static void +reserve_withdraw_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const struct TALER_DenominationSignature *sig, + const json_t *full_response) +{ + struct WithdrawState *ws = cls; + struct TALER_TESTING_Interpreter *is = ws->is; + + ws->wsh = NULL; + if (ws->expected_response_code != http_status) + { + if (GNUNET_YES == ws->do_retry) + { + if ( (0 == http_status) || + (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || + (TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS == ec) || + (TALER_EC_WITHDRAW_RESERVE_UNKNOWN == ec) || + (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Retrying withdraw failed with %u/%d\n", + http_status, + (int) ec); + /* on DB conflicts, do not use backoff */ + if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) + ws->backoff = GNUNET_TIME_UNIT_ZERO; + else + ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff); + ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff, + &do_retry, + ws); + return; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d to command %s in %s:%u\n", + http_status, + (int) ec, + TALER_TESTING_interpreter_get_current_label (is), + __FILE__, + __LINE__); + json_dumpf (full_response, + stderr, + 0); + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + switch (http_status) + { + case MHD_HTTP_OK: + if (NULL == sig) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + ws->sig.rsa_signature + = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature); + break; + case MHD_HTTP_FORBIDDEN: + /* nothing to check */ + break; + case MHD_HTTP_CONFLICT: + /* nothing to check */ + break; + case MHD_HTTP_NOT_FOUND: + /* nothing to check */ + break; + default: + /* Unsupported status code (by test harness) */ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Withdraw test command does not support status code %u\n", + http_status); + GNUNET_break (0); + break; + } + TALER_TESTING_interpreter_next (is); +} + + +/** + * Run the command. + */ +static void +withdraw_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct WithdrawState *ws = cls; + const struct TALER_ReservePrivateKeyP *rp; + const struct TALER_TESTING_Command *create_reserve; + const struct TALER_EXCHANGE_DenomPublicKey *dpk; + + (void) cmd; + create_reserve = TALER_TESTING_interpreter_lookup_command + (is, ws->reserve_reference); + if (NULL == create_reserve) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (create_reserve, + 0, + &rp)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_planchet_setup_random (&ws->ps); + ws->is = is; + + dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange), + &ws->amount); + if (NULL == dpk) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to determine denomination key at %s\n", + (NULL != cmd) ? cmd->label : ""); + GNUNET_assert (0); + } + else + { + /* We copy the denomination key, as re-querying /keys + * would free the old one. */ + ws->pk = TALER_EXCHANGE_copy_denomination_key (dpk); + } + + ws->wsh = TALER_EXCHANGE_reserve_withdraw (is->exchange, + ws->pk, + rp, + &ws->ps, + &reserve_withdraw_cb, + ws); + if (NULL == ws->wsh) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } +} + + +/** + * Free the state of a "withdraw" CMD, and possibly cancel + * a pending operation thereof. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +withdraw_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct WithdrawState *ws = cls; + + if (NULL != ws->wsh) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command %s did not complete\n", + cmd->label); + TALER_EXCHANGE_reserve_withdraw_cancel (ws->wsh); + ws->wsh = NULL; + } + if (NULL != ws->retry_task) + { + GNUNET_SCHEDULER_cancel (ws->retry_task); + ws->retry_task = NULL; + } + if (NULL != ws->sig.rsa_signature) + { + GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature); + ws->sig.rsa_signature = NULL; + } + if (NULL != ws->pk) + { + TALER_EXCHANGE_destroy_denomination_key (ws->pk); + ws->pk = NULL; + } + GNUNET_free_non_null (ws->exchange_url); + GNUNET_free (ws); +} + + +/** + * Offer internal data to a "withdraw" CMD state to other + * commands. + * + * @param cls closure + * @param[out] ret result (could be anything) + * @param trait name of the trait + * @param index index number of the object to offer. + * @return #GNUNET_OK on success + */ +static int +withdraw_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct WithdrawState *ws = cls; + const struct TALER_TESTING_Command *reserve_cmd; + const struct TALER_ReservePrivateKeyP *reserve_priv; + const struct TALER_ReservePublicKeyP *reserve_pub; + + /* We offer the reserve key where these coins were withdrawn + * from. */ + reserve_cmd = TALER_TESTING_interpreter_lookup_command + (ws->is, ws->reserve_reference); + + if (NULL == reserve_cmd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ws->is); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_priv (reserve_cmd, + 0, + &reserve_priv)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ws->is); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_TESTING_get_trait_reserve_pub (reserve_cmd, + 0, + &reserve_pub)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (ws->is); + return GNUNET_SYSERR; + } + if (NULL == ws->exchange_url) + ws->exchange_url + = GNUNET_strdup (TALER_EXCHANGE_get_base_url (ws->is->exchange)); + { + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_coin_priv (0 /* only one coin */, + &ws->ps.coin_priv), + TALER_TESTING_make_trait_blinding_key (0 /* only one coin */, + &ws->ps.blinding_key), + TALER_TESTING_make_trait_denom_pub (0 /* only one coin */, + ws->pk), + TALER_TESTING_make_trait_denom_sig (0 /* only one coin */, + &ws->sig), + TALER_TESTING_make_trait_reserve_priv (0, + reserve_priv), + TALER_TESTING_make_trait_reserve_pub (0, + reserve_pub), + TALER_TESTING_make_trait_amount_obj (0, + &ws->amount), + TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, + ws->exchange_url), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); + } +} + + +/** + * Create a withdraw command, letting the caller specify + * the desired amount as string. + * + * @param label command label. + * @param reserve_reference command providing us with a reserve to withdraw from + * @param amount how much we withdraw. + * @param expected_response_code which HTTP response code + * we expect from the exchange. + * @return the withdraw command to be executed by the interpreter. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_withdraw_amount (const char *label, + const char *reserve_reference, + const char *amount, + unsigned int expected_response_code) +{ + struct WithdrawState *ws; + + ws = GNUNET_new (struct WithdrawState); + ws->reserve_reference = reserve_reference; + if (GNUNET_OK != + TALER_string_to_amount (amount, + &ws->amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %s\n", + amount, + label); + GNUNET_assert (0); + } + ws->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = ws, + .label = label, + .run = &withdraw_run, + .cleanup = &withdraw_cleanup, + .traits = &withdraw_traits + }; + + return cmd; + } +} + + +/** + * Create withdraw command, letting the caller specify the + * amount by a denomination key. + * + * @param label command label. + * @param reserve_reference reference to the reserve to withdraw + * from; will provide reserve priv to sign the request. + * @param dk denomination public key. + * @param expected_response_code expected HTTP response code. + * + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_withdraw_denomination (const char *label, + const char *reserve_reference, + const struct + TALER_EXCHANGE_DenomPublicKey *dk, + unsigned int expected_response_code) +{ + struct WithdrawState *ws; + + if (NULL == dk) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Denomination key not specified at %s\n", + label); + GNUNET_assert (0); + } + ws = GNUNET_new (struct WithdrawState); + ws->reserve_reference = reserve_reference; + ws->pk = TALER_EXCHANGE_copy_denomination_key (dk); + ws->expected_response_code = expected_response_code; + { + struct TALER_TESTING_Command cmd = { + .cls = ws, + .label = label, + .run = &withdraw_run, + .cleanup = &withdraw_cleanup, + .traits = &withdraw_traits + }; + + return cmd; + } +} + + +/** + * Modify a withdraw command to enable retries when the + * reserve is not yet full or we get other transient + * errors from the exchange. + * + * @param cmd a withdraw command + * @return the command with retries enabled + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd) +{ + struct WithdrawState *ws; + + GNUNET_assert (&withdraw_run == cmd.run); + ws = cmd.cls; + ws->do_retry = GNUNET_YES; + return cmd; +} + + +/* end of testing_api_cmd_withdraw.c */ diff --git a/src/testing/testing_api_helpers_auditor.c b/src/testing/testing_api_helpers_auditor.c new file mode 100644 index 000000000..ccfa5e24e --- /dev/null +++ b/src/testing/testing_api_helpers_auditor.c @@ -0,0 +1,229 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_helpers_auditor.c + * @brief helper functions + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_testing_lib.h" +#include "taler_auditor_service.h" + + +/** + * Closure for #cleanup_auditor. + */ +struct CleanupContext +{ + /** + * Where we find the state to clean up. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Next cleanup routine to call, NULL for none. + */ + GNUNET_SCHEDULER_TaskCallback fcb; + + /** + * Closure for @e fcb + */ + void *fcb_cls; +}; + + +/** + * Function to clean up the auditor connection. + * + * @param cls a `struct CleanupContext` + */ +static void +cleanup_auditor (void *cls) +{ + struct CleanupContext *cc = cls; + struct TALER_TESTING_Interpreter *is = cc->is; + + TALER_AUDITOR_disconnect (is->auditor); + is->auditor = NULL; + if (NULL != cc->fcb) + cc->fcb (cc->fcb_cls); + GNUNET_free (cc); +} + + +/** + * Closure for #auditor_main_wrapper() + */ +struct MainWrapperContext +{ + /** + * Main function to launch. + */ + TALER_TESTING_Main main_cb; + + /** + * Closure for @e main_cb. + */ + void *main_cb_cls; + + /** + * Configuration we use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Name of the configuration file. + */ + const char *config_filename; + +}; + + +/** + * Function called with information about the auditor. + * + * @param cls closure + * @param vi basic information about the auditor + * @param compat protocol compatibility information + */ +static void +auditor_version_cb (void *cls, + const struct TALER_AUDITOR_VersionInformation *vi, + enum TALER_AUDITOR_VersionCompatibility compat) +{ + struct TALER_TESTING_Interpreter *is = cls; + + if (TALER_AUDITOR_VC_MATCH != compat) + { + TALER_TESTING_interpreter_fail (is); + return; + } + + is->auditor_working = GNUNET_YES; +} + + +/** + * Setup the @a is 'auditor' member before running the main test loop. + * + * @param cls must be a `struct MainWrapperContext *` + * @param[in,out] is interpreter state to setup + */ +static void +auditor_main_wrapper (void *cls, + struct TALER_TESTING_Interpreter *is) +{ + struct MainWrapperContext *mwc = cls; + struct CleanupContext *cc; + char *auditor_base_url; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (mwc->cfg, + "auditor", + "BASE_URL", + &auditor_base_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "auditor", + "BASE_URL"); + return; + } + + is->auditor = TALER_AUDITOR_connect (is->ctx, + auditor_base_url, + &auditor_version_cb, + is); + GNUNET_free (auditor_base_url); + + if (NULL == is->auditor) + { + GNUNET_break (0); + return; + } + + cc = GNUNET_new (struct CleanupContext); + cc->is = is; + cc->fcb = is->final_cleanup_cb; + cc->fcb_cls = is->final_cleanup_cb_cls; + is->final_cleanup_cb = cleanup_auditor; + is->final_cleanup_cb_cls = cc; + mwc->main_cb (mwc->main_cb_cls, + is); +} + + +/** + * Install signal handlers plus schedules the main wrapper + * around the "run" method. + * + * @param cls our `struct MainWrapperContext` + * @param cfg configuration we use + * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. + * non-GNUNET_OK codes are #GNUNET_SYSERR most of the + * times. + */ +static int +setup_with_cfg (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct MainWrapperContext *mwc = cls; + struct TALER_TESTING_SetupContext setup_ctx = { + .config_filename = mwc->config_filename, + .main_cb = &auditor_main_wrapper, + .main_cb_cls = mwc + }; + + mwc->cfg = cfg; + return TALER_TESTING_setup_with_auditor_and_exchange_cfg (&setup_ctx, + cfg); +} + + +/** + * Install signal handlers plus schedules the main wrapper + * around the "run" method. + * + * @param main_cb the "run" method which contains all the + * commands. + * @param main_cb_cls a closure for "run", typically NULL. + * @param config_filename configuration filename. + * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. + * non-GNUNET_OK codes are #GNUNET_SYSERR most of the + * times. + */ +int +TALER_TESTING_auditor_setup (TALER_TESTING_Main main_cb, + void *main_cb_cls, + const char *config_filename) +{ + struct MainWrapperContext mwc = { + .main_cb = main_cb, + .main_cb_cls = main_cb_cls, + .config_filename = config_filename + }; + + return GNUNET_CONFIGURATION_parse_and_run (config_filename, + &setup_with_cfg, + &mwc); +} + + +/* end of testing_auditor_api_helpers.c */ diff --git a/src/testing/testing_api_helpers_bank.c b/src/testing/testing_api_helpers_bank.c new file mode 100644 index 000000000..dbe89e63c --- /dev/null +++ b/src/testing/testing_api_helpers_bank.c @@ -0,0 +1,494 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_helpers_bank.c + * @brief convenience functions for bank tests. + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" + +#define BANK_FAIL() \ + do {GNUNET_break (0); return NULL; } while (0) + + +/** + * Runs the Fakebank by guessing / extracting the portnumber + * from the base URL. + * + * @param bank_url bank's base URL. + * @return the fakebank process handle, or NULL if any + * error occurs. + */ +struct TALER_FAKEBANK_Handle * +TALER_TESTING_run_fakebank (const char *bank_url) +{ + const char *port; + long pnum; + struct TALER_FAKEBANK_Handle *fakebankd; + + port = strrchr (bank_url, + (unsigned char) ':'); + if (NULL == port) + pnum = 80; + else + pnum = strtol (port + 1, NULL, 10); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Starting Fakebank on port %u (%s)\n", + (unsigned int) pnum, + bank_url); + fakebankd = TALER_FAKEBANK_start ((uint16_t) pnum); + if (NULL == fakebankd) + { + GNUNET_break (0); + return NULL; + } + return fakebankd; +} + + +/** + * Look for substring in a programs' name. + * + * @param prog program's name to look into + * @param marker chunk to find in @a prog + * @return #GNUNET_YES if @a marker is present, otherwise #GNUNET_NO + */ +int +TALER_TESTING_has_in_name (const char *prog, + const char *marker) +{ + size_t name_pos; + size_t pos; + + if (! prog || ! marker) + return GNUNET_NO; + + pos = 0; + name_pos = 0; + while (prog[pos]) + { + if ('/' == prog[pos]) + name_pos = pos + 1; + pos++; + } + if (name_pos == pos) + return GNUNET_YES; + return (NULL != strstr (prog + name_pos, marker)); +} + + +/** + * Start the (Python) bank process. Assume the port + * is available and the database is clean. Use the "prepare + * bank" function to do such tasks. + * + * @param config_filename configuration filename. + * @param bank_url base URL of the bank, used by `wget' to check + * that the bank was started right. + * @return the process, or NULL if the process could not + * be started. + */ +struct GNUNET_OS_Process * +TALER_TESTING_run_bank (const char *config_filename, + const char *bank_url) +{ + struct GNUNET_OS_Process *bank_proc; + unsigned int iter; + char *wget_cmd; + char *database; + char *serve_cfg; + char *serve_arg; + struct GNUNET_CONFIGURATION_Handle *cfg; + + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (cfg, + config_filename)) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + exit (77); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "bank", + "database", + &database)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "bank", + "database"); + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + exit (77); + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "bank", + "serve", + &serve_cfg)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "bank", + "serve"); + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (database); + exit (77); + } + GNUNET_CONFIGURATION_destroy (cfg); + + serve_arg = "serve-http"; + if (0 != strcmp ("http", serve_cfg)) + serve_arg = "serve-uwsgi"; + GNUNET_free (serve_cfg); + bank_proc = GNUNET_OS_start_process + (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-bank-manage-testing", + "taler-bank-manage-testing", + config_filename, + database, + serve_arg, NULL); + GNUNET_free (database); + if (NULL == bank_proc) + { + BANK_FAIL (); + } + + GNUNET_asprintf (&wget_cmd, + "wget -q -t 2 -T 1 %s -o /dev/null -O /dev/null", + bank_url); + + /* give child time to start and bind against the socket */ + fprintf (stderr, + "Waiting for `taler-bank-manage' to be ready (via %s)\n", wget_cmd); + iter = 0; + do + { + if (10 == iter) + { + fprintf ( + stderr, + "Failed to launch `taler-bank-manage' (or `wget')\n"); + GNUNET_OS_process_kill (bank_proc, + SIGTERM); + GNUNET_OS_process_wait (bank_proc); + GNUNET_OS_process_destroy (bank_proc); + GNUNET_free (wget_cmd); + BANK_FAIL (); + } + fprintf (stderr, "."); + sleep (1); + iter++; + } + while (0 != system (wget_cmd)); + GNUNET_free (wget_cmd); + fprintf (stderr, "\n"); + + return bank_proc; + +} + + +/** + * Prepare the bank execution. Check if the port is available + * and reset database. + * + * @param config_filename configuration file name. + * @param config_section section of the configuration with the exchange's account + * @param[out] bc set to the bank's configuration data + * @return the base url, or NULL upon errors. Must be freed + * by the caller. + */ +int +TALER_TESTING_prepare_bank (const char *config_filename, + const char *config_section, + struct TALER_TESTING_BankConfiguration *bc) +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + unsigned long long port; + struct GNUNET_OS_Process *dbreset_proc; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + char *database; + char *exchange_payto_uri; + + cfg = GNUNET_CONFIGURATION_create (); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (cfg, config_filename)) + { + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "bank", + "DATABASE", + &database)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "bank", + "DATABASE"); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + config_section, + "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */ + &exchange_payto_uri)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + config_section, + "URL"); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "bank", + "HTTP_PORT", + &port)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "bank", + "HTTP_PORT"); + GNUNET_CONFIGURATION_destroy (cfg); + GNUNET_free (database); + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + GNUNET_NETWORK_test_port_free (IPPROTO_TCP, + (uint16_t) port)) + { + fprintf (stderr, + "Required port %llu not available, skipping.\n", + port); + GNUNET_break (0); + GNUNET_free (database); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + + /* DB preparation */ + if (NULL == + (dbreset_proc = GNUNET_OS_start_process ( + GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-bank-manage", + "taler-bank-manage", + "-c", config_filename, + "--with-db", database, + "django", + "flush", + "--no-input", NULL))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to flush the bank db.\n"); + GNUNET_free (database); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + GNUNET_free (database); + + if (GNUNET_SYSERR == + GNUNET_OS_process_wait_status (dbreset_proc, + &type, + &code)) + { + GNUNET_OS_process_destroy (dbreset_proc); + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + if ( (type == GNUNET_OS_PROCESS_EXITED) && + (0 != code) ) + { + fprintf (stderr, + "Failed to setup database\n"); + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + if ( (type != GNUNET_OS_PROCESS_EXITED) || + (0 != code) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected error running `taler-bank-manage django flush'!\n"); + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + GNUNET_OS_process_destroy (dbreset_proc); + if (GNUNET_OK != + TALER_BANK_auth_parse_cfg (cfg, + config_section, + &bc->exchange_auth)) + { + GNUNET_break (0); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + GNUNET_CONFIGURATION_destroy (cfg); + bc->exchange_payto = exchange_payto_uri; + bc->user42_payto = "payto://x-taler-bank/localhost/42"; + bc->user43_payto = "payto://x-taler-bank/localhost/43"; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Using pybank %s on port %u\n", + bc->exchange_auth.wire_gateway_url, + (unsigned int) port); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n", + bc->exchange_payto); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", + bc->user42_payto); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", + bc->user43_payto); + return GNUNET_OK; +} + + +/** + * Prepare launching a fakebank. Check that the configuration + * file has the right option, and that the port is available. + * If everything is OK, return the configuration data of the fakebank. + * + * @param config_filename configuration file to use + * @param config_section which account to use (must match x-taler-bank) + * @param[out] bc set to the bank's configuration data + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_prepare_fakebank (const char *config_filename, + const char *config_section, + struct TALER_TESTING_BankConfiguration *bc) +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + unsigned long long fakebank_port; + char *exchange_payto_uri; + + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, + config_filename)) + return GNUNET_SYSERR; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "BANK", + "HTTP_PORT", + &fakebank_port)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "BANK", + "HTTP_PORT"); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + config_section, + "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */ + &exchange_payto_uri)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + config_section, + "URL"); + GNUNET_CONFIGURATION_destroy (cfg); + return GNUNET_SYSERR; + } + bc->exchange_auth.method = TALER_BANK_AUTH_NONE; + { + char *exchange_xtalerbank_account; + + exchange_xtalerbank_account + = TALER_xtalerbank_account_from_payto (exchange_payto_uri); + if (NULL == exchange_xtalerbank_account) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_asprintf (&bc->exchange_auth.wire_gateway_url, + "http://localhost:%u/%s/", + (unsigned int) fakebank_port, + exchange_xtalerbank_account); + GNUNET_free (exchange_xtalerbank_account); + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Using fakebank %s on port %u\n", + bc->exchange_auth.wire_gateway_url, + (unsigned int) fakebank_port); + + GNUNET_CONFIGURATION_destroy (cfg); + if (GNUNET_OK != + TALER_TESTING_url_port_free (bc->exchange_auth.wire_gateway_url)) + { + GNUNET_free (bc->exchange_auth.wire_gateway_url); + bc->exchange_auth.wire_gateway_url = NULL; + return GNUNET_SYSERR; + } + /* Now we know it's the fake bank, for purpose of authentication, we + * don't have any auth. */ + bc->exchange_auth.method = TALER_BANK_AUTH_NONE; + bc->exchange_payto = exchange_payto_uri; + bc->user42_payto = "payto://x-taler-bank/localhost/42"; + bc->user43_payto = "payto://x-taler-bank/localhost/43"; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n", + bc->exchange_payto); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", + bc->user42_payto); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n", + bc->user43_payto); + return GNUNET_OK; +} + + +/** + * Allocate and return a piece of wire-details. Combines + * a @a payto -URL and adds some salt to create the JSON. + * + * @param payto payto://-URL to encapsulate + * @return JSON describing the account, including the + * payto://-URL of the account, must be manually decref'd + */ +json_t * +TALER_TESTING_make_wire_details (const char *payto) +{ + return json_pack ("{s:s, s:s}", + "url", payto, + "salt", + "test-salt (must be constant for aggregation tests)"); +} + + +/* end of testing_api_helpers_bank.c */ diff --git a/src/testing/testing_api_helpers_exchange.c b/src/testing/testing_api_helpers_exchange.c new file mode 100644 index 000000000..29c96db19 --- /dev/null +++ b/src/testing/testing_api_helpers_exchange.c @@ -0,0 +1,975 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @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 +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * Remove files from previous runs + * + * @param config_name configuration filename. + */ +void +TALER_TESTING_cleanup_files (const char *config_name) +{ + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse_and_run (config_name, + &TALER_TESTING_cleanup_files_cfg, + NULL)) + exit (77); +} + + +/** + * Remove files from previous runs + * + * @param cls NULL + * @param cfg configuration + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_cleanup_files_cfg (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *dir; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "exchange", + "KEYDIR", + &dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "KEYDIR"); + return GNUNET_SYSERR; + } + if (GNUNET_YES == + GNUNET_DISK_directory_test (dir, + GNUNET_NO)) + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_remove (dir)); + GNUNET_free (dir); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "exchange", + "REVOCATION_DIR", + &dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "REVOCATION_DIR"); + return GNUNET_SYSERR; + } + if (GNUNET_YES == + GNUNET_DISK_directory_test (dir, + GNUNET_NO)) + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_remove (dir)); + GNUNET_free (dir); + return GNUNET_OK; +} + + +/** + * Run `taler-exchange-keyup`. + * + * @param config_filename configuration file to use + * @param output_filename where to write the output for the auditor + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_run_keyup (const char *config_filename, + const char *output_filename) +{ + struct GNUNET_OS_Process *proc; + + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-keyup", + "taler-exchange-keyup", + "-c", config_filename, + "-o", output_filename, + NULL); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to run `taler-exchange-keyup`, is your PATH correct?\n"); + return GNUNET_SYSERR; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_destroy (proc); + return GNUNET_OK; +} + + +/** + * Run `taler-auditor-sign`. + * + * @param config_filename configuration file to use + * @param exchange_master_pub master public key of the exchange + * @param auditor_base_url what is the base URL of the auditor + * @param signdata_in where is the information from taler-exchange-keyup + * @param signdata_out where to write the output for the exchange + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_run_auditor_sign (const char *config_filename, + const char *exchange_master_pub, + const char *auditor_base_url, + const char *signdata_in, + const char *signdata_out) +{ + struct GNUNET_OS_Process *proc; + + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor-sign", + "taler-auditor-sign", + "-c", config_filename, + "-u", auditor_base_url, + "-m", exchange_master_pub, + "-r", signdata_in, + "-o", signdata_out, + NULL); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to run `taler-auditor-sign`, is your PATH correct?\n"); + return GNUNET_SYSERR; + } + GNUNET_OS_process_wait (proc); + GNUNET_OS_process_destroy (proc); + return GNUNET_OK; +} + + +/** + * Run `taler-auditor-exchange`. + * + * @param config_filename configuration file to use + * @param exchange_master_pub master public key of the exchange + * @param exchange_base_url what is the base URL of the exchange + * @param do_remove #GNUNET_NO to add exchange, #GNUNET_YES to remove + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_run_auditor_exchange (const char *config_filename, + const char *exchange_master_pub, + const char *exchange_base_url, + int do_remove) +{ + struct GNUNET_OS_Process *proc; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + + TALER_LOG_DEBUG ("Add exchange (%s,%s) to the auditor\n", + exchange_base_url, + exchange_master_pub); + + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor-exchange", + "taler-auditor-exchange", + "-c", config_filename, + "-u", exchange_base_url, + "-m", exchange_master_pub, + (GNUNET_YES == do_remove) + ? "-r" + : NULL, + NULL); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to run `taler-auditor-exchange`, is your PATH correct?\n"); + return GNUNET_SYSERR; + } + GNUNET_assert (GNUNET_OK == + GNUNET_OS_process_wait_status (proc, + &type, + &code)); + GNUNET_OS_process_destroy (proc); + if ( (0 != code) || + (GNUNET_OS_PROCESS_EXITED != type) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "taler-auditor-exchange terminated with error (%d/%d)\n", + (int) type, + (int) code); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Run `taler-exchange-dbinit -r` (reset exchange database). + * + * @param config_filename configuration file to use + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_exchange_db_reset (const char *config_filename) +{ + struct GNUNET_OS_Process *proc; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-dbinit", + "taler-exchange-dbinit", + "-c", config_filename, + "-r", + NULL); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n"); + return GNUNET_NO; + } + if (GNUNET_SYSERR == + GNUNET_OS_process_wait_status (proc, + &type, + &code)) + { + GNUNET_break (0); + GNUNET_OS_process_destroy (proc); + return GNUNET_SYSERR; + } + GNUNET_OS_process_destroy (proc); + if ( (type == GNUNET_OS_PROCESS_EXITED) && + (0 != code) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to setup (exchange) database, exit code %d\n", + (int) code); + return GNUNET_NO; + } + if ( (type != GNUNET_OS_PROCESS_EXITED) || + (0 != code) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected error (%d/%d) running `taler-exchange-dbinit'!\n", + (int) type, + (int) code); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Run `taler-auditor-dbinit -r` (reset auditor database). + * + * @param config_filename configuration file to use + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_auditor_db_reset (const char *config_filename) +{ + struct GNUNET_OS_Process *proc; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + + proc = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor-dbinit", + "taler-auditor-dbinit", + "-c", config_filename, + "-r", + NULL); + if (NULL == proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to run `taler-auditor-dbinit`, is your PATH correct?\n"); + return GNUNET_NO; + } + if (GNUNET_SYSERR == + GNUNET_OS_process_wait_status (proc, + &type, + &code)) + { + GNUNET_break (0); + GNUNET_OS_process_destroy (proc); + return GNUNET_SYSERR; + } + GNUNET_OS_process_destroy (proc); + if ( (type == GNUNET_OS_PROCESS_EXITED) && + (0 != code) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to setup (auditor) database, exit code %d\n", + (int) code); + return GNUNET_NO; + } + if ( (type != GNUNET_OS_PROCESS_EXITED) || + (0 != code) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected error (%d/%d) running `taler-auditor-dbinit'!\n", + (int) type, + (int) code); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Type of closure for + * #sign_keys_for_exchange. + */ +struct SignInfo +{ + /** + * Members will be set to the exchange configuration. + */ + struct TALER_TESTING_ExchangeConfiguration *ec; + + /** + * Name of the configuration file to use. + */ + const char *config_filename; + + /** + * Must be set to input file with the data to be signed before + * calling #TALER_TESTING_sign_keys_for_exchange. + */ + const char *auditor_sign_input_filename; +}; + + +/** + * Sign the keys for an exchange given configuration @a cfg. + * The information to be signed must be in a file "auditor.in". + * + * @param[in,out] cls a `struct SignInfo` with further paramters + * @param cfg configuration to use + * @return #GNUNET_OK on success + */ +static int +sign_keys_for_exchange (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct SignInfo *si = cls; + char *test_home_dir; + char *signed_keys_out; + char *exchange_master_pub; + int ret; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "BASE_URL", + &si->ec->exchange_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "exchange", + "BASE_URL"); + si->ec->exchange_url = NULL; + return GNUNET_NO; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "auditor", + "BASE_URL", + &si->ec->auditor_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "auditor", + "BASE_URL"); + GNUNET_free (si->ec->exchange_url); + si->ec->exchange_url = NULL; + si->ec->auditor_url = NULL; + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "paths", + "TALER_TEST_HOME", + &test_home_dir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "paths", + "TALER_TEST_HOME"); + ret = GNUNET_SYSERR; + goto fail; + } + + GNUNET_asprintf (&signed_keys_out, + "%s/.local/share/taler/auditors/auditor.out", + test_home_dir); + GNUNET_free (test_home_dir); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "MASTER_PUBLIC_KEY", + &exchange_master_pub)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "MASTER_PUBLIC_KEY"); + GNUNET_free (signed_keys_out); + ret = GNUNET_SYSERR; + goto fail; + } + if (GNUNET_OK != + TALER_TESTING_run_auditor_exchange (si->config_filename, + exchange_master_pub, + si->ec->exchange_url, + GNUNET_NO)) + { + GNUNET_free (signed_keys_out); + ret = GNUNET_NO; + goto fail; + } + + if (GNUNET_OK != + TALER_TESTING_run_auditor_sign (si->config_filename, + exchange_master_pub, + si->ec->auditor_url, + si->auditor_sign_input_filename, + signed_keys_out)) + { + GNUNET_free (signed_keys_out); + GNUNET_free (exchange_master_pub); + ret = GNUNET_NO; + goto fail; + } + GNUNET_free (signed_keys_out); + GNUNET_free (exchange_master_pub); + return GNUNET_OK; +fail: + GNUNET_free (si->ec->exchange_url); + GNUNET_free (si->ec->auditor_url); + si->ec->exchange_url = NULL; + si->ec->auditor_url = NULL; + return ret; +} + + +/** + * Prepare launching an exchange. Checks that the configured + * port is available, runs taler-exchange-keyup, + * taler-auditor-sign and taler-exchange-dbinit. Does NOT + * launch the exchange process itself. + * + * @param config_filename configuration file to use + * @param[out] ec will be set to the exchange configuration data + * @return #GNUNET_OK on success, #GNUNET_NO if test should be + * skipped, #GNUNET_SYSERR on test failure + */ +int +TALER_TESTING_prepare_exchange (const char *config_filename, + struct TALER_TESTING_ExchangeConfiguration *ec) +{ + struct SignInfo si = { + .config_filename = config_filename, + .ec = ec, + .auditor_sign_input_filename = "auditor.in" + }; + + if (GNUNET_OK != + TALER_TESTING_run_keyup (config_filename, + si.auditor_sign_input_filename)) + return GNUNET_NO; + if (GNUNET_OK != + TALER_TESTING_exchange_db_reset (config_filename)) + return GNUNET_NO; + if (GNUNET_OK != + TALER_TESTING_auditor_db_reset (config_filename)) + return GNUNET_NO; + if (GNUNET_OK != + GNUNET_CONFIGURATION_parse_and_run (config_filename, + &sign_keys_for_exchange, + &si)) + return GNUNET_NO; + return GNUNET_OK; +} + + +/** + * Find denomination key matching the given amount. + * + * @param keys array of keys to search + * @param amount coin value to look for + * @return NULL if no matching key was found + */ +const struct TALER_EXCHANGE_DenomPublicKey * +TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys, + const struct TALER_Amount *amount) +{ + struct GNUNET_TIME_Absolute now; + struct TALER_EXCHANGE_DenomPublicKey *pk; + char *str; + + now = GNUNET_TIME_absolute_get (); + for (unsigned int i = 0; inum_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; inum_denom_keys; i++) + { + pk = &keys->denom_keys[i]; + if ( (0 == TALER_amount_cmp (amount, + &pk->value)) && + ( (now.abs_value_us < pk->valid_from.abs_value_us) || + (now.abs_value_us > + pk->withdraw_valid_until.abs_value_us) ) ) + { + GNUNET_log + (GNUNET_ERROR_TYPE_WARNING, + "Have denomination key for `%s', but with wrong" + " expiration range %llu vs [%llu,%llu)\n", + str, + (unsigned long long) now.abs_value_us, + (unsigned long long) pk->valid_from.abs_value_us, + (unsigned long long) + pk->withdraw_valid_until.abs_value_us); + GNUNET_free (str); + return NULL; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No denomination key for amount %s found\n", + str); + GNUNET_free (str); + return NULL; +} + + +/** + * Wait for the exchange to have started. Waits for at + * most 10s, after that returns 77 to indicate an error. + * + * @param base_url what URL should we expect the exchange + * to be running at + * @return 0 on success + */ +int +TALER_TESTING_wait_exchange_ready (const char *base_url) +{ + char *wget_cmd; + unsigned int iter; + + GNUNET_asprintf (&wget_cmd, + "wget -q -t 1 -T 1 %skeys -o /dev/null -O /dev/null", + base_url); // make sure ends with '/' + /* give child time to start and bind against the socket */ + fprintf (stderr, + "Waiting for `taler-exchange-httpd' to be ready (check with: %s)\n", + wget_cmd); + iter = 0; + do + { + if (10 == iter) + { + fprintf (stderr, + "Failed to launch `taler-exchange-httpd' (or `wget')\n"); + GNUNET_free (wget_cmd); + return 77; + } + fprintf (stderr, ".\n"); + sleep (1); + iter++; + } + while (0 != system (wget_cmd)); + GNUNET_free (wget_cmd); + return 0; +} + + +/** + * Wait for the auditor to have started. Waits for at + * most 10s, after that returns 77 to indicate an error. + * + * @param base_url what URL should we expect the auditor + * to be running at + * @return 0 on success + */ +int +TALER_TESTING_wait_auditor_ready (const char *base_url) +{ + char *wget_cmd; + unsigned int iter; + + GNUNET_asprintf (&wget_cmd, + "wget -q -t 1 -T 1 %sversion -o /dev/null -O /dev/null", + base_url); // make sure ends with '/' + /* give child time to start and bind against the socket */ + fprintf (stderr, + "Waiting for `taler-auditor-httpd' to be ready\n"); + iter = 0; + do + { + if (10 == iter) + { + fprintf (stderr, + "Failed to launch `taler-auditor-httpd' (or `wget')\n"); + GNUNET_free (wget_cmd); + return 77; + } + fprintf (stderr, ".\n"); + sleep (1); + iter++; + } + while (0 != system (wget_cmd)); + GNUNET_free (wget_cmd); + return 0; +} + + +/** + * Initialize scheduler loop and curl context for the testcase + * including starting and stopping the exchange using the given + * configuration file. + * + * @param main_cb routine containing all the commands to run. + * @param main_cb_cls closure for @a main_cb, typically NULL. + * @param config_file configuration file for the test-suite. + * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. + * non-#GNUNET_OK codes are #GNUNET_SYSERR most of the + * time. + */ +int +TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb, + void *main_cb_cls, + const char *config_file) +{ + struct TALER_TESTING_SetupContext setup_ctx = { + .config_filename = config_file, + .main_cb = main_cb, + .main_cb_cls = main_cb_cls + }; + int result; + + result = + GNUNET_CONFIGURATION_parse_and_run (config_file, + &TALER_TESTING_setup_with_exchange_cfg, + &setup_ctx); + if (GNUNET_OK != result) + return result; + return GNUNET_OK; +} + + +/** + * Initialize scheduler loop and curl context for the test case + * including starting and stopping the exchange using the given + * configuration file. + * + * @param cls must be a `struct TALER_TESTING_SetupContext *` + * @param cfg configuration to use. + * @return #GNUNET_OK if no errors occurred. + */ +int +TALER_TESTING_setup_with_exchange_cfg (void *cls, + const struct + GNUNET_CONFIGURATION_Handle *cfg) +{ + const struct TALER_TESTING_SetupContext *setup_ctx = cls; + struct GNUNET_OS_Process *exchanged; + unsigned long long port; + char *serve; + char *base_url; + int result; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "SERVE", + &serve)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "SERVE"); + return GNUNET_NO; + } + + if (0 == strcmp ("tcp", serve)) + { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "exchange", + "PORT", + &port)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "PORT"); + GNUNET_free (serve); + return GNUNET_NO; + } + + if (GNUNET_OK != + GNUNET_NETWORK_test_port_free (IPPROTO_TCP, + (uint16_t) port)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Required port %llu not available, skipping.\n", + port); + GNUNET_free (serve); + return GNUNET_NO; + } + } + GNUNET_free (serve); + exchanged = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-httpd", + "taler-exchange-httpd", + "-c", setup_ctx->config_filename, + "-i", + NULL); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "BASE_URL", + &base_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "BASE_URL"); + return GNUNET_NO; + } + + if (0 != TALER_TESTING_wait_exchange_ready (base_url)) + { + GNUNET_free (base_url); + return 77; + } + GNUNET_free (base_url); + + /* NOTE: this call blocks. */ + result = TALER_TESTING_setup (setup_ctx->main_cb, + setup_ctx->main_cb_cls, + setup_ctx->config_filename, + exchanged, + GNUNET_YES); + GNUNET_break (0 == + GNUNET_OS_process_kill (exchanged, + SIGTERM)); + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (exchanged)); + GNUNET_OS_process_destroy (exchanged); + return result; +} + + +/** + * Initialize scheduler loop and curl context for the test case + * including starting and stopping the auditor and exchange using the + * given configuration file. + * + * @param cls must be a `struct TALER_TESTING_SetupContext *` + * @param cfg configuration to use. + * @return #GNUNET_OK if no errors occurred. + */ +int +TALER_TESTING_setup_with_auditor_and_exchange_cfg (void *cls, + const struct + GNUNET_CONFIGURATION_Handle * + cfg) +{ + const struct TALER_TESTING_SetupContext *setup_ctx = cls; + struct GNUNET_OS_Process *auditord; + unsigned long long port; + char *serve; + char *base_url; + int result; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "auditor", + "SERVE", + &serve)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "auditor", + "SERVE"); + return GNUNET_NO; + } + + if (0 == strcmp ("tcp", serve)) + { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "auditor", + "PORT", + &port)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "auditor", + "PORT"); + GNUNET_free (serve); + return GNUNET_NO; + } + + if (GNUNET_OK != + GNUNET_NETWORK_test_port_free (IPPROTO_TCP, + (uint16_t) port)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Required port %llu not available, skipping.\n", + port); + GNUNET_free (serve); + return GNUNET_NO; + } + } + GNUNET_free (serve); + auditord = GNUNET_OS_start_process (GNUNET_NO, + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-auditor-httpd", + "taler-auditor-httpd", + "-c", setup_ctx->config_filename, + NULL); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "auditor", + "BASE_URL", + &base_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "auditor", + "BASE_URL"); + return GNUNET_NO; + } + + if (0 != TALER_TESTING_wait_auditor_ready (base_url)) + { + GNUNET_free (base_url); + GNUNET_break (0 == + GNUNET_OS_process_kill (auditord, + SIGTERM)); + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (auditord)); + GNUNET_OS_process_destroy (auditord); + return 77; + } + GNUNET_free (base_url); + + /* NOTE: this call blocks. */ + result = TALER_TESTING_setup_with_exchange_cfg ((void *) setup_ctx, + cfg); + GNUNET_break (0 == + GNUNET_OS_process_kill (auditord, + SIGTERM)); + GNUNET_break (GNUNET_OK == + GNUNET_OS_process_wait (auditord)); + GNUNET_OS_process_destroy (auditord); + return result; +} + + +/** + * Initialize scheduler loop and curl context for the test case + * including starting and stopping the auditor and exchange using the + * given configuration file. + * + * @param main_cb main method. + * @param main_cb_cls main method closure. + * @param config_file configuration file name. Is is used + * by both this function and the exchange itself. In the + * first case it gives out the exchange port number and + * the exchange base URL so as to check whether the port + * is available and the exchange responds when requested + * at its base URL. + * @return #GNUNET_OK if no errors occurred. + */ +int +TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb, + void *main_cb_cls, + const char *config_file) +{ + struct TALER_TESTING_SetupContext setup_ctx = { + .config_filename = config_file, + .main_cb = main_cb, + .main_cb_cls = main_cb_cls + }; + + return GNUNET_CONFIGURATION_parse_and_run (config_file, + & + TALER_TESTING_setup_with_auditor_and_exchange_cfg, + &setup_ctx); +} + + +/** + * Test port in URL string for availability. + * + * @param url URL to extract port from, 80 is default + * @return #GNUNET_OK if the port is free + */ +int +TALER_TESTING_url_port_free (const char *url) +{ + const char *port; + long pnum; + + port = strrchr (url, + (unsigned char) ':'); + if (NULL == port) + pnum = 80; + else + pnum = strtol (port + 1, NULL, 10); + if (GNUNET_OK != + GNUNET_NETWORK_test_port_free (IPPROTO_TCP, + pnum)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Port %u not available.\n", + (unsigned int) pnum); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/* end of testing_api_helpers_exchange.c */ diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c new file mode 100644 index 000000000..a7a5a23a4 --- /dev/null +++ b/src/testing/testing_api_loop.c @@ -0,0 +1,828 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file testing/testing_api_loop.c + * @brief main interpreter loop for testcases + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" +#include "taler_fakebank_lib.h" + +/** + * Pipe used to communicate child death via signal. + * Must be global, as used in signal handler! + */ +static struct GNUNET_DISK_PipeHandle *sigpipe; + +/** + * Lookup command by label. + * + * @param is interpreter state to search + * @param label label to look for + * @return NULL if command was not found + */ +const struct TALER_TESTING_Command * +TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is, + const char *label) +{ + if (NULL == label) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Attempt to lookup command for empty label\n"); + return NULL; + } + /* Search backwards as we most likely reference recent commands */ + for (int i = is->ip; i >= 0; i--) + { + const struct TALER_TESTING_Command *cmd = &is->commands[i]; + + /* Give precedence to top-level commands. */ + if ( (NULL != cmd->label) && + (0 == strcmp (cmd->label, + label)) ) + return cmd; + + if (TALER_TESTING_cmd_is_batch (cmd)) + { +#define BATCH_INDEX 1 + struct TALER_TESTING_Command *batch; + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_cmd (cmd, + BATCH_INDEX, + &batch)); + for (unsigned int j = 0; + NULL != (cmd = &batch[j])->label; + j++) + { + if ( (NULL != cmd->label) && + (0 == strcmp (cmd->label, + label)) ) + return cmd; + } + } + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Command not found: %s\n", + label); + return NULL; + +} + + +/** + * Obtain main execution context for the main loop. + */ +struct GNUNET_CURL_Context * +TALER_TESTING_interpreter_get_context + (struct TALER_TESTING_Interpreter *is) +{ + return is->ctx; +} + + +struct TALER_FAKEBANK_Handle * +TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is) +{ + return is->fakebank; +} + + +/** + * Run tests starting the "fakebank" first. The "fakebank" + * is a C minimalist version of the human-oriented Python bank, + * which is also part of the Taler project. + * + * @param is pointer to the interpreter state + * @param commands the list of commands to execute + * @param bank_url the url the fakebank is supposed to run on + */ +void +TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is, + struct TALER_TESTING_Command *commands, + const char *bank_url) +{ + const char *port; + long pnum; + + port = strrchr (bank_url, + (unsigned char) ':'); + if (NULL == port) + pnum = 80; + else + pnum = strtol (port + 1, NULL, 10); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Starting Fakebank on port %u (%s)\n", + (unsigned int) pnum, + bank_url); + is->fakebank = TALER_FAKEBANK_start ((uint16_t) pnum); + if (NULL == is->fakebank) + { + GNUNET_break (0); + is->result = GNUNET_SYSERR; + return; + } + TALER_TESTING_run (is, + commands); +} + + +/** + * Run the main interpreter loop that performs exchange operations. + * + * @param cls contains the `struct InterpreterState` + */ +static void +interpreter_run (void *cls); + + +/** + * Current command is done, run the next one. + */ +void +TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is) +{ + static unsigned long long ipc; + static struct GNUNET_TIME_Absolute last_report; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + + if (GNUNET_SYSERR == is->result) + return; /* ignore, we already failled! */ + if (TALER_TESTING_cmd_is_batch (cmd)) + TALER_TESTING_cmd_batch_next (is); + else + is->ip++; + if (0 == (ipc % 1000)) + { + if (0 != ipc) + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Interpreter executed 1000 instructions in %s\n", + GNUNET_STRINGS_relative_time_to_string ( + GNUNET_TIME_absolute_get_duration (last_report), + GNUNET_YES)); + last_report = GNUNET_TIME_absolute_get (); + } + ipc++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Current command failed, clean up and fail the test case. + * + * @param is interpreter of the test + */ +void +TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is) +{ + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed at command `%s'\n", + cmd->label); + while (TALER_TESTING_cmd_is_batch (cmd)) + { + cmd = TALER_TESTING_cmd_batch_get_current (cmd); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Batch is at command `%s'\n", + cmd->label); + } + is->result = GNUNET_SYSERR; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Create command array terminator. + * + * @return a end-command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_end (void) +{ + static struct TALER_TESTING_Command cmd; + cmd.label = NULL; + + return cmd; +} + + +/** + * Obtain current label. + */ +const char * +TALER_TESTING_interpreter_get_current_label (struct + TALER_TESTING_Interpreter *is) +{ + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + + return cmd->label; +} + + +/** + * Run the main interpreter loop that performs exchange operations. + * + * @param cls contains the `struct TALER_TESTING_Interpreter` + */ +static void +interpreter_run (void *cls) +{ + struct TALER_TESTING_Interpreter *is = cls; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + + is->task = NULL; + + if (NULL == cmd->label) + { + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Running command END\n"); + is->result = GNUNET_OK; + GNUNET_SCHEDULER_shutdown (); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Running command `%s'\n", + cmd->label); + + cmd->run (cmd->cls, + cmd, + is); +} + + +/** + * Function run when the test terminates (good or bad). + * Cleans up our state. + * + * @param cls the interpreter state. + */ +static void +do_shutdown (void *cls) +{ + struct TALER_TESTING_Interpreter *is = cls; + struct TALER_TESTING_Command *cmd; + const char *label; + + label = is->commands[is->ip].label; + if (NULL == label) + label = "END"; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Executing shutdown at `%s'\n", + label); + + for (unsigned int j = 0; + NULL != (cmd = &is->commands[j])->label; + j++) + cmd->cleanup (cmd->cls, + cmd); + + if (NULL != is->exchange) + { + TALER_LOG_DEBUG ("Disconnecting the exchange\n"); + TALER_EXCHANGE_disconnect (is->exchange); + is->exchange = NULL; + } + if (NULL != is->task) + { + GNUNET_SCHEDULER_cancel (is->task); + is->task = NULL; + } + if (NULL != is->ctx) + { + GNUNET_CURL_fini (is->ctx); + is->ctx = NULL; + } + if (NULL != is->rc) + { + GNUNET_CURL_gnunet_rc_destroy (is->rc); + is->rc = NULL; + } + if (NULL != is->timeout_task) + { + GNUNET_SCHEDULER_cancel (is->timeout_task); + is->timeout_task = NULL; + } + if (NULL != is->child_death_task) + { + GNUNET_SCHEDULER_cancel (is->child_death_task); + is->child_death_task = NULL; + } + if (NULL != is->fakebank) + { + TALER_FAKEBANK_stop (is->fakebank); + is->fakebank = NULL; + } + GNUNET_free_non_null (is->commands); +} + + +/** + * Function run when the test terminates (good or bad) with timeout. + * + * @param cls NULL + */ +static void +do_timeout (void *cls) +{ + struct TALER_TESTING_Interpreter *is = cls; + + is->timeout_task = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Terminating test due to timeout\n"); + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Task triggered whenever we receive a SIGCHLD (child + * process died). + * + * @param cls closure + */ +static void +maint_child_death (void *cls) +{ + struct TALER_TESTING_Interpreter *is = cls; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + const struct GNUNET_DISK_FileHandle *pr; + + struct GNUNET_OS_Process **processp; + char c[16]; + + if (TALER_TESTING_cmd_is_batch (cmd)) + { + struct TALER_TESTING_Command *batch_cmd; + + GNUNET_assert + (GNUNET_OK == TALER_TESTING_get_trait_cmd + (cmd, 0, &batch_cmd)); /* bad? */ + cmd = batch_cmd; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got SIGCHLD for `%s'.\n", + cmd->label); + + is->child_death_task = NULL; + pr = GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_READ); + GNUNET_break (0 < + GNUNET_DISK_file_read (pr, + &c, + sizeof (c))); + if (GNUNET_OK != + TALER_TESTING_get_trait_process (cmd, + 0, + &processp)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got the dead child process handle" + ", waiting for termination ...\n"); + + GNUNET_OS_process_wait (*processp); + GNUNET_OS_process_destroy (*processp); + *processp = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "... definitively terminated\n"); + + if (GNUNET_OK == is->reload_keys) + { + if (NULL == is->exchanged) + { + GNUNET_break (0); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Triggering key state reload at exchange\n"); + GNUNET_break (0 == GNUNET_OS_process_kill + (is->exchanged, SIGUSR1)); + sleep (5); /* make sure signal was received and processed */ + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Dead child, go on with next command.\n"); + TALER_TESTING_interpreter_next (is); +} + + +/** + * Wait until we receive SIGCHLD signal. + * Then obtain the process trait of the current + * command, wait on the the zombie and continue + * with the next command. + */ +void +TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is) +{ + const struct GNUNET_DISK_FileHandle *pr; + + GNUNET_assert (NULL == is->child_death_task); + pr = GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_READ); + is->child_death_task + = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + pr, + &maint_child_death, + is); +} + + +/** + * Run the testsuite. Note, CMDs are copied into + * the interpreter state because they are _usually_ + * defined into the "run" method that returns after + * having scheduled the test interpreter. + * + * @param is the interpreter state + * @param commands the list of command to execute + * @param timeout how long to wait + */ +void +TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is, + struct TALER_TESTING_Command *commands, + struct GNUNET_TIME_Relative timeout) +{ + unsigned int i; + + if (NULL != is->timeout_task) + { + GNUNET_SCHEDULER_cancel (is->timeout_task); + is->timeout_task = NULL; + } + /* get the number of commands */ + for (i = 0; NULL != commands[i].label; i++) + ; + is->commands = GNUNET_new_array (i + 1, + struct TALER_TESTING_Command); + memcpy (is->commands, + commands, + sizeof (struct TALER_TESTING_Command) * i); + is->timeout_task = GNUNET_SCHEDULER_add_delayed + (timeout, + &do_timeout, + is); + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is); + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is); +} + + +/** + * Run the testsuite. Note, CMDs are copied into + * the interpreter state because they are _usually_ + * defined into the "run" method that returns after + * having scheduled the test interpreter. + * + * @param is the interpreter state + * @param commands the list of command to execute + */ +void +TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, + struct TALER_TESTING_Command *commands) +{ + TALER_TESTING_run2 (is, + commands, + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, + 5)); +} + + +/** + * Information used by the wrapper around the main + * "run" method. + */ +struct MainContext +{ + /** + * Main "run" method. + */ + TALER_TESTING_Main main_cb; + + /** + * Closure for @e main_cb. + */ + void *main_cb_cls; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Configuration filename. The wrapper uses it to fetch + * the exchange port number; We could have passed the port + * number here, but having the config filename seems more + * generic. + */ + const char *config_filename; + + /** + * URL of the exchange. + */ + char *exchange_url; + +}; + + +/** + * Signal handler called for SIGCHLD. Triggers the + * respective handler by writing to the trigger pipe. + */ +static void +sighandler_child_death () +{ + static char c; + int old_errno = errno; /* back-up errno */ + + GNUNET_break (1 == GNUNET_DISK_file_write + (GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_WRITE), + &c, sizeof (c))); + errno = old_errno; /* restore errno */ +} + + +/** + * "Canonical" cert_cb used when we are connecting to the + * Exchange. + * + * @param cls closure, typically, the "run" method containing + * all the commands to be run, and a closure for it. + * @param keys the exchange's keys. + * @param compat protocol compatibility information. + */ +void +TALER_TESTING_cert_cb (void *cls, + const struct TALER_EXCHANGE_Keys *keys, + enum TALER_EXCHANGE_VersionCompatibility compat) +{ + struct MainContext *main_ctx = cls; + struct TALER_TESTING_Interpreter *is = main_ctx->is; + + if (NULL == keys) + { + if (GNUNET_NO == is->working) + { + GNUNET_log + (GNUNET_ERROR_TYPE_WARNING, + "Got NULL response for /keys" + " during startup, retrying!\n"); + TALER_EXCHANGE_disconnect (is->exchange); + GNUNET_assert + (NULL != (is->exchange = TALER_EXCHANGE_connect + (is->ctx, + main_ctx->exchange_url, + &TALER_TESTING_cert_cb, + main_ctx, + TALER_EXCHANGE_OPTION_END))); + return; + } + else + GNUNET_log + (GNUNET_ERROR_TYPE_ERROR, + "Got NULL response for /keys" + " during execution!\n"); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got %d DK from /keys in generation %u\n", + keys->num_denom_keys, + is->key_generation + 1); + } + is->key_generation++; + is->keys = keys; + + /* /keys has been called for some reason and + * the interpreter is already running. */ + if (GNUNET_YES == is->working) + return; + + is->working = GNUNET_YES; + + /* Very first start of tests, call "run()" */ + if (1 == is->key_generation) + { + main_ctx->main_cb (main_ctx->main_cb_cls, + is); + return; + } + + /* Tests already started, just trigger the + * next command. */ + TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n", + is->ip); + GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + +/** + * Initialize scheduler loop and curl context for the testcase, + * and responsible to run the "run" method. + * + * @param cls closure, typically the "run" method, the + * interpreter state and a closure for "run". + */ +static void +main_wrapper_exchange_agnostic (void *cls) +{ + struct MainContext *main_ctx = cls; + + main_ctx->main_cb (main_ctx->main_cb_cls, + main_ctx->is); +} + + +/** + * Function run when the test is aborted before we launch the actual + * interpreter. Cleans up our state. + * + * @param cls the main context + */ +static void +do_abort (void *cls) +{ + struct MainContext *main_ctx = cls; + struct TALER_TESTING_Interpreter *is = main_ctx->is; + + is->timeout_task = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Executing abort prior to interpreter launch\n"); + if (NULL != is->exchange) + { + TALER_EXCHANGE_disconnect (is->exchange); + is->exchange = NULL; + } +} + + +/** + * Initialize scheduler loop and curl context for the testcase, + * and responsible to run the "run" method. + * + * @param cls a `struct MainContext *` + * @param cfg configuration to use + */ +static int +main_exchange_connect_with_cfg (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct MainContext *main_ctx = cls; + struct TALER_TESTING_Interpreter *is = main_ctx->is; + char *exchange_url; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "BASE_URL", + &exchange_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "BASE_URL"); + return GNUNET_SYSERR; + } + main_ctx->exchange_url = exchange_url; + is->cfg = cfg; + is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort, + main_ctx); + GNUNET_break + (NULL != (is->exchange = TALER_EXCHANGE_connect + (is->ctx, + exchange_url, + &TALER_TESTING_cert_cb, + main_ctx, + TALER_EXCHANGE_OPTION_END))); + is->cfg = NULL; + return GNUNET_OK; +} + + +/** + * Initialize scheduler loop and curl context for the testcase, + * and responsible to run the "run" method. + * + * @param cls a `struct MainContext *` + */ +static void +main_wrapper_exchange_connect (void *cls) +{ + struct MainContext *main_ctx = cls; + + GNUNET_break (GNUNET_OK == + GNUNET_CONFIGURATION_parse_and_run (main_ctx->config_filename, + & + main_exchange_connect_with_cfg, + main_ctx)); +} + + +/** + * Install signal handlers plus schedules the main wrapper + * around the "run" method. + * + * @param main_cb the "run" method which contains all the + * commands. + * @param main_cb_cls a closure for "run", typically NULL. + * @param config_filename configuration filename. + * @param exchanged exchange process handle: will be put in the + * state as some commands - e.g. revoke - need to send + * signal to it, for example to let it know to reload the + * key state.. if NULL, the interpreter will run without + * trying to connect to the exchange first. + * @param exchange_connect #GNUNET_YES if the test should connect + * to the exchange, #GNUNET_NO otherwise + * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise. + * non-GNUNET_OK codes are #GNUNET_SYSERR most of the + * times. + */ +int +TALER_TESTING_setup (TALER_TESTING_Main main_cb, + void *main_cb_cls, + const char *config_filename, + struct GNUNET_OS_Process *exchanged, + int exchange_connect) +{ + struct TALER_TESTING_Interpreter is; + struct MainContext main_ctx = { + .main_cb = main_cb, + .main_cb_cls = main_cb_cls, + /* needed to init the curl ctx */ + .is = &is, + /* needed to read values like exchange port + * number to construct the exchange url.*/ + .config_filename = config_filename + }; + struct GNUNET_SIGNAL_Context *shc_chld; + + memset (&is, + 0, + sizeof (is)); + is.exchanged = exchanged; + sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, + GNUNET_NO, GNUNET_NO); + GNUNET_assert (NULL != sigpipe); + shc_chld = GNUNET_SIGNAL_handler_install + (GNUNET_SIGCHLD, + &sighandler_child_death); + is.ctx = GNUNET_CURL_init + (&GNUNET_CURL_gnunet_scheduler_reschedule, + &is.rc); + GNUNET_CURL_enable_async_scope_header (is.ctx, "Taler-Correlation-Id"); + GNUNET_assert (NULL != is.ctx); + is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx); + + /* Blocking */ + + if (GNUNET_YES == exchange_connect) + GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect, + &main_ctx); + else + GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic, + &main_ctx); + if (NULL != is.final_cleanup_cb) + is.final_cleanup_cb (is.final_cleanup_cb_cls); + GNUNET_free_non_null (main_ctx.exchange_url); + GNUNET_SIGNAL_handler_uninstall (shc_chld); + GNUNET_DISK_pipe_close (sigpipe); + sigpipe = NULL; + return is.result; +} + + +/* end of testing_api_loop.c */ diff --git a/src/testing/testing_api_trait_amount.c b/src/testing/testing_api_trait_amount.c new file mode 100644 index 000000000..96698b49e --- /dev/null +++ b/src/testing/testing_api_trait_amount.c @@ -0,0 +1,76 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_trait_amount.c + * @brief offer amounts as traits. + * @author Marcello Stanisci + */ + +#include "platform.h" +#include "taler_json_lib.h" +#include +#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 new file mode 100644 index 000000000..ae1889a1f --- /dev/null +++ b/src/testing/testing_api_trait_blinding_key.c @@ -0,0 +1,77 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#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 new file mode 100644 index 000000000..f24054713 --- /dev/null +++ b/src/testing/testing_api_trait_cmd.c @@ -0,0 +1,80 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file testing/testing_api_trait_cmd.c + * @brief offers CMDs as traits. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#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 new file mode 100644 index 000000000..61a770cf6 --- /dev/null +++ b/src/testing/testing_api_trait_coin_priv.c @@ -0,0 +1,78 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @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 +#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 new file mode 100644 index 000000000..1e88cb86f --- /dev/null +++ b/src/testing/testing_api_trait_contract.c @@ -0,0 +1,74 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#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 new file mode 100644 index 000000000..f866588db --- /dev/null +++ b/src/testing/testing_api_trait_denom_pub.c @@ -0,0 +1,77 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#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 new file mode 100644 index 000000000..07e89440e --- /dev/null +++ b/src/testing/testing_api_trait_denom_sig.c @@ -0,0 +1,79 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @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 +#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 new file mode 100644 index 000000000..8c7027260 --- /dev/null +++ b/src/testing/testing_api_trait_exchange_pub.c @@ -0,0 +1,77 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_trait_exchange_pub.c + * @brief exchange pub traits. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#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 new file mode 100644 index 000000000..349454ae7 --- /dev/null +++ b/src/testing/testing_api_trait_exchange_sig.c @@ -0,0 +1,77 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_trait_exchange_sig.c + * @brief exchange pub traits. + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#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 new file mode 100644 index 000000000..e5f1c6827 --- /dev/null +++ b/src/testing/testing_api_trait_fresh_coin.c @@ -0,0 +1,77 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#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 new file mode 100644 index 000000000..cbddad53e --- /dev/null +++ b/src/testing/testing_api_trait_json.c @@ -0,0 +1,123 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file testing/testing_api_trait_json.c + * @brief offers JSON traits. + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + +#define TALER_TESTING_TRAIT_WIRE_DETAILS "wire-details" +#define TALER_TESTING_TRAIT_EXCHANGE_KEYS "exchange-keys" + +/** + * Obtain serialized exchange keys from @a cmd. + * + * @param cmd command to extract the keys from. + * @param index index number associate with the keys on offer. + * @param[out] keys where to write the serialized keys. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_exchange_keys + (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const json_t **keys) +{ + return cmd->traits (cmd->cls, + (const void **) keys, + TALER_TESTING_TRAIT_EXCHANGE_KEYS, + index); +} + + +/** + * Offer serialized keys in a trait. + * + * @param index index number associate with the serial keys + * on offer. + * @param keys serialized keys to offer. + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_exchange_keys + (unsigned int index, + const json_t *keys) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_EXCHANGE_KEYS, + .ptr = (const json_t *) keys + }; + return ret; +} + + +/** + * Obtain wire details from @a cmd. + * + * @param cmd command to extract the wire details from. + * @param index index number associate with the wire details + * on offer; usually zero, as one command sticks to + * one bank account. + * @param[out] wire_details where to write the wire details. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_wire_details + (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const json_t **wire_details) +{ + return cmd->traits (cmd->cls, + (const void **) wire_details, + TALER_TESTING_TRAIT_WIRE_DETAILS, + index); +} + + +/** + * Offer wire details in a trait. + * + * @param index index number associate with the wire details + * on offer; usually zero, as one command sticks to + * one bank account. + * @param wire_details wire details to offer. + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_wire_details + (unsigned int index, + const json_t *wire_details) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS, + .ptr = (const json_t *) wire_details + }; + return ret; +} + + +/* end of testing_api_trait_json.c */ diff --git a/src/testing/testing_api_trait_merchant_key.c b/src/testing/testing_api_trait_merchant_key.c new file mode 100644 index 000000000..41b6b8883 --- /dev/null +++ b/src/testing/testing_api_trait_merchant_key.c @@ -0,0 +1,127 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#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 new file mode 100644 index 000000000..50ce6d8c7 --- /dev/null +++ b/src/testing/testing_api_trait_number.c @@ -0,0 +1,149 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_trait_number.c + * @brief traits to offer numbers + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + +#define TALER_TESTING_TRAIT_UINT "uint" +#define TALER_TESTING_TRAIT_UINT64 "uint-64" +#define TALER_TESTING_TRAIT_BANK_ROW "bank-transaction-row" + + +/** + * Obtain a number from @a cmd. + * + * @param cmd command to extract the number from. + * @param index the number's index number. + * @param[out] n set to the number coming from @a cmd. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_uint (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const unsigned int **n) +{ + return cmd->traits (cmd->cls, + (const void **) n, + TALER_TESTING_TRAIT_UINT, + index); +} + + +/** + * Offer a number. + * + * @param index the number's index number. + * @param n the number to offer. + * @return #GNUNET_OK on success. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_uint (unsigned int index, + const unsigned int *n) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_UINT, + .ptr = (const void *) n + }; + return ret; +} + + +/** + * Obtain a "number" value from @a cmd, 64-bit version. + * + * @param cmd command to extract the number from. + * @param index the number's index number. + * @param[out] n set to the number coming from @a cmd. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_uint64 (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const uint64_t **n) +{ + return cmd->traits (cmd->cls, + (const void **) n, + TALER_TESTING_TRAIT_UINT64, + index); +} + + +/** + * Offer number trait, 64-bit version. + * + * @param index the number's index number. + * @param n number to offer. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_uint64 (unsigned int index, + const uint64_t *n) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_UINT64, + .ptr = (const void *) n + }; + return ret; +} + + +/** + * Obtain a bank transaction row value from @a cmd. + * + * @param cmd command to extract the number from. + * @param[out] row set to the number coming from @a cmd. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_bank_row (const struct TALER_TESTING_Command *cmd, + const uint64_t **row) +{ + return cmd->traits (cmd->cls, + (const void **) row, + TALER_TESTING_TRAIT_BANK_ROW, + 0); +} + + +/** + * Offer bank transaction row trait. + * + * @param row number to offer. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_bank_row (const uint64_t *row) +{ + struct TALER_TESTING_Trait ret = { + .index = 0, + .trait_name = TALER_TESTING_TRAIT_BANK_ROW, + .ptr = (const void *) row + }; + return ret; +} + + +/* end of testing_api_trait_number.c */ diff --git a/src/testing/testing_api_trait_process.c b/src/testing/testing_api_trait_process.c new file mode 100644 index 000000000..3d2af31fd --- /dev/null +++ b/src/testing/testing_api_trait_process.c @@ -0,0 +1,82 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @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 +#include "taler_signatures.h" +#include "taler_testing_lib.h" + +#define TALER_TESTING_TRAIT_PROCESS "process" + + +/** + * Obtain location where a command stores a pointer to a process. + * + * @param cmd command to extract trait from. + * @param index which process to pick if @a cmd + * has multiple on offer. + * @param[out] processp set to the address of the pointer to the + * process. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_process + (const struct TALER_TESTING_Command *cmd, + unsigned int index, + struct GNUNET_OS_Process ***processp) +{ + return cmd->traits (cmd->cls, + (const void **) processp, + TALER_TESTING_TRAIT_PROCESS, + index); +} + + +/** + * Offer location where a command stores a pointer to a process. + * + * @param index offered location index number, in case there are + * multiple on offer. + * @param processp process location to offer. + * + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_process + (unsigned int index, + struct GNUNET_OS_Process **processp) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_PROCESS, + .ptr = (const void *) processp + }; + + return ret; +} + + +/* end of testing_api_trait_process.c */ diff --git a/src/testing/testing_api_trait_reserve_priv.c b/src/testing/testing_api_trait_reserve_priv.c new file mode 100644 index 000000000..f4a4ef500 --- /dev/null +++ b/src/testing/testing_api_trait_reserve_priv.c @@ -0,0 +1,76 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#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 new file mode 100644 index 000000000..a158114be --- /dev/null +++ b/src/testing/testing_api_trait_reserve_pub.c @@ -0,0 +1,76 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#include "taler_signatures.h" +#include "taler_testing_lib.h" + +#define TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY \ + "reserve-public-key" + +/** + * Obtain a reserve public key from a @a cmd. + * + * @param cmd command to extract the reserve pub from. + * @param index reserve pub's index number. + * @param[out] reserve_pub set to the reserve pub. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_reserve_pub + (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const struct TALER_ReservePublicKeyP **reserve_pub) +{ + return cmd->traits (cmd->cls, + (const void **) reserve_pub, + TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY, + index); +} + + +/** + * Offer a reserve public key. + * + * @param index reserve pub's index number. + * @param reserve_pub reserve public key to offer. + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_reserve_pub + (unsigned int index, + const struct TALER_ReservePublicKeyP *reserve_pub) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY, + .ptr = (const void *) reserve_pub + }; + return ret; +} + + +/* end of testing_api_trait_reserve_pub.c */ diff --git a/src/testing/testing_api_trait_string.c b/src/testing/testing_api_trait_string.c new file mode 100644 index 000000000..381760113 --- /dev/null +++ b/src/testing/testing_api_trait_string.c @@ -0,0 +1,231 @@ +/* + This file is part of TALER + Copyright (C) 2018-2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @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 +#include "taler_signatures.h" +#include "taler_testing_lib.h" + +/** + * Some string. Avoid, use something more precise! + */ +#define TALER_TESTING_TRAIT_STRING "string" + +/** + * An HTTP-URL. + */ +#define TALER_TESTING_TRAIT_URL "url" + +/** + * A PAYTO-URL. + */ +#define TALER_TESTING_TRAIT_PAYTO "payto" + +/** + * String identifying an order. + */ +#define TALER_TESTING_TRAIT_ORDER_ID "order-id" + + +/** + * Obtain a string from @a cmd. + * + * @param cmd command to extract the subject from. + * @param index index number associated with the transfer + * subject to offer. + * @param[out] s where to write the offered + * string + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_string (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const char **s) +{ + return cmd->traits (cmd->cls, + (const void **) s, + TALER_TESTING_TRAIT_STRING, + index); +} + + +/** + * Offer string. + * + * @param index index number associated with the transfer + * subject being offered. + * @param s transfer subject to offer. + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_string (unsigned int index, + const char *s) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_STRING, + .ptr = (const void *) s + }; + return ret; +} + + +/** + * Obtain a HTTP url from @a cmd. + * + * @param cmd command to extract the url from. + * @param index which url is to be picked, in case + * multiple are offered. + * @param[out] url where to write the url. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_url (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const char **url) +{ + return cmd->traits (cmd->cls, + (const void **) url, + TALER_TESTING_TRAIT_URL, + index); +} + + +/** + * Offer HTTP url in a trait. + * + * @param index which url is to be picked, + * in case multiple are offered. + * @param url the url to offer. + * + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_url (unsigned int index, + const char *url) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_URL, + .ptr = (const void *) url + }; + + GNUNET_assert (0 != strncasecmp (url, + "payto://", + strlen ("payto://"))); + + return ret; +} + + +/** + * Obtain a order id from @a cmd. + * + * @param cmd command to extract the order id from. + * @param index which order id is to be picked, in case + * multiple are offered. + * @param[out] order_id where to write the order id. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_order_id (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const char **order_id) +{ + return cmd->traits (cmd->cls, + (const void **) order_id, + TALER_TESTING_TRAIT_ORDER_ID, + index); +} + + +/** + * Offer order id in a trait. + * + * @param index which order id is to be offered, + * in case multiple are offered. + * @param order_id the order id to offer. + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_order_id (unsigned int index, + const char *order_id) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_ORDER_ID, + .ptr = (const void *) order_id + }; + return ret; +} + + +/** + * Obtain a PAYTO-url from @a cmd. + * + * @param cmd command to extract the url from. + * @param pt which url is to be picked, in case + * multiple are offered. + * @param[out] url where to write the url. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_payto (const struct TALER_TESTING_Command *cmd, + enum TALER_TESTING_PaytoType pt, + const char **url) +{ + return cmd->traits (cmd->cls, + (const void **) url, + TALER_TESTING_TRAIT_PAYTO, + (unsigned int) pt); +} + + +/** + * Offer a "payto" URL reference. + * + * @param pt which reference is to be offered, + * in case multiple are offered. + * @param payto_uri the payto URI + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_payto (enum TALER_TESTING_PaytoType pt, + const char *payto_uri) +{ + struct TALER_TESTING_Trait ret = { + .index = (unsigned int) pt, + .trait_name = TALER_TESTING_TRAIT_PAYTO, + .ptr = (const void *) payto_uri, + }; + + GNUNET_assert (0 == strncasecmp (payto_uri, + "payto://", + strlen ("payto://"))); + return ret; +} + + +/* end of testing_api_trait_string.c */ diff --git a/src/testing/testing_api_trait_time.c b/src/testing/testing_api_trait_time.c new file mode 100644 index 000000000..c77489bfa --- /dev/null +++ b/src/testing/testing_api_trait_time.c @@ -0,0 +1,76 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @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 +#include "taler_signatures.h" +#include "taler_testing_lib.h" + +#define TALER_TESTING_TRAIT_TIME_ABS "time-abs" + +/** + * Obtain a absolute time from @a cmd. + * + * @param cmd command to extract trait from + * @param index which time stamp to pick if + * @a cmd has multiple on offer. + * @param[out] time set to the wanted WTID. + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_get_trait_absolute_time + (const struct TALER_TESTING_Command *cmd, + unsigned int index, + const struct GNUNET_TIME_Absolute **time) +{ + return cmd->traits (cmd->cls, + (const void **) time, + TALER_TESTING_TRAIT_TIME_ABS, + index); +} + + +/** + * Offer a absolute time. + * + * @param index associate the object with this index + * @param time which object should be returned + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_absolute_time + (unsigned int index, + const struct GNUNET_TIME_Absolute *time) +{ + struct TALER_TESTING_Trait ret = { + .index = index, + .trait_name = TALER_TESTING_TRAIT_TIME_ABS, + .ptr = (const void *) time + }; + return ret; +} + + +/* end of testing_api_trait_time.c */ diff --git a/src/testing/testing_api_trait_wtid.c b/src/testing/testing_api_trait_wtid.c new file mode 100644 index 000000000..5c7e7060e --- /dev/null +++ b/src/testing/testing_api_trait_wtid.c @@ -0,0 +1,76 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ + +/** + * @file testing/testing_api_trait_number.c + * @brief traits to offer numbers + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#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 new file mode 100644 index 000000000..6d623af7a --- /dev/null +++ b/src/testing/testing_api_traits.c @@ -0,0 +1,81 @@ +/* + This file is part of TALER + Copyright (C) 2018 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + +*/ +/** + * @file testing/testing_api_traits.c + * @brief loop for trait resolution + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * End a trait array. Usually, commands offer several traits, + * and put them in arrays. + */ +struct TALER_TESTING_Trait +TALER_TESTING_trait_end () +{ + struct TALER_TESTING_Trait end = { + .index = 0, + .trait_name = NULL, + .ptr = NULL + }; + + return end; +} + + +/** + * Pick the chosen trait from the traits array. + * + * @param traits the traits array. + * @param ret where to store the result. + * @param trait type of the trait to extract. + * @param index index number of the object to extract. + * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise. + */ +int +TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, + const void **ret, + const char *trait, + unsigned int index) +{ + for (unsigned int i = 0; NULL != traits[i].trait_name; i++) + { + if ( (0 == strcmp (trait, traits[i].trait_name)) && + (index == traits[i].index) ) + { + *ret = (void *) traits[i].ptr; + return GNUNET_OK; + } + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Trait %s/%u not found.\n", + trait, index); + + return GNUNET_SYSERR; +} + + +/* end of testing_api_traits.c */ -- cgit v1.2.3