summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2020-08-27 13:57:21 -0400
committerJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2020-08-27 13:57:21 -0400
commit01d4723f8e58a7b68b0d814b58cc6c3e72702575 (patch)
tree60ef3ab071f68b8ced300e51a7fda89325fb28e7 /src
parentd354d119db7ca0195cb93140bf3160b11449fa92 (diff)
downloadmerchant-01d4723f8e58a7b68b0d814b58cc6c3e72702575.tar.gz
merchant-01d4723f8e58a7b68b0d814b58cc6c3e72702575.tar.bz2
merchant-01d4723f8e58a7b68b0d814b58cc6c3e72702575.zip
address some backend fixmes
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd_private-get-products-ID.c8
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c249
-rw-r--r--src/include/taler_merchant_testing_lib.h21
-rw-r--r--src/testing/test_merchant_api.c5
4 files changed, 168 insertions, 115 deletions
diff --git a/src/backend/taler-merchant-httpd_private-get-products-ID.c b/src/backend/taler-merchant-httpd_private-get-products-ID.c
index 41ef612d..f446ac21 100644
--- a/src/backend/taler-merchant-httpd_private-get-products-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-products-ID.c
@@ -53,7 +53,13 @@ TMH_private_get_products_ID (const struct TMH_RequestHandler *rh,
TALER_EC_GET_PRODUCTS_DB_LOOKUP_ERROR,
NULL);
}
- // FIXME: MUST return 404 if qs == 0, not this!
+ else if (0 == qs)
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_GET_PRODUCTS_NOT_FOUND,
+ NULL);
+ }
{
json_t *reply;
diff --git a/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c b/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c
index ce79037e..d2d7d65f 100644
--- a/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c
+++ b/src/backend/taler-merchant-httpd_private-patch-orders-ID-forget.c
@@ -28,6 +28,12 @@
/**
+ * How often do we retry the UPDATE database transaction?
+ */
+#define MAX_RETRIES 3
+
+
+/**
* Forget part of the contract terms.
*
* @param cls pointer to the result of the forget operation.
@@ -66,132 +72,147 @@ TMH_private_patch_orders_ID_forget (const struct TMH_RequestHandler *rh,
json_t *contract_terms;
uint64_t order_serial;
- // FIXME: should be a transaction with the update!
- qs = TMH_db->lookup_contract_terms (TMH_db->cls,
- hc->instance->settings.id,
- order_id,
- &contract_terms,
- &order_serial);
- switch (qs)
- {
- case GNUNET_DB_STATUS_HARD_ERROR:
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_ORDERS_CLAIM_HARD_DB_ERROR,
- NULL);
- case GNUNET_DB_STATUS_SOFT_ERROR:
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_ORDERS_CLAIM_SOFT_DB_ERROR,
- NULL);
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_FORGET_ORDER_NOT_FOUND,
- order_id);
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- GNUNET_assert (NULL != contract_terms);
- break;
- }
-
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_json ("fields",
- &fields),
- GNUNET_JSON_spec_end ()
- };
- enum GNUNET_GenericReturnValue res;
-
- res = TALER_MHD_parse_json_data (connection,
- hc->request_body,
- spec);
- if (GNUNET_OK != res)
- return (GNUNET_NO == res)
- ? MHD_YES
- : MHD_NO;
- }
- if (! (json_is_array (fields)))
+ for (unsigned int i = 0; i<MAX_RETRIES; i++)
{
- json_decref (contract_terms);
- json_decref (fields);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_PARAMETER_MALFORMED,
- "fields");
- }
-
- {
- size_t index;
- json_t *value;
- json_array_foreach (fields, index, value) {
- int forget_status = GNUNET_OK;
- int expand_status;
+ if (GNUNET_OK !=
+ TMH_db->start (TMH_db->cls,
+ "forget order"))
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_FORGET_ORDER_DB_START_ERROR,
+ NULL);
+ }
+ qs = TMH_db->lookup_contract_terms (TMH_db->cls,
+ hc->instance->settings.id,
+ order_id,
+ &contract_terms,
+ &order_serial);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ TMH_db->rollback (TMH_db->cls);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_ORDERS_CLAIM_HARD_DB_ERROR,
+ NULL);
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ TMH_db->rollback (TMH_db->cls);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_FORGET_ORDER_NOT_FOUND,
+ order_id);
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ GNUNET_assert (NULL != contract_terms);
+ break;
+ }
- if (! (json_is_string (value)))
- {
- json_decref (contract_terms);
- json_decref (fields);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_FORGET_PATH_SYNTAX_INCORRECT,
- "field is not a string");
- }
- expand_status = TALER_JSON_expand_path (contract_terms,
- json_string_value (value),
- &forget,
- &forget_status);
- if (GNUNET_SYSERR == forget_status)
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("fields",
+ &fields),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+
+ res = TALER_MHD_parse_json_data (connection,
+ hc->request_body,
+ spec);
+ if (GNUNET_OK != res)
{
- /* We tried to forget a field that isn't forgettable */
- json_decref (contract_terms);
- json_decref (fields);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_CONFLICT,
- TALER_EC_FORGET_PATH_NOT_FORGETTABLE,
- json_string_value (value));
- }
- if (GNUNET_SYSERR == expand_status)
- {
- /* One of the paths was malformed and couldn't be expanded */
- json_decref (contract_terms);
- json_decref (fields);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_FORGET_PATH_SYNTAX_INCORRECT,
- json_string_value (value));
+ TMH_db->rollback (TMH_db->cls);
+ return (GNUNET_NO == res)
+ ? MHD_YES
+ : MHD_NO;
}
}
- }
+ if (! (json_is_array (fields)))
+ {
+ TMH_db->rollback (TMH_db->cls);
+ json_decref (contract_terms);
+ json_decref (fields);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_PARAMETER_MALFORMED,
+ "fields");
+ }
- qs = TMH_db->update_contract_terms (TMH_db->cls,
- hc->instance->settings.id,
- order_id,
- contract_terms);
+ {
+ size_t index;
+ json_t *value;
+ json_array_foreach (fields, index, value) {
+ int forget_status = GNUNET_OK;
+ int expand_status;
+
+ if (! (json_is_string (value)))
+ {
+ TMH_db->rollback (TMH_db->cls);
+ json_decref (contract_terms);
+ json_decref (fields);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_FORGET_PATH_SYNTAX_INCORRECT,
+ "field is not a string");
+ }
+ expand_status = TALER_JSON_expand_path (contract_terms,
+ json_string_value (value),
+ &forget,
+ &forget_status);
+ if (GNUNET_SYSERR == forget_status)
+ {
+ /* We tried to forget a field that isn't forgettable */
+ TMH_db->rollback (TMH_db->cls);
+ json_decref (contract_terms);
+ json_decref (fields);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_CONFLICT,
+ TALER_EC_FORGET_PATH_NOT_FORGETTABLE,
+ json_string_value (value));
+ }
+ if (GNUNET_SYSERR == expand_status)
+ {
+ /* One of the paths was malformed and couldn't be expanded */
+ TMH_db->rollback (TMH_db->cls);
+ json_decref (contract_terms);
+ json_decref (fields);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_FORGET_PATH_SYNTAX_INCORRECT,
+ json_string_value (value));
+ }
+ }
+ }
- switch (qs)
+ qs = TMH_db->update_contract_terms (TMH_db->cls,
+ hc->instance->settings.id,
+ order_id,
+ contract_terms);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+ {
+ TMH_db->rollback (TMH_db->cls);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto retry;
+ else
+ goto giveup;
+ }
+ qs = TMH_db->commit (TMH_db->cls);
+retry:
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ continue;
+ break;
+ }
+giveup:
+ json_decref (contract_terms);
+ json_decref (fields);
+ if (0 > qs)
{
- case GNUNET_DB_STATUS_HARD_ERROR:
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_ORDERS_CLAIM_HARD_DB_ERROR,
- NULL);
- case GNUNET_DB_STATUS_SOFT_ERROR:
- // FIXME: We should not re-try a few times AND make this a larger transaction!
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_ORDERS_CLAIM_SOFT_DB_ERROR,
+ TALER_EC_FORGET_ORDER_DB_COMMIT_ERROR,
NULL);
- case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_FORGET_ORDER_NOT_FOUND,
- order_id);
- case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
- break;
}
- json_decref (contract_terms);
- json_decref (fields);
return TALER_MHD_reply_static (connection,
MHD_HTTP_OK,
diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h
index 98751ce9..aa0211a9 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -614,6 +614,27 @@ TALER_TESTING_cmd_wallet_get_order (const char *label,
/**
+ * Start a long poll for GET /private/orders/$ORDER_ID.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wallet_poll_order_start (
+ const char *label,
+ const char *merchant_url,
+ const char *order_id,
+ struct GNUNET_TIME_Relative timeout);
+
+
+/**
+ * Complete a long poll for GET /private/orders/$ORDER_ID.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wallet_poll_order_conclude (
+ const char *label,
+ unsigned int http_status,
+ const char *poll_start_reference);
+
+
+/**
* Define a GET /private/orders/$ORDER_ID CMD.
*
* @param label the command label
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index d4348bff..9c5a8d3b 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -1364,6 +1364,11 @@ run (void *cls,
"product-2",
MHD_HTTP_OK,
"patch-products-p2"),
+ TALER_TESTING_cmd_merchant_get_product ("get-product-nx",
+ merchant_url,
+ "product-nx",
+ MHD_HTTP_NOT_FOUND,
+ NULL),
TALER_TESTING_cmd_merchant_patch_product ("patch-products-p3-nx",
merchant_url,
"product-3",