gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] 43/277: toward stesting


From: gnunet
Subject: [taler-merchant] 43/277: toward stesting
Date: Sun, 05 Jul 2020 20:49:16 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository merchant.

commit f4b19c002aa3ef8054729f7e61254232d575b7a6
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Fri Apr 24 17:53:31 2020 +0200

    toward stesting
---
 src/backend/taler-merchant-httpd.c           |   8 +-
 src/include/taler_merchant_service.h         |  30 +--
 src/include/taler_merchant_testing_lib.h     | 102 ++++++++-
 src/lib/merchant_api_delete_product.c        |  15 +-
 src/lib/merchant_api_get_product.c           |  15 +-
 src/lib/merchant_api_get_products.c          |  21 +-
 src/lib/merchant_api_lock_product.c          |  15 +-
 src/lib/merchant_api_patch_product.c         |  15 +-
 src/lib/merchant_api_post_products.c         |  21 +-
 src/testing/Makefile.am                      |   5 +
 src/testing/testing_api_cmd_delete_product.c | 182 ++++++++++++++++
 src/testing/testing_api_cmd_get_product.c    | 224 +++++++++++++++++++
 src/testing/testing_api_cmd_get_products.c   | 181 +++++++++++++++
 src/testing/testing_api_cmd_lock_product.c   | 200 +++++++++++++++++
 src/testing/testing_api_cmd_patch_product.c  | 283 ++++++++++++++++++++++++
 src/testing/testing_api_cmd_post_products.c  | 315 +++++++++++++++++++++++++++
 16 files changed, 1514 insertions(+), 118 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 4efa6ad..25c7bab 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -955,8 +955,8 @@ url_handler (void *cls,
       handlers = public_handlers;
     }
   }
