From b90d7d27871ca09772a5ff4a5af15928bf3e68cb Mon Sep 17 00:00:00 2001 From: Jonathan Buchanan Date: Sat, 1 Aug 2020 21:53:16 -0400 Subject: implementation/tests for idempotent POST /orders requests --- src/testing/test_merchant_api.c | 19 +++++--- src/testing/testing_api_cmd_post_orders.c | 81 +++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 10 deletions(-) (limited to 'src/testing') diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c index b8ef13c0..b4e06ed1 100644 --- a/src/testing/test_merchant_api.c +++ b/src/testing/test_merchant_api.c @@ -285,8 +285,8 @@ run (void *cls, "EUR:5.0", "x-taler-bank", "", - ""), - /* + "", + NULL), TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-1-idem", merchant_url, MHD_HTTP_OK, @@ -297,7 +297,8 @@ run (void *cls, "EUR:5.0", "x-taler-bank", "", - ""),*/ + "", + "create-proposal-1"), TALER_TESTING_cmd_merchant_claim_order ("reclaim-1", merchant_url, MHD_HTTP_OK, @@ -520,7 +521,8 @@ run (void *cls, "EUR:5.0", "unsupported-wire-method", "product-3/2", - ""), + "", + NULL), TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p3-pd-nx", merchant_url, MHD_HTTP_NOT_FOUND, @@ -531,7 +533,8 @@ run (void *cls, "EUR:5.0", "x-taler-bank", "unknown-product/2", - ""), + "", + NULL), TALER_TESTING_cmd_merchant_post_orders2 ( "create-proposal-p3-not-enough-stock", merchant_url, @@ -543,7 +546,8 @@ run (void *cls, "EUR:5.0", "x-taler-bank", "product-3/24", - ""), + "", + NULL), TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p3", merchant_url, MHD_HTTP_OK, @@ -554,7 +558,8 @@ run (void *cls, "EUR:5.0", "x-taler-bank", "product-3/3", - "lock-product-p3"), + "lock-product-p3", + NULL), TALER_TESTING_cmd_merchant_delete_order ("delete-order-1", merchant_url, "1", diff --git a/src/testing/testing_api_cmd_post_orders.c b/src/testing/testing_api_cmd_post_orders.c index f95d94ae..f7a8dbb8 100644 --- a/src/testing/testing_api_cmd_post_orders.c +++ b/src/testing/testing_api_cmd_post_orders.c @@ -50,6 +50,11 @@ struct OrdersState */ const char *order_id; + /** + * The order id we expect the merchant to assign (if not NULL). + */ + const char *expected_order_id; + /** * Contract terms obtained from the backend. */ @@ -126,6 +131,12 @@ struct OrdersState * Should the command also CLAIM the order? */ bool with_claim; + + /** + * If not NULL, the command should duplicate the request and verify the + * response is the same as in this command. + */ + const char *duplicate_of; }; @@ -154,6 +165,7 @@ orders_traits (void *cls, TALER_TESTING_make_trait_merchant_pub (0, &ps->merchant_pub), TALER_TESTING_make_trait_claim_nonce (0, &ps->nonce), TALER_TESTING_make_trait_claim_token (0, &ps->claim_token), + TALER_TESTING_make_trait_string (0, ps->order), TALER_TESTING_trait_end () }; @@ -262,6 +274,44 @@ order_cb (void *cls, { case MHD_HTTP_OK: ps->order_id = GNUNET_strdup (order_id); + if ((NULL != ps->expected_order_id) && + (0 != strcmp (order_id, + ps->expected_order_id))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Order id assigned does not match\n"); + TALER_TESTING_interpreter_fail (ps->is); + return; + } + if (NULL != ps->duplicate_of) + { + const struct TALER_TESTING_Command *order_cmd; + const struct TALER_ClaimTokenP *prev_token; + struct TALER_ClaimTokenP zero_token = {0}; + order_cmd = TALER_TESTING_interpreter_lookup_command ( + ps->is, + ps->duplicate_of); + if (GNUNET_OK != + TALER_TESTING_get_trait_claim_token (order_cmd, + 0, + &prev_token)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not fetch previous order claim token\n"); + TALER_TESTING_interpreter_fail (ps->is); + return; + } + if (NULL == claim_token) + prev_token = &zero_token; + if (0 != GNUNET_memcmp (prev_token, + claim_token)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Claim tokens for identical requests do not match\n"); + TALER_TESTING_interpreter_fail (ps->is); + return; + } + } break; default: { @@ -372,6 +422,7 @@ orders_run2 (void *cls, struct TALER_TESTING_Interpreter *is) { struct OrdersState *ps = cls; + const char *order_str = ps->order; json_t *order; json_error_t error; @@ -385,7 +436,24 @@ orders_run2 (void *cls, unsigned int locks_length = 0; ps->is = is; - order = json_loads (ps->order, + if (NULL != ps->duplicate_of) + { + const struct TALER_TESTING_Command *order_cmd; + order_cmd = TALER_TESTING_interpreter_lookup_command ( + is, + ps->duplicate_of); + if (GNUNET_OK != + TALER_TESTING_get_trait_string (order_cmd, + 0, + &order_str)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not fetch previous order string\n"); + TALER_TESTING_interpreter_fail (is); + return; + } + } + order = json_loads (order_str, JSON_REJECT_DUPLICATES, &error); if (NULL == order) @@ -644,6 +712,7 @@ TALER_TESTING_cmd_merchant_post_orders_no_claim (const char *label, amount, &ps->order); ps->http_status = http_status; + ps->expected_order_id = order_id; ps->merchant_url = merchant_url; ps->with_claim = false; { @@ -693,6 +762,7 @@ TALER_TESTING_cmd_merchant_post_orders (const char *label, amount, &ps->order); ps->http_status = http_status; + ps->expected_order_id = order_id; ps->merchant_url = merchant_url; ps->with_claim = true; { @@ -727,6 +797,8 @@ TALER_TESTING_cmd_merchant_post_orders (const char *label, * "[product_id]/[quantity];...". * @param locks a string of references to lock product commands that should * be formatted as "[lock_1];[lock_2];...". + * @param duplicate_of if not NULL, a reference to a previous order command + * that should be duplicated and checked for an identical response. * @return the command */ struct TALER_TESTING_Command @@ -742,7 +814,8 @@ TALER_TESTING_cmd_merchant_post_orders2 (const char *label, const char *amount, const char *payment_target, const char *products, - const char *locks) + const char *locks, + const char *duplicate_of) { struct OrdersState *ps; @@ -754,12 +827,14 @@ TALER_TESTING_cmd_merchant_post_orders2 (const char *label, &ps->order); ps->http_status = http_status; + ps->expected_order_id = order_id; ps->merchant_url = merchant_url; ps->payment_target = payment_target; ps->products = products; ps->locks = locks; - ps->with_claim = true; + ps->with_claim = (NULL == duplicate_of); ps->make_claim_token = claim_token; + ps->duplicate_of = duplicate_of; { struct TALER_TESTING_Command cmd = { .cls = ps, -- cgit v1.2.3