gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 263/277: long polling test for GET /private/orders


From: gnunet
Subject: [taler-merchant] 263/277: long polling test for GET /private/orders
Date: Sun, 05 Jul 2020 20:52:56 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

commit b637514b36e6c0f44505fca510f3033b85c932ff
Author: Jonathan Buchanan <jonathan.russ.buchanan@gmail.com>
AuthorDate: Mon Jun 29 13:48:40 2020 -0400

    long polling test for GET /private/orders
---
 .../taler-merchant-httpd_private-post-orders.c     |  29 ++
 src/include/taler_merchant_testing_lib.h           |  18 ++
 src/testing/test_merchant_api.c                    |   6 +
 src/testing/testing_api_cmd_get_orders.c           | 337 +++++++++++++++++++++
 4 files changed, 390 insertions(+)

diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c 
b/src/backend/taler-merchant-httpd_private-post-orders.c
index e7b04e3..2772aef 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -30,6 +30,7 @@
 #include "taler-merchant-httpd_private-post-orders.h"
 #include "taler-merchant-httpd_auditors.h"
 #include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_private-get-orders.h"
 
 
 /**
@@ -198,6 +199,8 @@ execute_transaction (struct TMH_HandlerContext *hc,
                      const struct GNUNET_Uuid uuids[])
 {
   enum GNUNET_DB_QueryStatus qs;
+  struct GNUNET_TIME_Absolute timestamp;
+  uint64_t order_serial;
 
   if (GNUNET_OK !=
       TMH_db->start (TMH_db->cls,
@@ -249,11 +252,37 @@ execute_transaction (struct TMH_HandlerContext *hc,
       return qs;
     }
   }
+  /* Get the order serial and timestamp for the order we just created to
+     update long-poll clients. */
+  qs = TMH_db->lookup_order_summary (TMH_db->cls,
+                                     hc->instance->settings.id,
+                                     order_id,
+                                     &timestamp,
+                                     &order_serial);
+  if (1 != qs)
+  {
+    TMH_db->rollback (TMH_db->cls);
+    return qs;
+  }
   /* finally, commit transaction (note: if it fails, we ALSO re-acquire
      the UUID locks, which is exactly what we want) */
   qs = TMH_db->commit (TMH_db->cls);
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+  {
+    /* Notify clients that have been waiting for the payment to succeed */
+    TMH_long_poll_resume (order_id,
+                          hc->instance,
+                          NULL);
+    TMH_notify_order_change (hc->instance,
+                             order_id,
+                             false, /* paid */
+                             false, /* refunded */
+                             false, /* wired */
+                             timestamp,
+                             order_serial);
+
     return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* 1 == success! */
+  }
   return qs;
 }
 
diff --git a/src/include/taler_merchant_testing_lib.h 
b/src/include/taler_merchant_testing_lib.h
index 4c7039b..219997d 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -454,6 +454,24 @@ TALER_TESTING_cmd_merchant_get_orders (const char *label,
                                        ...);
 
 