-  if (strcmp (url,
-              ""))
+  if (0 == strcmp (url,
+                   ""))
     url = "/"; /* code below does not like empty string */
 
   {
@@ -1010,8 +1010,8 @@ url_handler (void *cls,
         if ( (NULL == infix_url)
              ^ (GNUNET_NO == rh->have_id_segment) )
           continue; /* infix existence missmatch */
-        if ( (NULL == suffix_url)
-             ^ (NULL != rh->url_suffix) )
+        if ( ( (NULL == suffix_url)
+               ^ (NULL == rh->url_suffix) ) )
           continue; /* suffix existence missmatch */
         if ( (NULL != suffix_url) &&
              ( (suffix_strlen != strlen (rh->url_suffix)) ||
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 42ea1fa..435f65d 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -421,7 +421,7 @@ typedef void
 
 
 /**
- * Setup an new instance in the backend.
+ * Modify an existing instance in the backend.
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
@@ -722,7 +722,7 @@ struct TALER_MERCHANT_InventoryEntry
 typedef void
 (*TALER_MERCHANT_ProductsGetCallback)(
   void *cls,
-  struct TALER_MERCHANT_HttpResponse *hr,
+  const struct TALER_MERCHANT_HttpResponse *hr,
   unsigned int products_length,
   const struct TALER_MERCHANT_InventoryEntry products[]);
 
@@ -732,8 +732,6 @@ typedef void
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param cb function to call with the backend's inventory information
  * @param cb_cls closure for @a cb
  * @return the request handle; NULL upon error
@@ -742,7 +740,6 @@ struct TALER_MERCHANT_ProductsGetHandle *
 TALER_MERCHANT_products_get (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   TALER_MERCHANT_ProductsGetCallback cb,
   void *cb_cls);
 
@@ -793,7 +790,7 @@ struct TALER_MERCHANT_ProductGetHandle;
 typedef void
 (*TALER_MERCHANT_ProductGetCallback)(
   void *cls,
-  struct TALER_MERCHANT_HttpResponse *hr,
+  const struct TALER_MERCHANT_HttpResponse *hr,
   const char *description,
   const json_t *description_i18n,
   const char *unit,
@@ -813,8 +810,6 @@ typedef void
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param product_id identifier of the product to inquire about
  * @param cb function to call with the backend's product information
  * @param cb_cls closure for @a cb
@@ -824,7 +819,6 @@ struct TALER_MERCHANT_ProductGetHandle *
 TALER_MERCHANT_product_get (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   TALER_MERCHANT_ProductGetCallback cb,
   void *cb_cls);
@@ -864,8 +858,6 @@ typedef void
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to add a product to,
- *                    NULL to query the default instance
  * @param product_id identifier to use for the product
  * @param description description of the product
  * @param description_i18n Map from IETF BCP 47 language tags to localized 
descriptions
@@ -888,7 +880,6 @@ struct TALER_MERCHANT_ProductsPostHandle *
 TALER_MERCHANT_products_post (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   const char *description,
   const json_t *description_i18n,
@@ -928,7 +919,7 @@ struct TALER_MERCHANT_ProductPatchHandle;
 typedef void
 (*TALER_MERCHANT_ProductPatchCallback)(
   void *cls,
-  struct TALER_MERCHANT_HttpResponse *hr);
+  const struct TALER_MERCHANT_HttpResponse *hr);
 
 
 /**
@@ -937,8 +928,6 @@ typedef void
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to add a product to,
- *                    NULL to query the default instance
  * @param product_id identifier to use for the product; the product must exist,
  *                    or the transaction will fail with a #MHD_HTTP_NOT_FOUND
  *                    HTTP status code
@@ -966,7 +955,6 @@ struct TALER_MERCHANT_ProductPatchHandle *
 TALER_MERCHANT_product_patch (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   const char *description,
   const json_t *description_i18n,
@@ -1007,7 +995,7 @@ struct TALER_MERCHANT_ProductLockHandle;
 typedef void
 (*TALER_MERCHANT_ProductLockCallback)(
   void *cls,
-  struct TALER_MERCHANT_HttpResponse *hr);
+  const struct TALER_MERCHANT_HttpResponse *hr);
 
 
 /**
@@ -1016,8 +1004,6 @@ typedef void
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param product_id identifier of the product
  * @param uuid UUID that identifies the client holding the lock
  * @param duration how long should the lock be held
@@ -1030,7 +1016,6 @@ struct TALER_MERCHANT_ProductLockHandle *
 TALER_MERCHANT_product_lock (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   const struct GNUNET_Uuid *uuid,
   struct GNUNET_TIME_Relative duration,
@@ -1065,7 +1050,7 @@ struct TALER_MERCHANT_ProductDeleteHandle;
 typedef void
 (*TALER_MERCHANT_ProductDeleteCallback)(
   void *cls,
-  struct TALER_MERCHANT_HttpResponse *hr);
+  const struct TALER_MERCHANT_HttpResponse *hr);
 
 
 /**
@@ -1074,8 +1059,6 @@ typedef void
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param product_id identifier of the product
  * @param cb function to call with the backend's deletion status
  * @param cb_cls closure for @a cb
@@ -1085,7 +1068,6 @@ struct TALER_MERCHANT_ProductDeleteHandle *
 TALER_MERCHANT_product_delete (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   TALER_MERCHANT_ProductDeleteCallback cb,
   void *cb_cls);
diff --git a/src/include/taler_merchant_testing_lib.h 
b/src/include/taler_merchant_testing_lib.h
index 95f945c..d9d3c8e 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -256,8 +256,6 @@ TALER_TESTING_cmd_merchant_delete_instance (const char 
*label,
  * @param label command label.
  * @param merchant_url base URL of the merchant serving the
  *        POST /products request.
- * @param instance_id instance to add a product to,
- *                    NULL to query the default instance
  * @param product_id the ID of the product to query
  * @param description description of the product
  * @param description_i18n Map from IETF BCP 47 language tags to localized 
descriptions
@@ -280,7 +278,6 @@ TALER_TESTING_cmd_merchant_post_products2 (
   const char *label,
   const char *merchant_url,
   const char *product_id,
-  const char *instance_id,
   const char *description,
   json_t *description_i18n,
   const char *unit,
@@ -299,8 +296,6 @@ TALER_TESTING_cmd_merchant_post_products2 (
  * @param label command label.
  * @param merchant_url base URL of the merchant serving the
  *        POST /products request.
- * @param instance_id instance to add a product to,
- *                    NULL to query the default instance
  * @param product_id the ID of the product to create
  * @param description name of the product
  * @param price price of the product
@@ -310,13 +305,108 @@ TALER_TESTING_cmd_merchant_post_products2 (
 struct TALER_TESTING_Command
 TALER_TESTING_cmd_merchant_post_products (const char *label,
                                           const char *merchant_url,
-                                          const char *instance_id,
                                           const char *product_id,
                                           const char *description,
                                           const char *price,
                                           unsigned int http_status);
 
 
+/**
+ * Define a "PATCH /products/$ID" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        PATCH /product request.
+ * @param product_id the ID of the product to query
+ * @param description description of the product
+ * @param description_i18n Map from IETF BCP 47 language tags to localized 
descriptions
+ * @param unit unit in which the product is measured (liters, kilograms, 
packages, etc.)
+ * @param price the price for one @a unit of the product, zero is used to 
imply that
+ *              this product is not sold separately or that the price is not 
fixed and
+ *              must be supplied by the front-end.  If non-zero, price must 
include
+ *              applicable taxes.
+ * @param image base64-encoded product image
+ * @param taxes list of taxes paid by the merchant
+ * @param total_stocked in @a units, -1 to indicate "infinite" (i.e. 
electronic books)
+ * @param total_lost in @a units, must be larger than previous values, and may
+ *               not exceed total_stocked minus total_sold; if it does, the 
transaction
+ *               will fail with a #MHD_HTTP_CONFLICT HTTP status code
+ * @param address where the product is in stock
+ * @param next_restock when the next restocking is expected to happen, 0 for 
unknown,
+ *                     #GNUNET_TIME_UNIT_FOREVER_ABS for 'never'.
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_patch_product (
+  const char *label,
+  const char *merchant_url,
+  const char *product_id,
+  const char *description,
+  json_t *description_i18n,
+  const char *unit,
+  const struct TALER_Amount *price,
+  json_t *image,
+  json_t *taxes,
+  int64_t total_stocked,
+  uint64_t total_lost,
+  json_t *address,
+  struct GNUNET_TIME_Absolute next_restock,
+  unsigned int http_status);
+
+
+/**
+ * Define a "GET /products" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        GET /products request.
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_products (const char *label,
+                                         const char *merchant_url,
+                                         unsigned int http_status);
+
+
+/**
+ * Define a "GET product" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        GET /products/$ID request.
+ * @param product_id the ID of the product to query
+ * @param http_status expected HTTP response code.
+ * @param product_reference reference to a "POST /products" or "PATCH 
/products/$ID" CMD
+ *        that will provide what we expect the backend to return to us
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_product (const char *label,
+                                        const char *merchant_url,
+                                        const char *product_id,
+                                        unsigned int http_status,
+                                        const char *product_reference);
+
+
+/**
+ * Define a "DELETE product" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        DELETE /products/$ID request.
+ * @param product_id the ID of the product to query
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_delete_product (const char *label,
+                                           const char *merchant_url,
+                                           const char *product_id,
+                                           unsigned int http_status);
+
+
 /* ******************** OLD ******************* */
 
 /**
diff --git a/src/lib/merchant_api_delete_product.c 
b/src/lib/merchant_api_delete_product.c
index e00f0a3..e406581 100644
--- a/src/lib/merchant_api_delete_product.c
+++ b/src/lib/merchant_api_delete_product.c
@@ -121,8 +121,6 @@ handle_delete_product_finished (void *cls,
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param product_id identifier of the product
  * @param cb function to call with the backend's deletion status
  * @param cb_cls closure for @a cb
@@ -132,7 +130,6 @@ struct TALER_MERCHANT_ProductDeleteHandle *
 TALER_MERCHANT_product_delete (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   TALER_MERCHANT_ProductDeleteCallback cb,
   void *cb_cls)
@@ -146,15 +143,9 @@ TALER_MERCHANT_product_delete (
   {
     char *path;
 
-    if (NULL == instance_id)
-      GNUNET_asprintf (&path,
-                       "products/%s",
-                       product_id);
-    else
-      GNUNET_asprintf (&path,
-                       "instances/%s/products/%s",
-                       instance_id,
-                       product_id);
+    GNUNET_asprintf (&path,
+                     "products/%s",
+                     product_id);
     pdh->url = TALER_url_join (backend_url,
                                path,
                                NULL);
diff --git a/src/lib/merchant_api_get_product.c 
b/src/lib/merchant_api_get_product.c
index f0f7cca..fc33ded 100644
--- a/src/lib/merchant_api_get_product.c
+++ b/src/lib/merchant_api_get_product.c
@@ -188,8 +188,6 @@ handle_get_product_finished (void *cls,
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param product_id identifier of the product to inquire about
  * @param cb function to call with the backend's product information
  * @param cb_cls closure for @a cb
@@ -199,7 +197,6 @@ struct TALER_MERCHANT_ProductGetHandle *
 TALER_MERCHANT_product_get (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   TALER_MERCHANT_ProductGetCallback cb,
   void *cb_cls)
@@ -214,15 +211,9 @@ TALER_MERCHANT_product_get (
   {
     char *path;
 
-    if (NULL == instance_id)
-      GNUNET_asprintf (&path,
-                       "products/%s",
-                       product_id);
-    else
-      GNUNET_asprintf (&path,
-                       "instances/%s/products/%s",
-                       instance_id,
-                       product_id);
+    GNUNET_asprintf (&path,
+                     "products/%s",
+                     product_id);
     pgh->url = TALER_url_join (backend_url,
                                path,
                                NULL);
diff --git a/src/lib/merchant_api_get_products.c 
b/src/lib/merchant_api_get_products.c
index 3c7eae5..86e93cd 100644
--- a/src/lib/merchant_api_get_products.c
+++ b/src/lib/merchant_api_get_products.c
@@ -203,8 +203,6 @@ handle_get_products_finished (void *cls,
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param cb function to call with the backend's inventory information
  * @param cb_cls closure for @a cb
  * @return the request handle; NULL upon error
@@ -213,7 +211,6 @@ struct TALER_MERCHANT_ProductsGetHandle *
 TALER_MERCHANT_products_get (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   TALER_MERCHANT_ProductsGetCallback cb,
   void *cb_cls)
 {
@@ -224,21 +221,9 @@ TALER_MERCHANT_products_get (
   pgh->ctx = ctx;
   pgh->cb = cb;
   pgh->cb_cls = cb_cls;
-  {
-    char *path;
-
-    if (NULL == instance_id)
-      GNUNET_asprintf (&path,
-                       "products");
-    else
-      GNUNET_asprintf (&path,
-                       "instances/%s/products",
-                       instance_id);
-    pgh->url = TALER_url_join (backend_url,
-                               path,
-                               NULL);
-    GNUNET_free (path);
-  }
+  pgh->url = TALER_url_join (backend_url,
+                             "products",
+                             NULL);
   if (NULL == pgh->url)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/lib/merchant_api_lock_product.c 
b/src/lib/merchant_api_lock_product.c
index ddd5e8e..9a83150 100644
--- a/src/lib/merchant_api_lock_product.c
+++ b/src/lib/merchant_api_lock_product.c
@@ -155,8 +155,6 @@ handle_lock_product_finished (void *cls,
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to query about its products,
- *                    NULL to query the default instance
  * @param product_id identifier of the product
  * @param uuid UUID that identifies the client holding the lock
  * @param duration how long should the lock be held
@@ -169,7 +167,6 @@ struct TALER_MERCHANT_ProductLockHandle *
 TALER_MERCHANT_product_lock (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   const struct GNUNET_Uuid *uuid,
   struct GNUNET_TIME_Relative duration,
@@ -199,15 +196,9 @@ TALER_MERCHANT_product_lock (
   {
     char *path;
 
-    if (NULL == instance_id)
-      GNUNET_asprintf (&path,
-                       "products/%s/lock",
-                       product_id);
-    else
-      GNUNET_asprintf (&path,
-                       "instances/%s/products/%s/lock",
-                       instance_id,
-                       product_id);
+    GNUNET_asprintf (&path,
+                     "products/%s/lock",
+                     product_id);
     plh->url = TALER_url_join (backend_url,
                                path,
                                NULL);
diff --git a/src/lib/merchant_api_patch_product.c 
b/src/lib/merchant_api_patch_product.c
index d90ae58..9b0aead 100644
--- a/src/lib/merchant_api_patch_product.c
+++ b/src/lib/merchant_api_patch_product.c
@@ -155,8 +155,6 @@ handle_patch_product_finished (void *cls,
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to add a product to,
- *                    NULL to query the default instance
  * @param product_id identifier to use for the product; the product must exist,
  *                    or the transaction will fail with a #MHD_HTTP_NOT_FOUND
  *                    HTTP status code
@@ -184,7 +182,6 @@ struct TALER_MERCHANT_ProductPatchHandle *
 TALER_MERCHANT_product_patch (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   const char *description,
   const json_t *description_i18n,
@@ -237,15 +234,9 @@ TALER_MERCHANT_product_patch (
   {
     char *path;
 
-    if (NULL == instance_id)
-      GNUNET_asprintf (&path,
-                       "products/%s",
-                       product_id);
-    else
-      GNUNET_asprintf (&path,
-                       "instances/%s/products/%s",
-                       instance_id,
-                       product_id);
+    GNUNET_asprintf (&path,
+                     "products/%s",
+                     product_id);
     pph->url = TALER_url_join (backend_url,
                                path,
                                NULL);
diff --git a/src/lib/merchant_api_post_products.c 
b/src/lib/merchant_api_post_products.c
index b15866d..77cc859 100644
--- a/src/lib/merchant_api_post_products.c
+++ b/src/lib/merchant_api_post_products.c
@@ -157,8 +157,6 @@ handle_post_products_finished (void *cls,
  *
  * @param ctx the context
  * @param backend_url HTTP base URL for the backend
- * @param instance_id instance to add a product to,
- *                    NULL to query the default instance
  * @param product_id identifier to use for the product
  * @param description description of the product
  * @param description_i18n Map from IETF BCP 47 language tags to localized 
descriptions
@@ -181,7 +179,6 @@ struct TALER_MERCHANT_ProductsPostHandle *
 TALER_MERCHANT_products_post (
   struct GNUNET_CURL_Context *ctx,
   const char *backend_url,
-  const char *instance_id,
   const char *product_id,
   const char *description,
   const json_t *description_i18n,
@@ -230,21 +227,9 @@ TALER_MERCHANT_products_post (
   pph->ctx = ctx;
   pph->cb = cb;
   pph->cb_cls = cb_cls;
-  {
-    char *path;
-
-    if (NULL == instance_id)
-      GNUNET_asprintf (&path,
-                       "products");
-    else
-      GNUNET_asprintf (&path,
-                       "instances/%s/products",
-                       instance_id);
-    pph->url = TALER_url_join (backend_url,
-                               path,
-                               NULL);
-    GNUNET_free (path);
-  }
+  pph->url = TALER_url_join (backend_url,
+                             "products",
+                             NULL);
   if (NULL == pph->url)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 3aecec6..df922b0 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -17,10 +17,15 @@ libtalermerchanttesting_la_SOURCES = \
   testing_api_cmd_config.c \
   testing_api_cmd_get_instance.c \
   testing_api_cmd_get_instances.c \
+  testing_api_cmd_get_product.c \
+  testing_api_cmd_get_products.c \
   testing_api_cmd_delete_instance.c \
+  testing_api_cmd_delete_product.c \
+  testing_api_cmd_lock_product.c \
   testing_api_cmd_post_instances.c \
   testing_api_cmd_post_products.c \
   testing_api_cmd_patch_instance.c \
+  testing_api_cmd_patch_product.c \
    \
   testing_api_cmd_check_payment.c \
   testing_api_cmd_history.c \
diff --git a/src/testing/testing_api_cmd_delete_product.c 
b/src/testing/testing_api_cmd_delete_product.c
new file mode 100644
index 0000000..f306c76
--- /dev/null
+++ b/src/testing/testing_api_cmd_delete_product.c
@@ -0,0 +1,182 @@
+/*
+  This file is part of TALER
+  Copyright (C) 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
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_delete_product.c
+ * @brief command to test DELETE /product/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "DELETE /products/$ID" CMD.
+ */
+struct DeleteProductState
+{
+
+  /**
+   * Handle for a "DELETE product" request.
+   */
+  struct TALER_MERCHANT_ProductDeleteHandle *pdh;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Base URL of the merchant serving the request.
+   */
+  const char *merchant_url;
+
+  /**
+   * ID of the product to run DELETE for.
+   */
+  const char *product_id;
+
+  /**
+   * Expected HTTP response code.
+   */
+  unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a /delete/products/$ID operation.
+ *
+ * @param cls closure for this function
+ */
+static void
+delete_product_cb (void *cls,
+                   const struct TALER_MERCHANT_HttpResponse *hr)
+{
+  struct DeleteProductState *dis = cls;
+
+  dis->pdh = NULL;
+  if (dis->http_status != hr->http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u (%d) to command %s\n",
+                hr->http_status,
+                (int) hr->ec,
+                TALER_TESTING_interpreter_get_current_label (dis->is));
+    TALER_TESTING_interpreter_fail (dis->is);
+    return;
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unhandled HTTP status.\n");
+  }
+  TALER_TESTING_interpreter_next (dis->is);
+}
+
+
+/**
+ * Run the "DELETE product" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+delete_product_run (void *cls,
+                    const struct TALER_TESTING_Command *cmd,
+                    struct TALER_TESTING_Interpreter *is)
+{
+  struct DeleteProductState *dis = cls;
+
+  dis->is = is;
+  dis->pdh = TALER_MERCHANT_product_delete (is->ctx,
+                                            dis->merchant_url,
+                                            dis->product_id,
+                                            &delete_product_cb,
+                                            dis);
+  GNUNET_assert (NULL != dis->pdh);
+}
+
+
+/**
+ * Free the state of a "DELETE product" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+delete_product_cleanup (void *cls,
+                        const struct TALER_TESTING_Command *cmd)
+{
+  struct DeleteProductState *dis = cls;
+
+  if (NULL != dis->pdh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "DELETE /products/$ID operation did not complete\n");
+    TALER_MERCHANT_product_delete_cancel (dis->pdh);
+  }
+  GNUNET_free (dis);
+}
+
+
+/**
+ * Define a "DELETE product" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        DELETE /products/$ID request.
+ * @param product_id the ID of the product to query
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_delete_product (const char *label,
+                                           const char *merchant_url,
+                                           const char *product_id,
+                                           unsigned int http_status)
+{
+  struct DeleteProductState *dis;
+
+  dis = GNUNET_new (struct DeleteProductState);
+  dis->merchant_url = merchant_url;
+  dis->product_id = product_id;
+  dis->http_status = http_status;
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = dis,
+      .label = label,
+      .run = &delete_product_run,
+      .cleanup = &delete_product_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
+/* end of testing_api_cmd_delete_product.c */
diff --git a/src/testing/testing_api_cmd_get_product.c 
b/src/testing/testing_api_cmd_get_product.c
new file mode 100644
index 0000000..43d39bb
--- /dev/null
+++ b/src/testing/testing_api_cmd_get_product.c
@@ -0,0 +1,224 @@
+/*
+  This file is part of TALER
+  Copyright (C) 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
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_get_product.c
+ * @brief command to test GET /product/$ID
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "GET product" CMD.
+ */
+struct GetProductState
+{
+
+  /**
+   * Handle for a "GET product" request.
+   */
+  struct TALER_MERCHANT_ProductGetHandle *igh;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Base URL of the merchant serving the request.
+   */
+  const char *merchant_url;
+
+  /**
+   * ID of the product to run GET for.
+   */
+  const char *product_id;
+
+  /**
+   * Reference for a POST or PATCH /products CMD (optional).
+   */
+  const char *product_reference;
+
+  /**
+   * Expected HTTP response code.
+   */
+  unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a /get/product/$ID operation.
+ *
+ * @param cls closure for this function
+ * @param hr HTTP response details
+ * @param description description of the product
+ * @param description_i18n Map from IETF BCP 47 language tags to localized 
descriptions
+ * @param unit unit in which the product is measured (liters, kilograms, 
packages, etc.)
+ * @param price the price for one @a unit of the product, zero is used to 
imply that
+ *              this product is not sold separately or that the price is not 
fixed and
+ *              must be supplied by the front-end.  If non-zero, price must 
include
+ *              applicable taxes.
+ * @param image base64-encoded product image
+ * @param taxes list of taxes paid by the merchant
+ * @param total_stocked in @a units, -1 to indicate "infinite" (i.e. 
electronic books),
+ *                does NOT indicate remaining stocks, to get remaining stocks,
+ *                subtract @a total_sold and @a total_lost. Note that this 
still
+ *                does not then say how many of the remaining inventory are 
locked.
+ * @param total_sold in @a units, total number of @a unit of product sold
+ * @param total_lost in @a units, total number of @a unit of product lost from 
inventory
+ * @param location where the product is in stock
+ * @param next_restock when the next restocking is expected to happen, 0 for 
unknown,
+ *                     #GNUNET_TIME_UNIT_FOREVER_ABS for 'never'.
+ */
+static void
+get_product_cb (void *cls,
+                const struct TALER_MERCHANT_HttpResponse *hr,
+                const char *description,
+                const json_t *description_i18n,
+                const char *unit,
+                const struct TALER_Amount *price,
+                const json_t *image,
+                const json_t *taxes,
+                int64_t total_stocked,
+                uint64_t total_sold,
+                uint64_t total_lost,
+                const json_t *location,
+                struct GNUNET_TIME_Absolute next_restock)
+{
+  /* FIXME, deeper checks should be implemented here. */
+  struct GetProductState *gis = cls;
+
+  gis->igh = NULL;
+  if (gis->http_status != hr->http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u (%d) to command %s\n",
+                hr->http_status,
+                (int) hr->ec,
+                TALER_TESTING_interpreter_get_current_label (gis->is));
+    TALER_TESTING_interpreter_fail (gis->is);
+    return;
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    // FIXME: use gis->product_reference here to
+    // check if the data returned matches that from the POST / PATCH
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unhandled HTTP status.\n");
+  }
+  TALER_TESTING_interpreter_next (gis->is);
+}
+
+
+/**
+ * Run the "GET product" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+get_product_run (void *cls,
+                 const struct TALER_TESTING_Command *cmd,
+                 struct TALER_TESTING_Interpreter *is)
+{
+  struct GetProductState *gis = cls;
+
+  gis->is = is;
+  gis->igh = TALER_MERCHANT_product_get (is->ctx,
+                                         gis->merchant_url,
+                                         gis->product_id,
+                                         &get_product_cb,
+                                         gis);
+  GNUNET_assert (NULL != gis->igh);
+}
+
+
+/**
+ * Free the state of a "GET product" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+get_product_cleanup (void *cls,
+                     const struct TALER_TESTING_Command *cmd)
+{
+  struct GetProductState *gis = cls;
+
+  if (NULL != gis->igh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "GET /products/$ID operation did not complete\n");
+    TALER_MERCHANT_product_get_cancel (gis->igh);
+  }
+  GNUNET_free (gis);
+}
+
+
+/**
+ * Define a "GET product" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        GET /products/$ID request.
+ * @param product_id the ID of the product to query
+ * @param http_status expected HTTP response code.
+ * @param product_reference reference to a "POST /products" or "PATCH 
/products/$ID" CMD
+ *        that will provide what we expect the backend to return to us
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_product (const char *label,
+                                        const char *merchant_url,
+                                        const char *product_id,
+                                        unsigned int http_status,
+                                        const char *product_reference)
+{
+  struct GetProductState *gis;
+
+  gis = GNUNET_new (struct GetProductState);
+  gis->merchant_url = merchant_url;
+  gis->product_id = product_id;
+  gis->http_status = http_status;
+  gis->product_reference = product_reference;
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = gis,
+      .label = label,
+      .run = &get_product_run,
+      .cleanup = &get_product_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
+/* end of testing_api_cmd_get_product.c */
diff --git a/src/testing/testing_api_cmd_get_products.c 
b/src/testing/testing_api_cmd_get_products.c
new file mode 100644
index 0000000..e9e2bd4
--- /dev/null
+++ b/src/testing/testing_api_cmd_get_products.c
@@ -0,0 +1,181 @@
+/*
+  This file is part of TALER
+  Copyright (C) 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
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_get_products.c
+ * @brief command to test GET /products
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "GET products" CMD.
+ */
+struct GetProductsState
+{
+
+  /**
+   * Handle for a "GET product" request.
+   */
+  struct TALER_MERCHANT_ProductsGetHandle *igh;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Base URL of the merchant serving the request.
+   */
+  const char *merchant_url;
+
+  /**
+   * Expected HTTP response code.
+   */
+  unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a GET /products operation.
+ *
+ * @param cls closure for this function
+ * @param hr HTTP response details
+ * @param products_length length of the @a products array
+ * @param products array of products the requested instance offers
+ */
+static void
+get_products_cb (void *cls,
+                 const struct TALER_MERCHANT_HttpResponse *hr,
+                 unsigned int products_length,
+                 const struct TALER_MERCHANT_InventoryEntry products[])
+{
+  /* FIXME, deeper checks should be implemented here. */
+  struct GetProductsState *gis = cls;
+
+  gis->igh = NULL;
+  if (gis->http_status != hr->http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u (%d) to command %s\n",
+                hr->http_status,
+                (int) hr->ec,
+                TALER_TESTING_interpreter_get_current_label (gis->is));
+    TALER_TESTING_interpreter_fail (gis->is);
+    return;
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    // FIXME: use gis->product_reference here to
+    // check if the data returned matches that from the POST / PATCH
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unhandled HTTP status.\n");
+  }
+  TALER_TESTING_interpreter_next (gis->is);
+}
+
+
+/**
+ * Run the "GET /products" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+get_products_run (void *cls,
+                  const struct TALER_TESTING_Command *cmd,
+                  struct TALER_TESTING_Interpreter *is)
+{
+  struct GetProductsState *gis = cls;
+
+  gis->is = is;
+  gis->igh = TALER_MERCHANT_products_get (is->ctx,
+                                          gis->merchant_url,
+                                          &get_products_cb,
+                                          gis);
+  GNUNET_assert (NULL != gis->igh);
+}
+
+
+/**
+ * Free the state of a "GET product" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+get_products_cleanup (void *cls,
+                      const struct TALER_TESTING_Command *cmd)
+{
+  struct GetProductsState *gis = cls;
+
+  if (NULL != gis->igh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "GET /products/$ID operation did not complete\n");
+    TALER_MERCHANT_products_get_cancel (gis->igh);
+  }
+  GNUNET_free (gis);
+}
+
+
+/**
+ * Define a "GET /products" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        GET /products request.
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_get_products (const char *label,
+                                         const char *merchant_url,
+                                         unsigned int http_status)
+{
+  struct GetProductsState *gis;
+
+  gis = GNUNET_new (struct GetProductsState);
+  gis->merchant_url = merchant_url;
+  gis->http_status = http_status;
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = gis,
+      .label = label,
+      .run = &get_products_run,
+      .cleanup = &get_products_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
+/* end of testing_api_cmd_get_products.c */
diff --git a/src/testing/testing_api_cmd_lock_product.c 
b/src/testing/testing_api_cmd_lock_product.c
new file mode 100644
index 0000000..009783e
--- /dev/null
+++ b/src/testing/testing_api_cmd_lock_product.c
@@ -0,0 +1,200 @@
+/*
+  This file is part of TALER
+  Copyright (C) 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
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_lock_product.c
+ * @brief command to test LOCK /product
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "LOCK /product" CMD.
+ */
+struct LockProductState
+{
+
+  /**
+   * Handle for a "GET product" request.
+   */
+  struct TALER_MERCHANT_ProductLockHandle *iph;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Base URL of the merchant serving the request.
+   */
+  const char *merchant_url;
+
+  /**
+   * ID of the product to run GET for.
+   */
+  const char *product_id;
+
+
+  /**
+   * Expected HTTP response code.
+   */
+  unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a POST /products/$ID/lock operation.
+ *
+ * @param cls closure for this function
+ */
+static void
+lock_product_cb (void *cls,
+                 const struct TALER_MERCHANT_HttpResponse *hr)
+{
+  struct LockProductState *pis = cls;
+
+  pis->iph = NULL;
+  if (pis->http_status != hr->http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u (%d) to command %s\n",
+                hr->http_status,
+                (int) hr->ec,
+                TALER_TESTING_interpreter_get_current_label (pis->is));
+    TALER_TESTING_interpreter_fail (pis->is);
+    return;
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    break;
+  // FIXME: add other legitimate states here...
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unhandled HTTP status.\n");
+  }
+  TALER_TESTING_interpreter_next (pis->is);
+}
+
+
+/**
+ * Run the "LOCK /products/$ID" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+lock_product_run (void *cls,
+                  const struct TALER_TESTING_Command *cmd,
+                  struct TALER_TESTING_Interpreter *is)
+{
+  struct LockProductState *pis = cls;
+
+  pis->is = is;
+  pis->iph = TALER_MERCHANT_product_lock (is->ctx,
+                                          pis->merchant_url,
+                                          pis->product_id,
+                                          ...
+                                          & lock_product_cb,
+                                          pis);
+  GNUNET_assert (NULL != pis->iph);
+}
+
+
+/**
+ * Free the state of a "GET product" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+lock_product_cleanup (void *cls,
+                      const struct TALER_TESTING_Command *cmd)
+{
+  struct LockProductState *pis = cls;
+
+  if (NULL != pis->iph)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "POST /product/$ID/lock operation did not complete\n");
+    TALER_MERCHANT_product_lock_cancel (pis->iph);
+  }
+  json_decref (pis->address);
+  json_decref (pis->jurisdiction);
+  GNUNET_free (pis);
+}
+
+
+/**
+ * Define a "LOCK /products/$ID" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        LOCK /product request.
+ * @param product_id the ID of the product to query
+ * @param payto_uris_length length of the @a accounts array
+ * @param payto_uris URIs of the bank accounts of the merchant product
+ * @param name name of the merchant product
+ * @param address physical address of the merchant product
+ * @param jurisdiction jurisdiction of the merchant product
+ * @param default_max_wire_fee default maximum wire fee merchant is willing to 
fully pay
+ * @param default_wire_fee_amortization default amortization factor for excess 
wire fees
+ * @param default_max_deposit_fee default maximum deposit fee merchant is 
willing to pay
+ * @param default_wire_transfer_delay default wire transfer delay merchant 
will ask for
+ * @param default_pay_delay default validity period for offers merchant makes
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_lock_product (
+  const char *label,
+  const char *merchant_url,
+  const char *product_id,
+  ...
+  unsigned int http_status)
+{
+  struct LockProductState *pis;
+
+  pis = GNUNET_new (struct LockProductState);
+  pis->merchant_url = merchant_url;
+  pis->product_id = product_id;
+  pis->http_status = http_status;
+
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = pis,
+      .label = label,
+      .run = &lock_product_run,
+      .cleanup = &lock_product_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
+/* end of testing_api_cmd_lock_product.c */
diff --git a/src/testing/testing_api_cmd_patch_product.c 
b/src/testing/testing_api_cmd_patch_product.c
new file mode 100644
index 0000000..8088932
--- /dev/null
+++ b/src/testing/testing_api_cmd_patch_product.c
@@ -0,0 +1,283 @@
+/*
+  This file is part of TALER
+  Copyright (C) 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
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_patch_product.c
+ * @brief command to test PATCH /product
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "PATCH /product" CMD.
+ */
+struct PatchProductState
+{
+
+  /**
+   * Handle for a "GET product" request.
+   */
+  struct TALER_MERCHANT_ProductPatchHandle *iph;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Base URL of the merchant serving the request.
+   */
+  const char *merchant_url;
+
+  /**
+   * ID of the product to run GET for.
+   */
+  const char *product_id;
+
+  /**
+   * description of the product
+   */
+  const char *description;
+
+  /**
+   * Map from IETF BCP 47 language tags to localized descriptions
+   */
+  json_t *description_i18n;
+
+  /**
+   * unit in which the product is measured (liters, kilograms, packages, etc.)
+   */
+  const char *unit;
+
+  /**
+   * the price for one @a unit of the product
+   */
+  struct TALER_Amount price;
+
+  /**
+   * base64-encoded product image
+   */
+  json_t *image;
+
+  /**
+   * list of taxes paid by the merchant
+   */
+  json_t *taxes;
+
+  /**
+   * in @e units, -1 to indicate "infinite" (i.e. electronic books)
+   */
+  int64_t total_stocked;
+
+  /**
+   * in @e units.
+   */
+  int64_t total_lost;
+
+  /**
+   * where the product is in stock
+   */
+  json_t *address;
+
+  /**
+   * when the next restocking is expected to happen, 0 for unknown,
+   */
+  struct GNUNET_TIME_Absolute next_restock;
+
+  /**
+   * Expected HTTP response code.
+   */
+  unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a PATCH /products/$ID operation.
+ *
+ * @param cls closure for this function
+ */
+static void
+patch_product_cb (void *cls,
+                  const struct TALER_MERCHANT_HttpResponse *hr)
+{
+  struct PatchProductState *pis = cls;
+
+  pis->iph = NULL;
+  if (pis->http_status != hr->http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u (%d) to command %s\n",
+                hr->http_status,
+                (int) hr->ec,
+                TALER_TESTING_interpreter_get_current_label (pis->is));
+    TALER_TESTING_interpreter_fail (pis->is);
+    return;
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    break;
+  // FIXME: add other legitimate states here...
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unhandled HTTP status.\n");
+  }
+  TALER_TESTING_interpreter_next (pis->is);
+}
+
+
+/**
+ * Run the "PATCH /products/$ID" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+patch_product_run (void *cls,
+                   const struct TALER_TESTING_Command *cmd,
+                   struct TALER_TESTING_Interpreter *is)
+{
+  struct PatchProductState *pis = cls;
+
+  pis->is = is;
+  pis->iph = TALER_MERCHANT_product_patch (is->ctx,
+                                           pis->merchant_url,
+                                           pis->product_id,
+                                           pis->description,
+                                           pis->description_i18n,
+                                           pis->unit,
+                                           &pis->price,
+                                           pis->image,
+                                           pis->taxes,
+                                           pis->total_stocked,
+                                           pis->total_lost,
+                                           pis->address,
+                                           pis->next_restock,
+                                           &patch_product_cb,
+                                           pis);
+  GNUNET_assert (NULL != pis->iph);
+}
+
+
+/**
+ * Free the state of a "GET product" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+patch_product_cleanup (void *cls,
+                       const struct TALER_TESTING_Command *cmd)
+{
+  struct PatchProductState *pis = cls;
+
+  if (NULL != pis->iph)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "PATCH /products/$ID operation did not complete\n");
+    TALER_MERCHANT_product_patch_cancel (pis->iph);
+  }
+  json_decref (pis->description_i18n);
+  json_decref (pis->image);
+  json_decref (pis->taxes);
+  json_decref (pis->address);
+  GNUNET_free (pis);
+}
+
+
+/**
+ * Define a "PATCH /products/$ID" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        PATCH /product request.
+ * @param product_id the ID of the product to query
+ * @param description description of the product
+ * @param description_i18n Map from IETF BCP 47 language tags to localized 
descriptions
+ * @param unit unit in which the product is measured (liters, kilograms, 
packages, etc.)
+ * @param price the price for one @a unit of the product, zero is used to 
imply that
+ *              this product is not sold separately or that the price is not 
fixed and
+ *              must be supplied by the front-end.  If non-zero, price must 
include
+ *              applicable taxes.
+ * @param image base64-encoded product image
+ * @param taxes list of taxes paid by the merchant
+ * @param total_stocked in @a units, -1 to indicate "infinite" (i.e. 
electronic books)
+ * @param total_lost in @a units, must be larger than previous values, and may
+ *               not exceed total_stocked minus total_sold; if it does, the 
transaction
+ *               will fail with a #MHD_HTTP_CONFLICT HTTP status code
+ * @param address where the product is in stock
+ * @param next_restock when the next restocking is expected to happen, 0 for 
unknown,
+ *                     #GNUNET_TIME_UNIT_FOREVER_ABS for 'never'.
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_patch_product (
+  const char *label,
+  const char *merchant_url,
+  const char *product_id,
+  const char *description,
+  json_t *description_i18n,
+  const char *unit,
+  const struct TALER_Amount *price,
+  json_t *image,
+  json_t *taxes,
+  int64_t total_stocked,
+  uint64_t total_lost,
+  json_t *address,
+  struct GNUNET_TIME_Absolute next_restock,
+  unsigned int http_status)
+{
+  struct PatchProductState *pis;
+
+  pis = GNUNET_new (struct PatchProductState);
+  pis->merchant_url = merchant_url;
+  pis->product_id = product_id;
+  pis->http_status = http_status;
+  pis->description = description;
+  pis->description_i18n = description_i18n; /* ownership taken */
+  pis->unit = unit;
+  pis->price = *price;
+  pis->image = image; /* ownership taken */
+  pis->taxes = taxes; /* ownership taken */
+  pis->total_stocked = total_stocked;
+  pis->total_lost = total_lost;
+  pis->address = address; /* ownership taken */
+  pis->next_restock = next_restock; {
+    struct TALER_TESTING_Command cmd = {
+      .cls = pis,
+      .label = label,
+      .run = &patch_product_run,
+      .cleanup = &patch_product_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
+/* end of testing_api_cmd_patch_product.c */
diff --git a/src/testing/testing_api_cmd_post_products.c 
b/src/testing/testing_api_cmd_post_products.c
new file mode 100644
index 0000000..f5fed27
--- /dev/null
+++ b/src/testing/testing_api_cmd_post_products.c
@@ -0,0 +1,315 @@
+/*
+  This file is part of TALER
+  Copyright (C) 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
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_post_products.c
+ * @brief command to test POST /products
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_exchange_service.h>
+#include <taler/taler_testing_lib.h>
+#include "taler_merchant_service.h"
+#include "taler_merchant_testing_lib.h"
+
+
+/**
+ * State of a "POST /products" CMD.
+ */
+struct PostProductsState
+{
+
+  /**
+   * Handle for a "GET product" request.
+   */
+  struct TALER_MERCHANT_ProductsPostHandle *iph;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Base URL of the merchant serving the request.
+   */
+  const char *merchant_url;
+
+  /**
+   * ID of the product to run POST for.
+   */
+  const char *product_id;
+
+  /**
+   * description of the product
+   */
+  const char *description;
+
+  /**
+   * Map from IETF BCP 47 language tags to localized descriptions
+   */
+  json_t *description_i18n;
+
+  /**
+   * unit in which the product is measured (liters, kilograms, packages, etc.)
+   */
+  const char *unit;
+
+  /**
+   * the price for one @a unit of the product
+   */
+  struct TALER_Amount price;
+
+  /**
+   * base64-encoded product image
+   */
+  json_t *image;
+
+  /**
+   * list of taxes paid by the merchant
+   */
+  json_t *taxes;
+
+  /**
+   * in @e units, -1 to indicate "infinite" (i.e. electronic books)
+   */
+  int64_t total_stocked;
+
+  /**
+   * where the product is in stock
+   */
+  json_t *address;
+
+  /**
+   * when the next restocking is expected to happen, 0 for unknown,
+   */
+  struct GNUNET_TIME_Absolute next_restock;
+
+  /**
+   * Expected HTTP response code.
+   */
+  unsigned int http_status;
+
+};
+
+
+/**
+ * Callback for a POST /products operation.
+ *
+ * @param cls closure for this function
+ */
+static void
+post_products_cb (void *cls,
+                  const struct TALER_MERCHANT_HttpResponse *hr)
+{
+  struct PostProductsState *pis = cls;
+
+  pis->iph = NULL;
+  if (pis->http_status != hr->http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unexpected response code %u (%d) to command %s\n",
+                hr->http_status,
+                (int) hr->ec,
+                TALER_TESTING_interpreter_get_current_label (pis->is));
+    TALER_TESTING_interpreter_fail (pis->is);
+    return;
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    break;
+  // FIXME: add other legitimate states here...
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unhandled HTTP status.\n");
+  }
+  TALER_TESTING_interpreter_next (pis->is);
+}
+
+
+/**
+ * Run the "POST /products" CMD.
+ *
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+post_products_run (void *cls,
+                   const struct TALER_TESTING_Command *cmd,
+                   struct TALER_TESTING_Interpreter *is)
+{
+  struct PostProductsState *pis = cls;
+
+  pis->is = is;
+  pis->iph = TALER_MERCHANT_products_post (is->ctx,
+                                           pis->merchant_url,
+                                           pis->product_id,
+                                           pis->description,
+                                           pis->description_i18n,
+                                           pis->unit,
+                                           &pis->price,
+                                           pis->image,
+                                           pis->taxes,
+                                           pis->total_stocked,
+                                           pis->address,
+                                           pis->next_restock,
+                                           &post_products_cb,
+                                           pis);
+  GNUNET_assert (NULL != pis->iph);
+}
+
+
+/**
+ * Free the state of a "POST product" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+post_products_cleanup (void *cls,
+                       const struct TALER_TESTING_Command *cmd)
+{
+  struct PostProductsState *pis = cls;
+
+  if (NULL != pis->iph)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "POST /products operation did not complete\n");
+    TALER_MERCHANT_products_post_cancel (pis->iph);
+  }
+  json_decref (pis->description_i18n);
+  json_decref (pis->image);
+  json_decref (pis->taxes);
+  json_decref (pis->address);
+  GNUNET_free (pis);
+}
+
+
+/**
+ * Define a "POST /products" CMD.
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        POST /products request.
+ * @param product_id the ID of the product to query
+ * @param description description of the product
+ * @param description_i18n Map from IETF BCP 47 language tags to localized 
descriptions
+ * @param unit unit in which the product is measured (liters, kilograms, 
packages, etc.)
+ * @param price the price for one @a unit of the product, zero is used to 
imply that
+ *              this product is not sold separately or that the price is not 
fixed and
+ *              must be supplied by the front-end.  If non-zero, price must 
include
+ *              applicable taxes.
+ * @param image base64-encoded product image
+ * @param taxes list of taxes paid by the merchant
+ * @param total_stocked in @a units, -1 to indicate "infinite" (i.e. 
electronic books)
+ * @param address where the product is in stock
+ * @param next_restock when the next restocking is expected to happen, 0 for 
unknown,
+ *                     #GNUNET_TIME_UNIT_FOREVER_ABS for 'never'.
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_post_products2 (
+  const char *label,
+  const char *merchant_url,
+  const char *product_id,
+  const char *description,
+  json_t *description_i18n,
+  const char *unit,
+  const struct TALER_Amount *price,
+  json_t *image,
+  json_t *taxes,
+  int64_t total_stocked,
+  json_t *address,
+  struct GNUNET_TIME_Absolute next_restock,
+  unsigned int http_status)
+{
+  struct PostProductsState *pis;
+
+  pis = GNUNET_new (struct PostProductsState);
+  pis->merchant_url = merchant_url;
+  pis->product_id = product_id;
+  pis->http_status = http_status;
+  pis->description = description;
+  pis->description_i18n = description_i18n; /* ownership taken */
+  pis->unit = unit;
+  pis->price = *price;
+  pis->image = image; /* ownership taken */
+  pis->taxes = taxes; /* ownership taken */
+  pis->total_stocked = total_stocked;
+  pis->address = address; /* ownership taken */
+  pis->next_restock = next_restock;
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = pis,
+      .label = label,
+      .run = &post_products_run,
+      .cleanup = &post_products_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
+/**
+ * Define a "POST /products" CMD, simple version
+ *
+ * @param label command label.
+ * @param merchant_url base URL of the merchant serving the
+ *        POST /products request.
+ * @param product_id the ID of the product to create
+ * @param description name of the product
+ * @param price price of the product
+ * @param http_status expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_merchant_post_products (const char *label,
+                                          const char *merchant_url,
+                                          const char *product_id,
+                                          const char *description,
+                                          const char *price,
+                                          unsigned int http_status)
+{
+  struct TALER_Amount amount;
+
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (price,
+                                         &amount));
+  return TALER_TESTING_cmd_merchant_post_products2 (
+    label,
+    merchant_url,
+    product_id,
+    description,
+    json_pack ("{s:s}", "en", description),
+    "test-unit",
+    &amount,
+    json_object (),
+    json_object (),
+    4,
+    json_pack ("{s:s}", "street", "my street"),
+    GNUNET_TIME_UNIT_ZERO_ABS,
+    http_status);
+}
+
+
+/* end of testing_api_cmd_post_products.c */

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]