From 566408fa02acf56bbf6063c6d17d739e491e27f2 Mon Sep 17 00:00:00 2001 From: Jonathan Buchanan Date: Thu, 18 Jun 2020 20:27:04 -0400 Subject: stricter tests for tips/reserves --- src/backend/taler-merchant-httpd.c | 2 +- ...-httpd_private-post-reserves-ID-authorize-tip.c | 4 + src/backenddb/plugin_merchantdb_postgres.c | 27 ++- src/include/taler_merchant_testing_lib.h | 144 ++++++++++++-- src/lib/merchant_api_tip_authorize.c | 2 +- src/testing/test_merchant_api.c | 207 +++++++++------------ src/testing/testing_api_cmd_get_reserve.c | 2 +- src/testing/testing_api_cmd_merchant_get_tip.c | 175 ++++++++++++++++- src/testing/testing_api_cmd_post_reserves.c | 55 ++++++ src/testing/testing_api_cmd_tip_authorize.c | 187 ++++++++++++++++--- src/testing/testing_api_cmd_tip_pickup.c | 24 ++- src/testing/testing_api_cmd_wallet_get_tip.c | 83 +++++++++ 12 files changed, 730 insertions(+), 182 deletions(-) (limited to 'src') diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 34c31647..3968d6b2 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -865,7 +865,7 @@ url_handler (void *cls, }, /* POST /reserves/$ID/authorize-tip: */ { - .url_prefix = "/reserves", + .url_prefix = "/reserves/", .url_suffix = "authorize-tip", .have_id_segment = true, .method = MHD_HTTP_METHOD_POST, diff --git a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c index 61e2b38a..1c28173b 100644 --- a/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c +++ b/src/backend/taler-merchant-httpd_private-post-reserves-ID-authorize-tip.c @@ -97,6 +97,10 @@ authorize_tip (const struct TMH_RequestHandler *rh, msg = "Failed to approve tip: merchant's tipping reserve does not exist"; rc = MHD_HTTP_SERVICE_UNAVAILABLE; break; + case TALER_EC_TIP_AUTHORIZE_DB_RESERVE_NOT_FOUND: + msg = "Failed to approve tip: merchant's tipping reserve does not exist"; + rc = MHD_HTTP_NOT_FOUND; + break; default: rc = MHD_HTTP_INTERNAL_SERVER_ERROR; msg = "Failed to approve tip: internal server error"; diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index db9e9c51..7188839e 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -4889,6 +4889,12 @@ RETRY: postgres_rollback (pg); return TALER_EC_TIP_AUTHORIZE_DB_LOOKUP_RESERVE_FAILURE; } + if (qs == 0) + { + GNUNET_break (0); + postgres_rollback (pg); + return TALER_EC_TIP_AUTHORIZE_DB_RESERVE_NOT_FOUND; + } } { struct TALER_Amount remaining; @@ -5354,13 +5360,14 @@ lookup_pickup_details_cb (void *cls, for (unsigned int i = 0; i < num_results; i++) { struct TALER_MERCHANTDB_PickupDetails *pd = &((*ltdc->pickups)[i]); + uint64_t num_planchets = 0; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_auto_from_type ("pickup_id", &pd->pickup_id), TALER_PQ_RESULT_SPEC_AMOUNT ("amount", &pd->requested_amount), - GNUNET_PQ_result_spec_uint32 ("num_planchets", - &pd->num_planchets), + GNUNET_PQ_result_spec_uint64 ("num_planchets", + &num_planchets), GNUNET_PQ_result_spec_end }; @@ -5376,6 +5383,8 @@ lookup_pickup_details_cb (void *cls, 0); return; } + + pd->num_planchets = num_planchets; } } @@ -5457,7 +5466,8 @@ postgres_lookup_tip_details (void *cls, struct LookupTipDetailsContext ltdc = { .pickups_length = pickups_length, .pickups = pickups, - .pg = pg + .pg = pg, + .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT }; qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, @@ -7835,14 +7845,11 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " pickup_id" ",amount_val" ",amount_frac" - ",(SELECT" - " COUNT(blind_sig)" - " FROM merchant_tip_pickups" - " JOIN merchant_tip_pickup_signatures USING (pickup_serial)" - " WHERE tip_serial = $1)" - " AS num_planchets" + ",COUNT(blind_sig) AS num_planchets" " FROM merchant_tip_pickups" - " WHERE tip_serial = $1", + " JOIN merchant_tip_pickup_signatures USING (pickup_serial)" + " WHERE tip_serial = $1" + " GROUP BY pickup_serial", 1), /* for postgres_insert_pickup() */ GNUNET_PQ_make_prepare ("insert_pickup", diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h index c7813176..85cd73ef 100644 --- a/src/include/taler_merchant_testing_lib.h +++ b/src/include/taler_merchant_testing_lib.h @@ -582,6 +582,18 @@ TALER_TESTING_cmd_merchant_post_reserves (const char *label, const char *wire_method, unsigned int http_status); + +/** + * This commands does not query the backend at all, + * but just makes up a fake reserve. + * + * @param label command label. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_merchant_post_reserves_fake (const char *label); + + /** * Define a "GET reserve" CMD. * @@ -677,6 +689,24 @@ TALER_TESTING_cmd_merchant_get_tip (const char *label, unsigned int http_status); +/** + * Define a GET /private/tips/$TIP_ID CMD. + * + * @param label the command label + * @param merchant_url base URL of the merchant which will + * serve the request. + * @param tip_reference reference to a command that created a tip. + * @param pickup_refs a NULL-terminated list of pickup commands + * associated with the tip. + * @param http_status expected HTTP response code for the request. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_merchant_get_tip_with_pickups (const char *label, + const char *merchant_url, + const char *tip_reference, + const char *pickup_refs[], + unsigned int http_status); + /** * Define a GET /tips/$TIP_ID CMD. * @@ -693,6 +723,73 @@ TALER_TESTING_cmd_wallet_get_tip (const char *label, unsigned int http_status); +/** + * Define a GET /tips/$TIP_ID CMD. + * + * @param label the command label + * @param merchant_url base URL of the merchant which will + * serve the request. + * @param tip_reference reference to a command that created a tip. + * @param amount_remaining the balance remaining after pickups. + * @param http_status expected HTTP response code for the request. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_wallet_get_tip2 (const char *label, + const char *merchant_url, + const char *tip_reference, + const char *amount_remaining, + unsigned int http_status); + + +/** + * Create a /tip-authorize CMD. + * + * @param label this command label + * @param merchant_url the base URL of the merchant that will + * serve the /tip-authorize request. + * @param exchange_url the base URL of the exchange that owns + * the reserve from which the tip is going to be gotten. + * @param http_status the HTTP response code which is expected + * for this operation. + * @param justification human-readable justification for this + * tip authorization. + * @param amount the amount to authorize for tipping. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_tip_authorize (const char *label, + const char *merchant_url, + const char *exchange_url, + unsigned int http_status, + const char *justification, + const char *amount); + + +/** + * Create a /tip-authorize CMD. + * + * @param label this command label + * @param merchant_url the base URL of the merchant that will + * serve the /tip-authorize request. + * @param exchange_url the base URL of the exchange that owns + * the reserve from which the tip is going to be gotten. + * @param reserve_reference reference to a command that created + * a reserve. + * @param http_status the HTTP response code which is expected + * for this operation. + * @param justification human-readable justification for this + * tip authorization. + * @param amount the amount to authorize for tipping. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_tip_authorize_from_reserve (const char *label, + const char *merchant_url, + const char *exchange_url, + const char *reserve_refernce, + unsigned int http_status, + const char *justification, + const char *amount); + + /** * Create a /tip-authorize CMD, specifying the Taler error code * that is expected to be returned by the backend. @@ -720,39 +817,46 @@ TALER_TESTING_cmd_tip_authorize_with_ec (const char *label, /** - * This commands does not query the backend at all, - * but just makes up a fake authorization id that will - * be subsequently used by the "pick up" CMD in order - * to test against such a case. - * - * @param label command label. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize_fake (const char *label); - - -/** - * Create a /tip-authorize CMD. + * Create a /tip-authorize CMD, specifying the Taler error code + * that is expected to be returned by the backend. * * @param label this command label * @param merchant_url the base URL of the merchant that will * serve the /tip-authorize request. * @param exchange_url the base URL of the exchange that owns * the reserve from which the tip is going to be gotten. + * @param reserve_reference reference to a command that created + * a reserve. * @param http_status the HTTP response code which is expected * for this operation. * @param justification human-readable justification for this * tip authorization. * @param amount the amount to authorize for tipping. + * @param ec expected Taler-defined error code. */ struct TALER_TESTING_Command -TALER_TESTING_cmd_tip_authorize (const char *label, - const char *merchant_url, - const char *exchange_url, - unsigned int http_status, - const char *justification, - const char *amount); +TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec (const char *label, + const char *merchant_url, + const char *exchange_url, + const char * + reserve_reference, + unsigned int http_status, + const char *justification, + const char *amount, + enum TALER_ErrorCode ec); + + +/** + * This commands does not query the backend at all, + * but just makes up a fake authorization id that will + * be subsequently used by the "pick up" CMD in order + * to test against such a case. + * + * @param label command label. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_tip_authorize_fake (const char *label); /** diff --git a/src/lib/merchant_api_tip_authorize.c b/src/lib/merchant_api_tip_authorize.c index 8f8505df..01d369f6 100644 --- a/src/lib/merchant_api_tip_authorize.c +++ b/src/lib/merchant_api_tip_authorize.c @@ -250,7 +250,7 @@ TALER_MERCHANT_tip_authorize2 ( *end = '\0'; GNUNET_snprintf (arg_str, sizeof (arg_str), - "/private/reserves/%s/tip-authorize", + "private/reserves/%s/authorize-tip", res_str); tao->url = TALER_url_join (backend_url, arg_str, diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c index ff705a36..8663b2e3 100644 --- a/src/testing/test_merchant_api.c +++ b/src/testing/test_merchant_api.c @@ -51,6 +51,10 @@ static const char *pickup_amounts_1[] = {"EUR:5", NULL}; +static const char *pickup_amounts_2[] = {"EUR:0.01", NULL}; + +static const char *pickup_refs[] = {"pickup-tip-1", "pickup-tip-4", NULL}; + /** * Payto URI of the customer (payer). */ @@ -654,12 +658,13 @@ run (void *cls, MHD_HTTP_OK, "tip 1", "EUR:5.01"), - TALER_TESTING_cmd_tip_authorize ("authorize-tip-2", - merchant_url, - EXCHANGE_URL, - MHD_HTTP_OK, - "tip 2", - "EUR:5.01"), + TALER_TESTING_cmd_tip_authorize_from_reserve ("authorize-tip-2", + merchant_url, + EXCHANGE_URL, + "create-reserve-tip-1", + MHD_HTTP_OK, + "tip 2", + "EUR:5.01"), TALER_TESTING_cmd_wallet_get_tip ("get-tip-1", merchant_url, "authorize-tip-1", @@ -683,136 +688,94 @@ run (void *cls, MHD_HTTP_OK, "authorize-tip-1", pickup_amounts_1), - TALER_TESTING_cmd_merchant_delete_reserve ("delete-reserve-tip-1", - merchant_url, - "create-reserve-tip-1", - MHD_HTTP_NO_CONTENT), - TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-tip-2", - merchant_url, - "create-reserve-tip-1", - MHD_HTTP_NO_CONTENT), - TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-tip-3", - merchant_url, - "create-reserve-tip-1", - MHD_HTTP_NOT_FOUND), -#if 0 - /* Test tipping. */ - TALER_TESTING_cmd_admin_add_incoming_with_instance ("create-reserve-tip-1", - "EUR:20.04", - &bc.exchange_auth, - payer_payto, - "tip", - CONFIG_FILE), - cmd_exec_wirewatch ("wirewatch-3"), - TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-tip-1", - "EUR:20.04", - payer_payto, - exchange_payto, - "create-reserve-tip-1"), - TALER_TESTING_cmd_tip_authorize ("authorize-tip-1", - merchant_url_internal ("tip"), - EXCHANGE_URL, - MHD_HTTP_OK, - "tip 1", - "EUR:5.01"), - TALER_TESTING_cmd_tip_authorize ("authorize-tip-2", - merchant_url_internal ("tip"), - EXCHANGE_URL, - MHD_HTTP_OK, - "tip 2", - "EUR:5.01"), + TALER_TESTING_cmd_wallet_get_tip2 ("query-tip-2", + merchant_url, + "authorize-tip-1", + "EUR:0.01", + MHD_HTTP_OK), + TALER_TESTING_cmd_tip_pickup ("pickup-tip-2", + merchant_url, + MHD_HTTP_OK, + "authorize-tip-2", + pickup_amounts_1), + + TALER_TESTING_cmd_tip_pickup_with_ec ("pickup-tip-3-too-much", + merchant_url, + MHD_HTTP_BAD_REQUEST, + "authorize-tip-1", + pickup_amounts_1, + TALER_EC_TIP_PICKUP_AMOUNT_EXCEEDS_TIP_REMAINING), + + TALER_TESTING_cmd_tip_pickup ("pickup-tip-4", + merchant_url, + MHD_HTTP_OK, + "authorize-tip-1", + pickup_amounts_2), + TALER_TESTING_cmd_merchant_get_tip_with_pickups ("merchant-get-tip-2", + merchant_url, + "authorize-tip-1", + pickup_refs, + MHD_HTTP_OK), + /* This command tests the authorization of tip * against a reserve that does not exist. This is * implemented by passing a "tip instance" that * specifies a reserve key that was never used to * actually create a reserve. */// - TALER_TESTING_cmd_tip_authorize_with_ec ("authorize-tip-null", - merchant_url_internal ("nulltip"), - EXCHANGE_URL, - MHD_HTTP_SERVICE_UNAVAILABLE, - "tip 2", - "EUR:5.01", - TALER_EC_TIP_QUERY_RESERVE_UNKNOWN_TO_EXCHANGE), - TALER_TESTING_cmd_tip_query ("query-tip-1", - merchant_url_internal ("tip"), - MHD_HTTP_OK), - TALER_TESTING_cmd_tip_query_with_amounts ("query-tip-2", - merchant_url_internal ("tip"), - MHD_HTTP_OK, - "EUR:0.0", // picked - "EUR:10.02", // authorized - "EUR:20.04"),// available - TALER_TESTING_cmd_tip_pickup ("pickup-tip-1", - merchant_url_external ("tip"), - MHD_HTTP_OK, - "authorize-tip-1", - pickup_amounts_1), - TALER_TESTING_cmd_tip_query_with_amounts ("query-tip-3", - merchant_url_internal ("tip"), - MHD_HTTP_OK, - "EUR:5.01", // picked - NULL, // authorized - "EUR:15.03"),// available - TALER_TESTING_cmd_tip_pickup ("pickup-tip-2", - merchant_url_external ("tip"), - MHD_HTTP_OK, - "authorize-tip-2", - pickup_amounts_1), - TALER_TESTING_cmd_tip_query_with_amounts ("query-tip-4", - merchant_url_internal ("tip"), - MHD_HTTP_OK, - "EUR:10.02", // pick - "EUR:10.02", // authorized - "EUR:10.02"), // available - TALER_TESTING_cmd_admin_add_incoming_with_instance ( - "create-reserve-insufficient-funds", - "EUR:1.01", - &bc.exchange_auth, - payer_payto, - "dtip", - CONFIG_FILE), - TALER_TESTING_cmd_check_bank_admin_transfer ( - "check_bank_transfer-insufficient-tip-funds", - "EUR:1.01", - payer_payto, - exchange_payto, - "create-reserve-insufficient-funds"), - cmd_exec_wirewatch ("wirewatch-insufficient-tip-funds"), - TALER_TESTING_cmd_tip_authorize_with_ec ( - "authorize-tip-3-insufficient-funds", - merchant_url_internal ("dtip"), + TALER_TESTING_cmd_merchant_post_reserves_fake ("create-reserve-tip-2-fake"), + TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec ("authorize-tip-null", + merchant_url, + EXCHANGE_URL, + "create-reserve-tip-2-fake", + MHD_HTTP_NOT_FOUND, + "tip 3", + "EUR:5.01", + TALER_EC_TIP_AUTHORIZE_DB_RESERVE_NOT_FOUND), + + // Test reserve with insufficient funds + TALER_TESTING_cmd_merchant_post_reserves ("create-reserve-tip-2", + merchant_url, + "EUR:1.04", + EXCHANGE_URL, + "x-taler-bank", + MHD_HTTP_OK), + TALER_TESTING_cmd_admin_add_incoming_with_ref ("create-reserve-tip-2-exch", + "EUR:1.04", + &bc.exchange_auth, + payer_payto, + "create-reserve-tip-2"), + cmd_exec_wirewatch ("wirewatch-4"), + TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec ( + "authorize-tip-insufficient-funds", + merchant_url, EXCHANGE_URL, + "create-reserve-tip-2", MHD_HTTP_PRECONDITION_FAILED, - "tip 3", - "EUR:2.02", + "tip 4", + "EUR:5.01", TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS), - TALER_TESTING_cmd_tip_authorize_with_ec ("authorize-tip-4-unknown-instance", - merchant_url_internal ("unknown"), - EXCHANGE_URL, - MHD_HTTP_NOT_FOUND, - "tip 4", - "EUR:5.01", - TALER_EC_INSTANCE_UNKNOWN), - TALER_TESTING_cmd_tip_authorize_with_ec ("authorize-tip-5-notip-instance", - merchant_url, - EXCHANGE_URL, - MHD_HTTP_PRECONDITION_FAILED, - "tip 5", - "EUR:5.01", - TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP), - TALER_TESTING_cmd_tip_pickup_with_ec ("pickup-tip-3-too-much", - merchant_url_external ("tip"), - MHD_HTTP_CONFLICT, - "authorize-tip-1", - pickup_amounts_1, - TALER_EC_TIP_PICKUP_NO_FUNDS), + TALER_TESTING_cmd_tip_authorize_fake ("fake-tip-authorization"), TALER_TESTING_cmd_tip_pickup_with_ec ("pickup-non-existent-id", - merchant_url_external ("tip"), + merchant_url, MHD_HTTP_NOT_FOUND, "fake-tip-authorization", pickup_amounts_1, TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN), + + TALER_TESTING_cmd_merchant_delete_reserve ("delete-reserve-tip-1", + merchant_url, + "create-reserve-tip-1", + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-tip-2", + merchant_url, + "create-reserve-tip-1", + MHD_HTTP_NO_CONTENT), + TALER_TESTING_cmd_merchant_purge_reserve ("delete-reserve-tip-3", + merchant_url, + "create-reserve-tip-1", + MHD_HTTP_NOT_FOUND), +#if 0 TALER_TESTING_cmd_merchant_post_orders ("create-proposal-tip-1", merchant_url_internal ("tip"), MHD_HTTP_OK, diff --git a/src/testing/testing_api_cmd_get_reserve.c b/src/testing/testing_api_cmd_get_reserve.c index d617c182..2a685ae4 100644 --- a/src/testing/testing_api_cmd_get_reserve.c +++ b/src/testing/testing_api_cmd_get_reserve.c @@ -100,7 +100,7 @@ get_reserve_cb (void *cls, TALER_TESTING_get_trait_amount_obj (reserve_cmd, 0, &initial_amount)) - TALER_TESTING_FAIL (grs->is); + TALER_TESTING_interpreter_fail (grs->is); if ((GNUNET_OK != TALER_amount_cmp_currency (&rs->merchant_initial_amount, initial_amount)) || (0 != TALER_amount_cmp (&rs->merchant_initial_amount, diff --git a/src/testing/testing_api_cmd_merchant_get_tip.c b/src/testing/testing_api_cmd_merchant_get_tip.c index f70356c7..085f9575 100644 --- a/src/testing/testing_api_cmd_merchant_get_tip.c +++ b/src/testing/testing_api_cmd_merchant_get_tip.c @@ -43,6 +43,16 @@ struct MerchantTipGetState */ unsigned int http_status; + /** + * Whether to fetch and compare pickups. + */ + bool fetch_pickups; + + /** + * The NULL-terminated list of pickup commands associated with the tip. + */ + const char **pickup_refs; + /** * The handle to the current GET /tips/$TIP_ID request. */ @@ -86,8 +96,15 @@ merchant_get_tip_cb (void *cls, { /* FIXME, deeper checks should be implemented here. */ struct MerchantTipGetState *gts = cls; + const struct TALER_TESTING_Command *authorize_cmd; + struct TALER_Amount expected_total_picked_up; + + authorize_cmd = TALER_TESTING_interpreter_lookup_command (gts->is, + gts->tip_reference); gts->tgh = NULL; + GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (total_picked_up->currency, + &expected_total_picked_up)); if (gts->http_status != hr->http_status) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -103,6 +120,123 @@ merchant_get_tip_cb (void *cls, case MHD_HTTP_OK: // FIXME: use gts->tip_reference here to // check if the data returned matches that from the POST / PATCH + { + const struct TALER_Amount *initial_amount; + if (GNUNET_OK != + TALER_TESTING_get_trait_amount_obj (authorize_cmd, + 0, + &initial_amount)) + TALER_TESTING_FAIL (gts->is); + if ((GNUNET_OK != TALER_amount_cmp_currency (total_authorized, + initial_amount)) || + (0 != TALER_amount_cmp (total_authorized, + initial_amount))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Tip authorized amount does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const char *justification; + if (GNUNET_OK != + TALER_TESTING_get_trait_string (authorize_cmd, + 0, + &justification)) + TALER_TESTING_FAIL (gts->is); + if (0 != strcmp (reason, + justification)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Tip authorized reason does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const struct GNUNET_TIME_Absolute *tip_expiration; + if (GNUNET_OK != + TALER_TESTING_get_trait_absolute_time (authorize_cmd, + 0, + &tip_expiration)) + TALER_TESTING_FAIL (gts->is); + if (tip_expiration->abs_value_us != expiration.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Tip authorized expiration does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + for (unsigned int i = 0; i < pickups_length; ++i) + { + const struct TALER_TESTING_Command *pickup_cmd; + if (NULL == gts->pickup_refs[i]) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Length of pickup array does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + + pickup_cmd = TALER_TESTING_interpreter_lookup_command (gts->is, + gts->pickup_refs[ + i]); + { + const uint64_t *num_planchets; + + if (GNUNET_OK != + TALER_TESTING_get_trait_uint64 (pickup_cmd, + 0, + &num_planchets)) + TALER_TESTING_FAIL (gts->is); + + if (*num_planchets != pickups[i].num_planchets) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Pickup planchet count does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const struct TALER_Amount *total; + + if (GNUNET_OK != + TALER_TESTING_get_trait_amount_obj (pickup_cmd, + pickups[i].num_planchets, + &total)) + TALER_TESTING_FAIL (gts->is); + + if ((GNUNET_OK != TALER_amount_cmp_currency (total, + &pickups[i]. + requested_amount)) || + (0 != TALER_amount_cmp (total, + &pickups[i].requested_amount))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Pickup planchet sum does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + GNUNET_assert (0 < TALER_amount_add (&expected_total_picked_up, + &expected_total_picked_up, + total)); + } + } + if ((GNUNET_OK != TALER_amount_cmp_currency (&expected_total_picked_up, + total_picked_up)) || + (0 != TALER_amount_cmp (&expected_total_picked_up, + total_picked_up))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Tip picked up amount does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -141,7 +275,7 @@ merchant_get_tip_run (void *cls, tgs->tgh = TALER_MERCHANT_merchant_tip_get (is->ctx, tgs->merchant_url, tip_id, - false, + tgs->fetch_pickups, &merchant_get_tip_cb, tgs); GNUNET_assert (NULL != tgs->tgh); @@ -204,4 +338,43 @@ TALER_TESTING_cmd_merchant_get_tip (const char *label, } +/** + * Define a GET /private/tips/$TIP_ID CMD. + * + * @param label the command label + * @param merchant_url base URL of the merchant which will + * serve the request. + * @param tip_reference reference to a command that created a tip. + * @param pickup_refs a NULL-terminated list of pickup commands + * associated with the tip. + * @param http_status expected HTTP response code for the request. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_merchant_get_tip_with_pickups (const char *label, + const char *merchant_url, + const char *tip_reference, + const char *pickup_refs[], + unsigned int http_status) +{ + struct MerchantTipGetState *tgs; + + tgs = GNUNET_new (struct MerchantTipGetState); + tgs->merchant_url = merchant_url; + tgs->tip_reference = tip_reference; + tgs->fetch_pickups = true; + tgs->pickup_refs = pickup_refs; + tgs->http_status = http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = tgs, + .label = label, + .run = &merchant_get_tip_run, + .cleanup = &merchant_get_tip_cleanup + }; + + return cmd; + } +} + + /* end of testing_api_cmd_merchant_get_tip.c */ diff --git a/src/testing/testing_api_cmd_post_reserves.c b/src/testing/testing_api_cmd_post_reserves.c index 3d62d2f6..f25005c8 100644 --- a/src/testing/testing_api_cmd_post_reserves.c +++ b/src/testing/testing_api_cmd_post_reserves.c @@ -179,6 +179,34 @@ post_reserves_run (void *cls, } +/** + * Run the fake "POST /reserves" CMD. + * + * @param cls closure. + * @param cmd command being run now. + * @param is interpreter state. + */ +static void +post_reserves_fake_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct PostReservesState *prs = cls; + struct TALER_ReservePrivateKeyP reserve_priv; + + prs->is = is; + prs->reserve_pub = GNUNET_new (struct TALER_ReservePublicKeyP); + + GNUNET_CRYPTO_eddsa_key_create (&reserve_priv.eddsa_priv); + GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv.eddsa_priv, + &prs->reserve_pub->eddsa_pub); + + GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:100.00", + &prs->initial_balance)); + TALER_TESTING_interpreter_next (prs->is); +} + + /** * Free the state of a "POST /reserves" CMD, and possibly * cancel a pending operation thereof. @@ -244,3 +272,30 @@ TALER_TESTING_cmd_merchant_post_reserves (const char *label, return cmd; } } + + +/** + * This commands does not query the backend at all, + * but just makes up a fake reserve. + * + * @param label command label. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_merchant_post_reserves_fake (const char *label) +{ + struct PostReservesState *prs; + + prs = GNUNET_new (struct PostReservesState); + { + struct TALER_TESTING_Command cmd = { + .cls = prs, + .label = label, + .run = &post_reserves_fake_run, + .cleanup = &post_reserves_cleanup, + .traits = &post_reserves_traits + }; + + return cmd; + } +} diff --git a/src/testing/testing_api_cmd_tip_authorize.c b/src/testing/testing_api_cmd_tip_authorize.c index e51b70f4..83b472ab 100644 --- a/src/testing/testing_api_cmd_tip_authorize.c +++ b/src/testing/testing_api_cmd_tip_authorize.c @@ -46,6 +46,12 @@ struct TipAuthorizeState */ unsigned int http_status; + /** + * Reference to the reserv to authorize the tip + * from (if NULL, the merchant decides). + */ + const char *reserve_reference; + /** * Human-readable justification for the * tip authorization carried on by this CMD. @@ -55,7 +61,7 @@ struct TipAuthorizeState /** * Amount that should be authorized for tipping. */ - const char *amount; + struct TALER_Amount amount; /** * Expected Taler error code for this CMD. @@ -135,6 +141,7 @@ tip_authorize_cb (void *cls, { tas->tip_uri = strdup (taler_tip_uri); tas->tip_id = *tip_id; + tas->tip_expiration = expiration; } TALER_TESTING_interpreter_next (tas->is); } @@ -157,15 +164,21 @@ tip_authorize_traits (void *cls, unsigned int index) { struct TipAuthorizeState *tas = cls; - struct TALER_TESTING_Trait traits[] = { - TALER_TESTING_make_trait_tip_id (0, &tas->tip_id), - TALER_TESTING_trait_end (), - }; - - return TALER_TESTING_get_trait (traits, - ret, - trait, - index); + + { + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_tip_id (0, &tas->tip_id), + TALER_TESTING_make_trait_amount_obj (0, &tas->amount), + TALER_TESTING_make_trait_string (0, tas->justification), + TALER_TESTING_make_trait_absolute_time (0, &tas->tip_expiration), + TALER_TESTING_trait_end (), + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); + } } @@ -182,20 +195,39 @@ tip_authorize_run (void *cls, struct TALER_TESTING_Interpreter *is) { struct TipAuthorizeState *tas = cls; - struct TALER_Amount amount; tas->is = is; - if (GNUNET_OK != TALER_string_to_amount (tas->amount, - &amount)) - TALER_TESTING_FAIL (is); - - tas->tao = TALER_MERCHANT_tip_authorize (is->ctx, - tas->merchant_url, - "http://merchant.com/pickup", - &amount, - tas->justification, - &tip_authorize_cb, - tas); + if (NULL == tas->reserve_reference) + { + tas->tao = TALER_MERCHANT_tip_authorize (is->ctx, + tas->merchant_url, + "http://merchant.com/pickup", + &tas->amount, + tas->justification, + &tip_authorize_cb, + tas); + } + else + { + const struct TALER_TESTING_Command *reserve_cmd; + const struct TALER_ReservePublicKeyP *reserve_pub; + + reserve_cmd = TALER_TESTING_interpreter_lookup_command ( + tas->is, + tas->reserve_reference); + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_reserve_pub (reserve_cmd, + 0, + &reserve_pub)); + tas->tao = TALER_MERCHANT_tip_authorize2 (is->ctx, + tas->merchant_url, + reserve_pub, + "http://merchant.com/pickup", + &tas->amount, + tas->justification, + &tip_authorize_cb, + tas); + } GNUNET_assert (NULL != tas->tao); } @@ -277,9 +309,65 @@ TALER_TESTING_cmd_tip_authorize_with_ec (const char *label, tas = GNUNET_new (struct TipAuthorizeState); tas->merchant_url = merchant_url; tas->justification = justification; - tas->amount = amount; tas->http_status = http_status; tas->expected_ec = ec; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = tas, + .run = &tip_authorize_run, + .cleanup = &tip_authorize_cleanup, + .traits = &tip_authorize_traits + }; + + return cmd; + } +} + + +/** + * Create a /tip-authorize CMD, specifying the Taler error code + * that is expected to be returned by the backend. + * + * @param label this command label + * @param merchant_url the base URL of the merchant that will + * serve the /tip-authorize request. + * @param exchange_url the base URL of the exchange that owns + * the reserve from which the tip is going to be gotten. + * @param reserve_reference reference to a command that created + * a reserve. + * @param http_status the HTTP response code which is expected + * for this operation. + * @param justification human-readable justification for this + * tip authorization. + * @param amount the amount to authorize for tipping. + * @param ec expected Taler-defined error code. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_tip_authorize_from_reserve_with_ec (const char *label, + const char *merchant_url, + const char *exchange_url, + const char * + reserve_reference, + unsigned int http_status, + const char *justification, + const char *amount, + enum TALER_ErrorCode ec) +{ + struct TipAuthorizeState *tas; + + tas = GNUNET_new (struct TipAuthorizeState); + tas->merchant_url = merchant_url; + tas->justification = justification; + tas->http_status = http_status; + tas->expected_ec = ec; + tas->reserve_reference = reserve_reference; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); { struct TALER_TESTING_Command cmd = { .label = label, @@ -321,8 +409,59 @@ TALER_TESTING_cmd_tip_authorize (const char *label, tas = GNUNET_new (struct TipAuthorizeState); tas->merchant_url = merchant_url; tas->justification = justification; - tas->amount = amount; tas->http_status = http_status; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); + { + struct TALER_TESTING_Command cmd = { + .label = label, + .cls = tas, + .run = &tip_authorize_run, + .cleanup = &tip_authorize_cleanup, + .traits = &tip_authorize_traits + }; + + return cmd; + } +} + + +/** + * Create a /tip-authorize CMD. + * + * @param label this command label + * @param merchant_url the base URL of the merchant that will + * serve the /tip-authorize request. + * @param exchange_url the base URL of the exchange that owns + * the reserve from which the tip is going to be gotten. + * @param reserve_reference reference to a command that created + * a reserve. + * @param http_status the HTTP response code which is expected + * for this operation. + * @param justification human-readable justification for this + * tip authorization. + * @param amount the amount to authorize for tipping. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_tip_authorize_from_reserve (const char *label, + const char *merchant_url, + const char *exchange_url, + const char *reserve_refernce, + unsigned int http_status, + const char *justification, + const char *amount) +{ + struct TipAuthorizeState *tas; + + tas = GNUNET_new (struct TipAuthorizeState); + tas->merchant_url = merchant_url; + tas->reserve_reference = reserve_refernce; + tas->justification = justification; + tas->http_status = http_status; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (amount, + &tas->amount)); { struct TALER_TESTING_Command cmd = { .label = label, diff --git a/src/testing/testing_api_cmd_tip_pickup.c b/src/testing/testing_api_cmd_tip_pickup.c index d05b20d4..833ab6bc 100644 --- a/src/testing/testing_api_cmd_tip_pickup.c +++ b/src/testing/testing_api_cmd_tip_pickup.c @@ -84,10 +84,15 @@ struct TipPickupState */ struct TALER_Amount *amounts_obj; + /** + * The sum of the the amounts above. + */ + struct TALER_Amount total_amount; + /** * How many coins are involved in the tipping operation. */ - unsigned int num_coins; + uint64_t num_coins; /** * The array of denomination keys, in the same order of @a @@ -237,6 +242,15 @@ tip_pickup_run (void *cls, GNUNET_assert (GNUNET_OK == TALER_string_to_amount (tps->amounts[i], &tps->amounts_obj[i])); + if (0 == i) + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (tps->amounts_obj[i].currency, + &tps->total_amount)); + + GNUNET_assert (0 < + TALER_amount_add (&tps->total_amount, + &tps->total_amount, + &tps->amounts_obj[i])); tps->dks[i] = TALER_TESTING_find_pk (is->keys, &tps->amounts_obj[i]); if (NULL == tps->dks[i]) @@ -329,7 +343,7 @@ tip_pickup_traits (void *cls, unsigned int index) { struct TipPickupState *tps = cls; - #define NUM_TRAITS (tps->num_coins * 5) + 2 + #define NUM_TRAITS (tps->num_coins * 5) + 4 struct TALER_TESTING_Trait traits[NUM_TRAITS]; for (unsigned int i = 0; inum_coins; i++) @@ -345,6 +359,12 @@ tip_pickup_traits (void *cls, traits[i + (tps->num_coins * 4)] = TALER_TESTING_make_trait_amount_obj (i, &tps->amounts_obj[i]); } + traits[NUM_TRAITS - 4] + = TALER_TESTING_make_trait_amount_obj (tps->num_coins, + &tps->total_amount); + traits[NUM_TRAITS - 3] + = TALER_TESTING_make_trait_uint64 (0, + &tps->num_coins); traits[NUM_TRAITS - 2] = TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL, tps->exchange_url); diff --git a/src/testing/testing_api_cmd_wallet_get_tip.c b/src/testing/testing_api_cmd_wallet_get_tip.c index f76c3b69..0374adae 100644 --- a/src/testing/testing_api_cmd_wallet_get_tip.c +++ b/src/testing/testing_api_cmd_wallet_get_tip.c @@ -44,6 +44,16 @@ struct WalletTipGetState */ unsigned int http_status; + /** + * Whether to compare amounts or not. + */ + bool cmp_amounts; + + /** + * The expected amount remaining. + */ + struct TALER_Amount amount_remaining; + /** * The handle to the current GET /tips/$TIP_ID request. */ @@ -81,6 +91,11 @@ wallet_tip_get_cb (void *cls, { /* FIXME, deeper checks should be implemented here. */ struct WalletTipGetState *gts = cls; + const struct TALER_TESTING_Command *tip_cmd; + + tip_cmd = TALER_TESTING_interpreter_lookup_command ( + gts->is, + gts->tip_reference); gts->tgh = NULL; if (gts->http_status != hr->http_status) @@ -98,6 +113,35 @@ wallet_tip_get_cb (void *cls, case MHD_HTTP_OK: // FIXME: use gts->tip_reference here to // check if the data returned matches that from the POST / PATCH + if (gts->cmp_amounts) + { + if ((GNUNET_OK != TALER_amount_cmp_currency (>s->amount_remaining, + amount_remaining)) || + (0 != TALER_amount_cmp (>s->amount_remaining, + amount_remaining))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Amount remaining on tip does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } + { + const struct GNUNET_TIME_Absolute *expiration; + + if (GNUNET_OK != + TALER_TESTING_get_trait_absolute_time (tip_cmd, + 0, + &expiration)) + TALER_TESTING_interpreter_fail (gts->is); + if (expiration->abs_value_us != reserve_expiration.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Tip expiration does not match\n"); + TALER_TESTING_interpreter_fail (gts->is); + return; + } + } break; default: GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -197,4 +241,43 @@ TALER_TESTING_cmd_wallet_get_tip (const char *label, } +/** + * Define a GET /tips/$TIP_ID CMD. + * + * @param label the command label + * @param merchant_url base URL of the merchant which will + * serve the request. + * @param tip_reference reference to a command that created a tip. + * @param amount_remaining the balance remaining after pickups. + * @param http_status expected HTTP response code for the request. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_wallet_get_tip2 (const char *label, + const char *merchant_url, + const char *tip_reference, + const char *amount_remaining, + unsigned int http_status) +{ + struct WalletTipGetState *tgs; + + tgs = GNUNET_new (struct WalletTipGetState); + tgs->merchant_url = merchant_url; + tgs->tip_reference = tip_reference; + tgs->cmp_amounts = true; + GNUNET_assert (GNUNET_OK == TALER_string_to_amount (amount_remaining, + &tgs->amount_remaining)); + tgs->http_status = http_status; + { + struct TALER_TESTING_Command cmd = { + .cls = tgs, + .label = label, + .run = &wallet_get_tip_run, + .cleanup = &wallet_get_tip_cleanup + }; + + return cmd; + } +} + + /* end of testing_api_cmd_get_tip.c */ -- cgit v1.2.3