gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-merchant] branch master updated: add testcases for m


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch master updated: add testcases for merchantdb tipping functions, fix bugs found
Date: Tue, 24 Oct 2017 13:12:13 +0200

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

grothoff pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new 868a853  add testcases for merchantdb tipping functions, fix bugs found
868a853 is described below

commit 868a853f0e29c9611542c3e18cb4dfee84779ee3
Author: Christian Grothoff <address@hidden>
AuthorDate: Tue Oct 24 13:12:11 2017 +0200

    add testcases for merchantdb tipping functions, fix bugs found
---
 src/backenddb/plugin_merchantdb_postgres.c | 114 ++++++++++----
 src/backenddb/test_merchantdb.c            | 232 ++++++++++++++++++++++++++++-
 2 files changed, 320 insertions(+), 26 deletions(-)

diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index bd76481..92287c4 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -188,6 +188,16 @@ postgres_initialize (void *cls)
                             ",balance_curr VARCHAR(" TALER_CURRENCY_LEN_STR ") 
NOT NULL"
                             ",PRIMARY KEY (reserve_priv)"
                             ");"),
+    /* table where we remember when tipping reserves where established / 
enabled */
+    GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS 
merchant_tip_reserve_credits ("
+                            " reserve_priv BYTEA NOT NULL CHECK 
(LENGTH(reserve_priv)=32)"
+                            ",credit_uuid BYTEA NOT NULL CHECK 
(LENGTH(credit_uuid)=64)"
+                            ",timestamp INT8 NOT NULL"
+                            ",amount_val INT8 NOT NULL"
+                            ",amount_frac INT4 NOT NULL"
+                            ",amount_curr VARCHAR(" TALER_CURRENCY_LEN_STR ") 
NOT NULL"
+                            ",PRIMARY KEY (credit_uuid)"
+                            ");"),
     /* tips that have been authorized */
     GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS merchant_tips ("
                             " reserve_priv BYTEA NOT NULL CHECK 
(LENGTH(reserve_priv)=32)"
@@ -549,7 +559,8 @@ postgres_initialize (void *cls)
                             10),
     GNUNET_PQ_make_prepare ("lookup_reserve_by_tip_id",
                             "SELECT"
-                            " left_val"
+                            " reserve_priv"
+                            ",left_val"
                             ",left_frac"
                             ",left_curr"
                             " FROM merchant_tips"
@@ -581,6 +592,17 @@ postgres_initialize (void *cls)
                             ") VALUES "
                             "($1, $2, $3, $4, $5)",
                             5),
+    GNUNET_PQ_make_prepare ("insert_tip_credit_uuid",
+                            "INSERT INTO merchant_tip_reserve_credits"
+                            "(reserve_priv"
+                            ",credit_uuid"
+                            ",timestamp"
+                            ",amount_val"
+                            ",amount_frac"
+                            ",amount_curr)"
+                            " VALUES "
+                            "($1, $2, $3, $4, $5, $6)",
+                            6),
     GNUNET_PQ_PREPARED_STATEMENT_END
   };
 
@@ -2596,19 +2618,8 @@ postgres_enable_tip_reserve (void *cls,
                              struct GNUNET_TIME_Absolute expiration)
 {
   struct PostgresClosure *pg = cls;
-  struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (reserve_priv),
-    GNUNET_PQ_query_param_end
-  };
   struct GNUNET_TIME_Absolute old_expiration;
   struct TALER_Amount old_balance;
-  struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_absolute_time ("expiration",
-                                        &old_expiration),
-    TALER_PQ_result_spec_amount ("balance",
-                                 &old_balance),
-    GNUNET_PQ_result_spec_end
-  };
   enum GNUNET_DB_QueryStatus qs;
   struct GNUNET_TIME_Absolute new_expiration;
   struct TALER_Amount new_balance;
