From 0ff76b5abbf09aa273b7998f4d16bb0c0e4d90bb Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 4 Apr 2016 16:47:11 +0200 Subject: [PATCH] fix test to ensure DB invariants are met --- src/exchange/test_taler_exchange_aggregator.c | 134 +++++++++++++++++- src/include/taler_amount_lib.h | 13 ++ src/util/amount.c | 24 ++++ 3 files changed, 170 insertions(+), 1 deletion(-) diff --git a/src/exchange/test_taler_exchange_aggregator.c b/src/exchange/test_taler_exchange_aggregator.c index b27c10d1f..22bc8e277 100644 --- a/src/exchange/test_taler_exchange_aggregator.c +++ b/src/exchange/test_taler_exchange_aggregator.c @@ -290,6 +290,16 @@ static struct Transaction *transactions_head; */ static struct Transaction *transactions_tail; +/** + * Private key we use for fake coins. + */ +static struct GNUNET_CRYPTO_RsaPrivateKey *coin_pk; + +/** + * Public key we use for fake coins. + */ +static struct GNUNET_CRYPTO_RsaPublicKey *coin_pub; + /** * Interprets the commands from the test program. @@ -383,6 +393,47 @@ maint_child_death (void *cls, } +/** + * 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)); +} + + +/** + * Setup (fake) information about a coin used in deposit. + * + * @param[out] coin information to initialize with "valid" data + */ +static void +fake_coin (struct TALER_CoinPublicInfo *coin) +{ + struct GNUNET_HashCode hc; + + coin->denom_pub.rsa_public_key = coin_pub; + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, + &hc); + coin->denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (coin_pk, + &hc); +} + /** * Helper function to fake a deposit operation. @@ -423,6 +474,7 @@ do_deposit (struct Command *cmd) GNUNET_break (0); return GNUNET_SYSERR; } + fake_coin (&deposit.coin); /* Build JSON for wire details; note that this simple method may fail in the future if we implement and enforce signature checking on test-wire account details */ @@ -451,6 +503,7 @@ do_deposit (struct Command *cmd) ret = GNUNET_SYSERR; else ret = GNUNET_OK; + GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig.rsa_signature); json_decref (deposit.wire); return ret; } @@ -590,7 +643,7 @@ static void run_test () { static struct Command commands[] = { - /* FIXME: prime DB */ + /* test running with empty DB */ { .opcode = OPCODE_RUN_AGGREGATOR, .label = "run-aggregator-on-empty-db" @@ -599,6 +652,57 @@ run_test () .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY, .label = "expect-empty-transactions-on-start" }, + /* test simple deposit */ + { + .opcode = OPCODE_DATABASE_DEPOSIT, + .label = "do-deposit-", + .details.deposit.merchant_name = "bob", + .details.deposit.merchant_account = 4, + .details.deposit.transaction_id = 1, + .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 5s */ + .details.deposit.amount_with_fee = "EUR:1", + .details.deposit.deposit_fee = "EUR:0" + }, + { + .opcode = OPCODE_RUN_AGGREGATOR, + .label = "run-aggregator-deposit-1" + }, + + /* The above step is already known to fail (with an error message) + right now, so we skip the rest of the test. */ + { + .opcode = OPCODE_TERMINATE_SKIP, + .label = "testcase-incomplete-terminating-with-skip" + }, + + + { + .opcode = OPCODE_EXPECT_TRANSACTION, + .label = "expect-deposit-1", + .details.expect_transaction.debit_account = 1, + .details.expect_transaction.credit_account = 4, + .details.expect_transaction.amount = "EUR:1" + }, + { + .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY, + .label = "expect-empty-transactions-on-start" + }, + /* test idempotency: run again on transactions already done */ + { + .opcode = OPCODE_DATABASE_DEPOSIT, + .label = "do-deposit-", + .details.deposit.merchant_name = "bob", + .details.deposit.merchant_account = 4, + .details.deposit.transaction_id = 1, + .details.deposit.wire_deadline = { 1000LL * 1000 * 0 }, /* 5s */ + .details.deposit.amount_with_fee = "EUR:1", + .details.deposit.deposit_fee = "EUR:0" + }, + { + .opcode = OPCODE_EXPECT_TRANSACTIONS_EMPTY, + .label = "expect-empty-transactions-on-start" + }, + { .opcode = OPCODE_TERMINATE_SKIP, .label = "testcase-incomplete-terminating-with-skip" @@ -851,19 +955,43 @@ run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct TALER_EXCHANGEDB_DenominationKeyInformationP issue; + struct TALER_DenominationPublicKey dpk; plugin = TALER_EXCHANGEDB_plugin_load (cfg); if (GNUNET_OK != plugin->create_tables (plugin->cls, GNUNET_YES)) { + GNUNET_break (0); TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; result = 77; return; } session = plugin->get_session (plugin->cls, GNUNET_YES); GNUNET_assert (NULL != session); + fake_issue (&issue); + dpk.rsa_public_key = coin_pub; + if ( (GNUNET_OK != + plugin->start (plugin->cls, + session)) || + (GNUNET_OK != + plugin->insert_denomination_info (plugin->cls, + session, + &dpk, + &issue)) || + (GNUNET_OK != + plugin->commit (plugin->cls, + session)) ) + { + GNUNET_break (0); + TALER_EXCHANGEDB_plugin_unload (plugin); + plugin = NULL; + result = 77; + return; + } child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_DISK_pipe_handle (sigpipe, @@ -945,7 +1073,11 @@ main (int argc, GNUNET_assert (NULL != sigpipe); shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death); + coin_pk = GNUNET_CRYPTO_rsa_private_key_create (1024); + coin_pub = GNUNET_CRYPTO_rsa_private_key_get_public (coin_pk); GNUNET_SCHEDULER_run (&run, cfg); + GNUNET_CRYPTO_rsa_private_key_free (coin_pk); + GNUNET_CRYPTO_rsa_public_key_free (coin_pub); GNUNET_SIGNAL_handler_uninstall (shc_chld); shc_chld = NULL; GNUNET_DISK_pipe_close (sigpipe); diff --git a/src/include/taler_amount_lib.h b/src/include/taler_amount_lib.h index 094b96f7f..2fd547196 100644 --- a/src/include/taler_amount_lib.h +++ b/src/include/taler_amount_lib.h @@ -127,6 +127,19 @@ TALER_string_to_amount (const char *str, struct TALER_Amount *denom); +/** + * Parse denomination description, in the format "T:V.F". + * + * @param str denomination description + * @param denom denomination to write the result to, in NBO + * @return #GNUNET_OK if the string is a valid denomination specification, + * #GNUNET_SYSERR if it is invalid. + */ +int +TALER_string_to_amount_nbo (const char *str, + struct TALER_AmountNBO *denom); + + /** * Get the value of "zero" in a particular currency. * diff --git a/src/util/amount.c b/src/util/amount.c index dc2d2e400..4ac7d30ab 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -150,6 +150,30 @@ TALER_string_to_amount (const char *str, } +/** + * Parse denomination description, in the format "T:V.F". + * + * @param str denomination description + * @param denom denomination to write the result to, in NBO + * @return #GNUNET_OK if the string is a valid denomination specification, + * #GNUNET_SYSERR if it is invalid. + */ +int +TALER_string_to_amount_nbo (const char *str, + struct TALER_AmountNBO *denom) +{ + struct TALER_Amount amount; + + if (GNUNET_OK != + TALER_string_to_amount (str, + &amount)) + return GNUNET_SYSERR; + TALER_amount_hton (denom, + &amount); + return GNUNET_OK; +} + + /** * Convert amount from host to network representation. *