+/**
+ * Start a long poll for GET /private/orders.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_poll_orders_start (const char *label,
+                                     const char *merchant_url,
+                                     struct GNUNET_TIME_Relative timeout);
+
+
+/**
+ * Complete a long poll for GET /private/orders.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_poll_orders_conclude (const char *label,
+                                        unsigned int http_status,
+                                        const char *poll_start_reference);
+
+
 /**
  * Define a GET /orders/$ORDER_ID CMD.
  *
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index 3bee5bd..501cc7e 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -271,6 +271,9 @@ run (void *cls,
                               "create-reserve-1",
                               "EUR:0",
                               MHD_HTTP_OK),
+    TALER_TESTING_cmd_poll_orders_start ("poll-orders-1-start",
+                                         merchant_url,
+                                         GNUNET_TIME_UNIT_MINUTES),
     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-1",
                                             merchant_url,
                                             MHD_HTTP_OK,
@@ -283,6 +286,9 @@ run (void *cls,
         \"fulfillment_url\": \"https://example.com/\",\
         \"products\": [ {\"description\":\"ice cream\",\
                          \"value\":\"{EUR:5}\"} ] }"),
+    TALER_TESTING_cmd_poll_orders_conclude ("poll-orders-1-conclude",
+                                            MHD_HTTP_OK,
+                                            "poll-orders-1-start"),
     TALER_TESTING_cmd_merchant_get_orders ("get-orders-1",
                                            merchant_url,
                                            MHD_HTTP_OK,
diff --git a/src/testing/testing_api_cmd_get_orders.c 
b/src/testing/testing_api_cmd_get_orders.c
index d4073b0..db3e20a 100644
--- a/src/testing/testing_api_cmd_get_orders.c
+++ b/src/testing/testing_api_cmd_get_orders.c
@@ -236,4 +236,341 @@ TALER_TESTING_cmd_merchant_get_orders (const char *label,
 }
 
 
+struct MerchantPollOrdersConcludeState
+{
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * Reference to a command that can provide a poll orders start command.
+   */
+  const char *start_reference;
+
+  /**
+   * Task to wait for the deadline.
+   */
+  struct GNUNET_SCHEDULER_Task *task;
+
+  /**
+   * Expected HTTP response status code.
+   */
+  unsigned int expected_http_status;
+};
+
+
+struct MerchantPollOrdersStartState
+{
+  /**
+   * The merchant base URL.
+   */
+  const char *merchant_url;
+
+  /**
+   * The handle to the current GET /private/orders request.
+   */
+  struct TALER_MERCHANT_OrdersGetHandle *ogh;
+
+  /**
+   * The interpreter state.
+   */
+  struct TALER_TESTING_Interpreter *is;
+
+  /**
+   * How long to wait for server to return a response.
+   */
+  struct GNUNET_TIME_Relative timeout;
+
+  /**
+   * Conclude state waiting for completion (if any).
+   */
+  struct MerchantPollOrdersConcludeState *cs;
+
+  /**
+   * The HTTP status code returned by the backend.
+   */
+  unsigned int http_status;
+
+  /**
+   * When the request should be completed by.
+   */
+  struct GNUNET_TIME_Absolute deadline;
+};
+
+
+/**
+ * Task called when either the timeout for the get orders
+ * command expired or we got a response.  Checks if the
+ * result is what we expected.
+ *
+ * @param cls a `struct MerchantPollOrdersConcludeState`
+ */
+static void
+conclude_task (void *cls)
+{
+  struct MerchantPollOrdersConcludeState *poc = cls;
+  const struct TALER_TESTING_Command *poll_cmd;
+  struct MerchantPollOrdersStartState *pos;
+  struct GNUNET_TIME_Absolute now;
+
+  poc->task = NULL;
+  poll_cmd =
+    TALER_TESTING_interpreter_lookup_command (poc->is,
+                                              poc->start_reference);
+  if (NULL == poll_cmd)
+    TALER_TESTING_FAIL (poc->is);
+  pos = poll_cmd->cls;
+  if (NULL != pos->ogh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Expected poll GET /private/orders to have completed, but it 
did not!\n");
+    TALER_TESTING_FAIL (poc->is);
+  }
+  if (pos->http_status != poc->expected_http_status)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Expected HTTP status %u, got %u\n",
+                poc->expected_http_status,
+                pos->http_status);
+    TALER_TESTING_FAIL (poc->is);
+  }
+  now = GNUNET_TIME_absolute_get ();
+  if ((GNUNET_TIME_absolute_add (pos->deadline,
+                                 GNUNET_TIME_UNIT_SECONDS).abs_value_us <
+       now.abs_value_us) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Expected answer to be delayed until %llu, but got response at 
%llu\n",
+                (unsigned long long) pos->deadline.abs_value_us,
+                (unsigned long long) now.abs_value_us);
+    TALER_TESTING_FAIL (poc->is);
+  }
+  TALER_TESTING_interpreter_next (poc->is);
+}
+
+
+/**
+ * Callback to process a GET /orders request
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ * @param osr order status response details (on success)
+ */
+static void
+merchant_poll_orders_cb (
+  void *cls,
+  const struct TALER_MERCHANT_HttpResponse *hr,
+  unsigned int orders_length,
+  const struct TALER_MERCHANT_OrderEntry orders[])
+{
+  /* FIXME, deeper checks should be implemented here. */
+  struct MerchantPollOrdersStartState *pos = cls;
+
+  pos->ogh = NULL;
+  if (MHD_HTTP_OK != 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 (pos->is));
+    TALER_TESTING_interpreter_fail (pos->is);
+    return;
+  }
+  switch (hr->http_status)
+  {
+  case MHD_HTTP_OK:
+    // FIXME: use order references
+    // check if the data returned matches that from the POST / PATCH
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unhandled HTTP status.\n");
+  }
+  pos->http_status = hr->http_status;
+  if (NULL != pos->cs)
+  {
+    GNUNET_SCHEDULER_cancel (pos->cs->task);
+    pos->cs->task = GNUNET_SCHEDULER_add_now (&conclude_task,
+                                              pos->cs);
+  }
+}
+
+
+/**
+ * Run the "GET orders" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+merchant_poll_orders_start_run (void *cls,
+                                const struct TALER_TESTING_Command *cmd,
+                                struct TALER_TESTING_Interpreter *is)
+{
+  struct MerchantPollOrdersStartState *pos = cls;
+
+  /* add 1s grace time to timeout */
+  pos->deadline
+    = GNUNET_TIME_absolute_add (GNUNET_TIME_relative_to_absolute 
(pos->timeout),
+                                GNUNET_TIME_UNIT_SECONDS);
+  pos->is = is;
+  pos->ogh = TALER_MERCHANT_orders_get2 (is->ctx,
+                                         pos->merchant_url,
+                                         TALER_EXCHANGE_YNA_ALL,
+                                         TALER_EXCHANGE_YNA_ALL,
+                                         TALER_EXCHANGE_YNA_ALL,
+                                         GNUNET_TIME_UNIT_ZERO_ABS,
+                                         1,
+                                         2,
+                                         pos->timeout,
+                                         &merchant_poll_orders_cb,
+                                         pos);
+  GNUNET_assert (NULL != pos->ogh);
+  /* We CONTINUE to run the interpreter while the long-polled command
+     completes asynchronously! */
+  TALER_TESTING_interpreter_next (pos->is);
+}
+
+
+/**
+ * Free the state of a "GET orders" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+merchant_poll_orders_start_cleanup (void *cls,
+                                    const struct TALER_TESTING_Command *cmd)
+{
+  struct MerchantPollOrdersStartState *pos = cls;
+
+  if (NULL != pos->ogh)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Command `%s' was not terminated\n",
+                TALER_TESTING_interpreter_get_current_label (
+                  pos->is));
+    TALER_MERCHANT_orders_get_cancel (pos->ogh);
+  }
+  GNUNET_free (pos);
+}
+
+
+/**
+ * Start a long poll for GET /private/orders.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_poll_orders_start (const char *label,
+                                     const char *merchant_url,
+                                     struct GNUNET_TIME_Relative timeout)
+{
+  struct MerchantPollOrdersStartState *pos;
+
+  pos = GNUNET_new (struct MerchantPollOrdersStartState);
+  pos->merchant_url = merchant_url;
+  pos->timeout = timeout;
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = pos,
+      .label = label,
+      .run = &merchant_poll_orders_start_run,
+      .cleanup = &merchant_poll_orders_start_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
+/**
+ * Run the "GET orders" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command being run now.
+ * @param is interpreter state.
+ */
+static void
+merchant_poll_orders_conclude_run (void *cls,
+                                   const struct TALER_TESTING_Command *cmd,
+                                   struct TALER_TESTING_Interpreter *is)
+{
+  struct MerchantPollOrdersConcludeState *poc = cls;
+  const struct TALER_TESTING_Command *poll_cmd;
+  struct MerchantPollOrdersStartState *pos;
+
+  poc->is = is;
+  poll_cmd =
+    TALER_TESTING_interpreter_lookup_command (is,
+                                              poc->start_reference);
+  if (NULL == poll_cmd)
+    TALER_TESTING_FAIL (poc->is);
+  GNUNET_assert (poll_cmd->run == &merchant_poll_orders_start_run);
+  pos = poll_cmd->cls;
+  pos->cs = poc;
+  if (NULL == pos->ogh)
+    poc->task = GNUNET_SCHEDULER_add_now (&conclude_task,
+                                          poc);
+  else
+    poc->task = GNUNET_SCHEDULER_add_at (pos->deadline,
+                                         &conclude_task,
+                                         poc);
+}
+
+
+/**
+ * Free the state of a "GET orders" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ */
+static void
+merchant_poll_orders_conclude_cleanup (void *cls,
+                                       const struct TALER_TESTING_Command *cmd)
+{
+  struct MerchantPollOrdersConcludeState *poc = cls;
+
+  if (NULL != poc->task)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Command `%s' was not terminated\n",
+                TALER_TESTING_interpreter_get_current_label (
+                  poc->is));
+    GNUNET_SCHEDULER_cancel (poc->task);
+    poc->task = NULL;
+  }
+  GNUNET_free (poc);
+}
+
+
+/**
+ * Complete a long poll for GET /private/orders.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_poll_orders_conclude (const char *label,
+                                        unsigned int http_status,
+                                        const char *poll_start_reference)
+{
+  struct MerchantPollOrdersConcludeState *poc;
+
+  poc = GNUNET_new (struct MerchantPollOrdersConcludeState);
+  poc->start_reference = poll_start_reference;
+  poc->expected_http_status = http_status;
+  {
+    struct TALER_TESTING_Command cmd = {
+      .cls = poc,
+      .label = label,
+      .run = &merchant_poll_orders_conclude_run,
+      .cleanup = &merchant_poll_orders_conclude_cleanup
+    };
+
+    return cmd;
+  }
+}
+
+
 /* end of testing_api_cmd_get_orders.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]