@@ -2620,12 +2631,58 @@ postgres_enable_tip_reserve (void *cls,
     GNUNET_break (0);
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
-  qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
-                                                "lookup_tip_reserve_balance",
-                                                params,
-                                                rs);
+
+  /* ensure that credit_uuid is new/unique */
+  {
+    struct GNUNET_TIME_Absolute now;
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_auto_from_type (reserve_priv),
+      GNUNET_PQ_query_param_auto_from_type (credit_uuid),
+      GNUNET_PQ_query_param_absolute_time (&now),
+      TALER_PQ_query_param_amount (credit),
+      GNUNET_PQ_query_param_end
+    };
+
+    now = GNUNET_TIME_absolute_get ();
+    qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+                                             "insert_tip_credit_uuid",
+                                             params);
+    if (0 > qs)
+    {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+      postgres_rollback (pg);
+      return qs;
+    }
+    /* UUID already exists, we are done! */
+    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+    {
+      postgres_rollback (pg);
+      return qs;
+    }
+  }
+
+  /* Obtain existing reserve balance */
+  {
+    struct GNUNET_PQ_QueryParam params[] = {
+      GNUNET_PQ_query_param_auto_from_type (reserve_priv),
+      GNUNET_PQ_query_param_end
+    };
+    struct GNUNET_PQ_ResultSpec rs[] = {
+      GNUNET_PQ_result_spec_absolute_time ("expiration",
+                                           &old_expiration),
+      TALER_PQ_result_spec_amount ("balance",
+                                   &old_balance),
+      GNUNET_PQ_result_spec_end
+    };
+
+    qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+                                                   
"lookup_tip_reserve_balance",
+                                                   params,
+                                                   rs);
+  }
   if (0 > qs)
   {
+    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     postgres_rollback (pg);
     return qs;
   }
@@ -2674,11 +2731,16 @@ postgres_enable_tip_reserve (void *cls,
                                              params);
     if (0 > qs)
     {
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
       postgres_rollback (pg);
       return qs;
     }
   }
-  return postgres_commit (pg);
+  qs = postgres_commit (pg);
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+  GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+  return qs;
 }
 
 
@@ -2913,16 +2975,18 @@ postgres_pickup_tip (void *cls,
         ? TALER_EC_TIP_PICKUP_DB_ERROR_HARD
         : TALER_EC_TIP_PICKUP_DB_ERROR_SOFT;
     }
-    if (0 !=
-        TALER_amount_cmp (&existing_amount,
-                          amount))
-    {
-      GNUNET_break_op (0);
-      postgres_rollback (pg);
-      return TALER_EC_TIP_PICKUP_AMOUNT_CHANGED;
-    }
     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+    {
+      if (0 !=
+          TALER_amount_cmp (&existing_amount,
+                            amount))
+      {
+        GNUNET_break_op (0);
+        postgres_rollback (pg);
+        return TALER_EC_TIP_PICKUP_AMOUNT_CHANGED;
+      }
       return TALER_EC_NONE; /* we are done! */
+    }
   }
 
   /* Calculate new balance */
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index eb4fe14..05db7c2 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -17,6 +17,7 @@
  * @file merchant/test_merchantdb_postgres.c
  * @brief testcase for merchant's postgres db plugin
  * @author Marcello Stanisci
+ * @author Christian Grothoff
  */
 
 #include "platform.h"
@@ -510,6 +511,232 @@ test_wire_fee ()
 
 
 /**
+ * Test APIs related to tipping.
+ *
+ * @return #GNUNET_OK upon success
+ */
+static int
+test_tipping ()
+{
+  struct TALER_ReservePrivateKeyP tip_reserve_priv;
+  struct TALER_ReservePrivateKeyP pres;
+  struct GNUNET_HashCode tip_id;
+  struct GNUNET_HashCode tip_credit_uuid;
+  struct GNUNET_HashCode pickup_id;
+  struct GNUNET_TIME_Absolute tip_expiration;
+  struct GNUNET_TIME_Absolute reserve_expiration;
+  struct TALER_Amount total;
+  struct TALER_Amount amount;
+  struct TALER_Amount inc;
+
+  RND_BLK (&tip_reserve_priv);
+  if (TALER_EC_TIP_AUTHORIZE_RESERVE_UNKNOWN !=
+      plugin->authorize_tip (plugin->cls,
+                             "testing tips reserve unknown",
+                             &amount,
+                             &tip_reserve_priv,
+                             &tip_expiration,
+                             &tip_id))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  RND_BLK (&tip_credit_uuid);
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":5",
+                                         &total));
+  /* Pick short expiration, but long enough to
+     run 2 DB interactions even on very slow systems. */
+  reserve_expiration = GNUNET_TIME_relative_to_absolute 
(GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
+                                                                               
         2));
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      plugin->enable_tip_reserve (plugin->cls,
+                                  &tip_reserve_priv,
+                                  &tip_credit_uuid,
+                                  &total,
+                                  reserve_expiration))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  /* check idempotency */
+  if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+      plugin->enable_tip_reserve (plugin->cls,
+                                  &tip_reserve_priv,
+                                  &tip_credit_uuid,
+                                  &total,
+                                  reserve_expiration))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  /* Make sure it has expired, so at this point the value is back at ZERO! */
+  sleep (3);
+  if (TALER_EC_TIP_AUTHORIZE_RESERVE_EXPIRED !=
+      plugin->authorize_tip (plugin->cls,
+                             "testing tips too late",
+                             &amount,
+                             &tip_reserve_priv,
+                             &tip_expiration,
+                             &tip_id))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* Re-add some funds again */
+  RND_BLK (&tip_credit_uuid);
+  reserve_expiration = GNUNET_TIME_relative_to_absolute 
(GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
+                                                                               
         2));
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      plugin->enable_tip_reserve (plugin->cls,
+                                  &tip_reserve_priv,
+                                  &tip_credit_uuid,
+                                  &total,
+                                  reserve_expiration))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  /* top it up by adding more with a fresh UUID
+     and even longer expiration time (until end of test) */
+  RND_BLK (&tip_credit_uuid);
+  reserve_expiration = GNUNET_TIME_relative_to_absolute 
(GNUNET_TIME_UNIT_DAYS);
+  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+      plugin->enable_tip_reserve (plugin->cls,
+                                  &tip_reserve_priv,
+                                  &tip_credit_uuid,
+                                  &total,
+                                  reserve_expiration))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* Now authorize some tips */
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":4",
+                                         &amount));
+  if (TALER_EC_NONE !=
+      plugin->authorize_tip (plugin->cls,
+                             "testing tips",
+                             &amount,
+                             &tip_reserve_priv,
+                             &tip_expiration,
+                             &tip_id))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (tip_expiration.abs_value_us != reserve_expiration.abs_value_us)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (TALER_EC_NONE !=
+      plugin->authorize_tip (plugin->cls,
+                             "testing tips more",
+                             &amount,
+                             &tip_reserve_priv,
+                             &tip_expiration,
+                             &tip_id))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (tip_expiration.abs_value_us != reserve_expiration.abs_value_us)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* Let's try to pick up the authorized tip in 2 increments */
+  GNUNET_assert (GNUNET_OK ==
+                 TALER_string_to_amount (CURRENCY ":2",
+                                         &inc));
+  RND_BLK (&pickup_id);
+  if (TALER_EC_NONE !=
+      plugin->pickup_tip (plugin->cls,
+                          &inc,
+                          &tip_id,
+                          &pickup_id,
+                          &pres))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (0 != memcmp (&pres,
+                   &tip_reserve_priv,
+                   sizeof (pres)))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  RND_BLK (&pickup_id);
+  if (TALER_EC_NONE !=
+      plugin->pickup_tip (plugin->cls,
+                          &inc,
+                          &tip_id,
+                          &pickup_id,
+                          &pres))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (0 != memcmp (&pres,
+                   &tip_reserve_priv,
+                   sizeof (pres)))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* Third attempt should fail, as we've picked up 4/4 in amount */
+  RND_BLK (&pickup_id);
+  if (TALER_EC_TIP_PICKUP_NO_FUNDS !=
+      plugin->pickup_tip (plugin->cls,
+                          &inc,
+                          &tip_id,
+                          &pickup_id,
+                          &pres))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* We authorized 8 out of 10, so going for another 4 should fail with 
insufficient funds */
+  if (TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS !=
+      plugin->authorize_tip (plugin->cls,
+                             "testing tips insufficient funds",
+                             &amount,
+                             &tip_reserve_priv,
+                             &tip_expiration,
+                             &tip_id))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* Test that picking up with random (unauthorized) tip_id fails as well */
+  RND_BLK (&tip_id);
+  RND_BLK (&pickup_id);
+  if (TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN !=
+      plugin->pickup_tip (plugin->cls,
+                          &inc,
+                          &tip_id,
+                          &pickup_id,
+                          &pres))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  return GNUNET_OK;
+}
+
+
+/**
  * Main function that will be run by the scheduler.
  *
  * @param cls closure with config
@@ -519,6 +746,7 @@ run (void *cls)
 {
   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
   struct GNUNET_TIME_Absolute fake_now;
+  json_t *out;
   /* Data for 'store_payment()' */
 
   if (NULL == (plugin = TALER_MERCHANTDB_plugin_load (cfg)))
@@ -615,7 +843,6 @@ run (void *cls)
                                       &h_contract_terms,
                                       &merchant_pub));
 
-  json_t *out;
 
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->find_contract_terms (plugin->cls,
@@ -787,6 +1014,9 @@ run (void *cls)
 
   FAILIF (GNUNET_OK !=
          test_wire_fee ());
+  FAILIF (GNUNET_OK !=
+         test_tipping ());
+
 
   if (-1 == result)
     result = 0;

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

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