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 (6b2297c -> cc367e6)


From: gnunet
Subject: [GNUnet-SVN] [taler-merchant] branch master updated (6b2297c -> cc367e6)
Date: Thu, 04 Jan 2018 12:00:16 +0100

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

grothoff pushed a change to branch master
in repository merchant.

    from 6b2297c  expand testcases to cover pay-again case
     new b31e9a3  expand test logic for #5158
     new cc367e6  enable test logic for #5158

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/backend/taler-merchant-httpd_pay.c |  11 +-
 src/include/taler_merchant_service.h   |  35 +++-
 src/lib/merchant_api_pay.c             |  68 ++++----
 src/lib/test_merchant_api.c            | 306 ++++++++++++++++++++++++++++++---
 4 files changed, 356 insertions(+), 64 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_pay.c 
b/src/backend/taler-merchant-httpd_pay.c
index 20b50d7..974c092 100644
--- a/src/backend/taler-merchant-httpd_pay.c
+++ b/src/backend/taler-merchant-httpd_pay.c
@@ -1710,6 +1710,8 @@ begin_transaction (struct PayContext *pc)
        struct TALER_MerchantSignatureP msig;
        uint64_t rtransactionid;
 
+       if (GNUNET_YES != pc->dc[i].found_in_db)
+         continue;
        rtransactionid = 0;
         rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
        rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
@@ -1717,7 +1719,11 @@ begin_transaction (struct PayContext *pc)
        rr.coin_pub = pc->dc[i].coin_pub;
        rr.merchant = pc->mi->pubkey;
        rr.rtransaction_id = GNUNET_htonll (rtransactionid);
-
+       TALER_amount_hton (&rr.refund_amount,
+                          &pc->dc[i].amount_with_fee);
+       TALER_amount_hton (&rr.refund_fee,
+                          &pc->dc[i].refund_fee);
+       
        if (GNUNET_OK !=
            GNUNET_CRYPTO_eddsa_sign (&pc->mi->privkey.eddsa_priv,
                                      &rr.purpose,
@@ -1733,8 +1739,9 @@ begin_transaction (struct PayContext *pc)
          return;
        }
        json_array_append_new (refunds,
-                              json_pack ("{s:I, s:o}",
+                              json_pack ("{s:I, s:o, s:o}",
                                          "rtransaction_id", (json_int_t) 
rtransactionid,
+                                         "coin_pub", 
GNUNET_JSON_from_data_auto (&rr.coin_pub),
                                          "merchant_sig", 
GNUNET_JSON_from_data_auto (&msig)));                    
       }
       resume_pay_with_response (pc,
diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 8c6c770..51db135 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -311,6 +311,11 @@ struct TALER_MERCHANT_PayCoin
   struct TALER_Amount amount_without_fee;
   
   /**
+   * Fee the exchange charges for refunds of this coin.
+   */
+  struct TALER_Amount refund_fee;
+
+  /**
    * URL of the exchange that issued @e coin_priv.
    */ 
   const char *exchange_url;
@@ -362,6 +367,28 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
 
 
 /**
+ * Entry in the array of refunded coins.
+ */
+struct TALER_MERCHANT_RefundEntry
+{
+  /**
+   * Merchant signature affirming the refund.
+   */ 
+  struct TALER_MerchantSignatureP merchant_sig;
+
+  /**
+   * Public key of the refunded coin.
+   */ 
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+
+  /**
+   * Refund transaction ID.
+   */
+  uint64_t rtransaction_id;
+};
+
+
+/**
  * Callbacks of this type are used to serve the result of submitting a
  * /pay request to a merchant.
  *
@@ -373,9 +400,8 @@ TALER_MERCHANT_pay_wallet (struct GNUNET_CURL_Context *ctx,
  * @param ec taler-specific error code
  * @param merchant_pub public key of the merchant
  * @param h_contract hash of the contract
- * @param num_refunds size of the @a merchant_sigs array, 0 on errors
- * @param merchant_sigs merchant signatures refunding coins, NULL on errors
- * @param rtids refund transaction IDs (array of length @a num_refunds) 
+ * @param num_refunds size of the @a res array, 0 on errors
+ * @param res merchant signatures refunding coins, NULL on errors
  * @param obj the received JSON reply, with error details if the request failed
  */
 typedef void
@@ -385,8 +411,7 @@ typedef void
                                     const struct TALER_MerchantPublicKeyP 
*merchant_pub,
                                     const struct GNUNET_HashCode *h_contract,
                                     unsigned int num_refunds,
-                                    const struct TALER_MerchantSignatureP 
*merchant_sigs,
-                                    const uint64_t *rtids,
+                                    const struct TALER_MERCHANT_RefundEntry 
*res,
                                     const json_t *obj);
 
 
diff --git a/src/lib/merchant_api_pay.c b/src/lib/merchant_api_pay.c
index 135cb9c..6d57862 100644
--- a/src/lib/merchant_api_pay.c
+++ b/src/lib/merchant_api_pay.c
@@ -132,30 +132,27 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph,
     return GNUNET_SYSERR;
   }
   num_refunds = json_array_size (refunds);
-  if (num_refunds != ph->num_coins)
   {
-    GNUNET_break_op (0);
-    GNUNET_JSON_parse_free (spec);
-    return GNUNET_SYSERR;
-  }
-  {
-    struct TALER_MerchantSignatureP sigs[num_refunds];
-    uint64_t rtids[num_refunds];
+    struct TALER_MERCHANT_RefundEntry res[num_refunds];
 
     for (unsigned int i=0;i<num_refunds;i++)
     {
-      struct TALER_MerchantSignatureP *sig = &sigs[i];
-      json_t *deposit = json_array_get (refunds, i);
-      uint64_t rtransaction_id;
+      struct TALER_MerchantSignatureP *sig = &res[i].merchant_sig;
+      json_t *refund = json_array_get (refunds, i);
       struct GNUNET_JSON_Specification spec_detail[] = {
-        GNUNET_JSON_spec_fixed_auto ("sig", sig),
-       GNUNET_JSON_spec_uint64 ("rtransaction_id", &rtransaction_id),
+        GNUNET_JSON_spec_fixed_auto ("merchant_sig",
+                                    sig),
+        GNUNET_JSON_spec_fixed_auto ("coin_pub",
+                                    &res[i].coin_pub),
+       GNUNET_JSON_spec_uint64 ("rtransaction_id",
+                                &res[i].rtransaction_id),
         GNUNET_JSON_spec_end()
       };
       struct TALER_RefundRequestPS rr;
+      int found;
 
       if (GNUNET_OK !=
-          GNUNET_JSON_parse (deposit,
+          GNUNET_JSON_parse (refund,
                              spec_detail,
                              NULL, NULL))
       {
@@ -167,13 +164,29 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph,
       rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
       rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS));
       rr.h_contract_terms = ph->h_contract_terms;
-      rr.coin_pub = ph->coins[i].coin_pub;
+      rr.coin_pub = res[i].coin_pub;
       rr.merchant = merchant_pub;      
-      rr.rtransaction_id = GNUNET_htonll (rtransaction_id);
-      TALER_amount_hton (&rr.refund_amount,
-                        &ph->coins[i].amount_with_fee);
-      TALER_amount_hton (&rr.refund_fee,
-                        &ph->coins[i].refund_fee);
+      rr.rtransaction_id = GNUNET_htonll (res[i].rtransaction_id);
+      found = -1;
+      for (unsigned int j=0;j<ph->num_coins;j++)
+      {
+       if (0 == memcmp (&ph->coins[j].coin_pub,
+                        &res[i].coin_pub,
+                        sizeof (struct TALER_CoinSpendPublicKeyP)))
+       {
+         TALER_amount_hton (&rr.refund_amount,
+                            &ph->coins[j].amount_with_fee);
+         TALER_amount_hton (&rr.refund_fee,
+                            &ph->coins[j].refund_fee);
+         found = j;
+       }
+      }
+      if (-1 == found)
+      {
+       GNUNET_break_op (0);
+       return GNUNET_SYSERR;
+      }
+
       if (GNUNET_OK !=
          GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
                                      &rr.purpose,
@@ -183,7 +196,6 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph,
        GNUNET_break_op (0);
        return GNUNET_SYSERR;
       }
-      rtids[i] = rtransaction_id;     
     }
     ph->abort_cb (ph->abort_cb_cls,
                  MHD_HTTP_OK,
@@ -191,8 +203,7 @@ check_abort_refund (struct TALER_MERCHANT_Pay *ph,
                  &merchant_pub,
                  &ph->h_contract_terms,
                  num_refunds,
-                 sigs,
-                 rtids,
+                 res,
                  json);
     ph->abort_cb = NULL;
   }
@@ -421,7 +432,6 @@ handle_pay_finished (void *cls,
                  NULL,
                  0,
                  NULL,
-                 NULL,
                  json);
   }
     
@@ -688,15 +698,6 @@ prepare_pay_generic (struct GNUNET_CURL_Context *ctx,
                        TALER_amount2s (&fee));
     }
 
-    fprintf (stderr,
-            "Signing DP %s/%s/%s/%llu/%llu/%s with coin %s\n",
-            GNUNET_h2s (&dr.h_contract_terms),
-            GNUNET_h2s2 (&dr.h_wire),
-            TALER_amount2s (&coin->amount_without_fee),
-            (unsigned long long) timestamp.abs_value_us,
-            (unsigned long long) refund_deadline.abs_value_us,      
-            TALER_B2S (&dr),
-            GNUNET_i2s ((const struct GNUNET_PeerIdentity *)&dr.coin_pub));
     GNUNET_CRYPTO_eddsa_sign (&coin->coin_priv.eddsa_priv,
                              &dr.purpose,
                              &p->coin_sig.eddsa_signature);
@@ -706,6 +707,7 @@ prepare_pay_generic (struct GNUNET_CURL_Context *ctx,
     p->coin_pub = dr.coin_pub;
     p->amount_with_fee = coin->amount_with_fee;
     p->amount_without_fee = coin->amount_without_fee;
+    p->refund_fee = coin->refund_fee;
     p->exchange_url = coin->exchange_url;
   }
   return request_pay_generic (ctx,
diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c
index 9e4473a..574cbd7 100644
--- a/src/lib/test_merchant_api.c
+++ b/src/lib/test_merchant_api.c
@@ -18,9 +18,6 @@
  * @brief testcase to test merchant's HTTP API interface
  * @author Christian Grothoff
  * @author Marcello Stanisci
- *
- * TODO:
- * - add test logic for pay-abort-refund
  */
 #include "platform.h"
 #include <taler/taler_exchange_service.h>
@@ -185,6 +182,11 @@ enum OpCode
    * Abort payment with coins, requesting refund.
    */
   OC_PAY_ABORT,
+  
+  /**
+   * Abort payment with coins, executing refund.
+   */
+  OC_PAY_ABORT_REFUND,
 
   /**
    * Run the aggregator to execute deposits.
@@ -549,6 +551,12 @@ struct Command
        */
       const char *amount_without_fee;
 
+      /** 
+       * Refund fee to use for each coin (only relevant if we
+       * exercise /pay's abort functionality).
+       */
+      const char *refund_fee;
+      
       /**
        * Pay handle while operation is running.
        */
@@ -600,9 +608,57 @@ struct Command
        * Pay handle while operation is running.
        */
       struct TALER_MERCHANT_Pay *ph;
-      
+
+      /** 
+       * Set in #pay_refund_cb to number of refunds obtained.
+       */
+      unsigned int num_refunds;
+
+      /**
+       * Array of @e num_refund refunds obtained.
+       */
+      struct TALER_MERCHANT_RefundEntry *res;
+
+      /**
+       * Set to the hash of the original contract.
+       */ 
+      struct GNUNET_HashCode h_contract;      
+
+      /**
+       * Set to the merchant's public key.
+       */ 
+      struct TALER_MerchantPublicKeyP merchant_pub;
+
     } pay_abort;
-    
+
+    struct {
+
+      /**
+       * Reference to the pay_abort command to be refunded.
+       */ 
+      const char *abort_ref;
+
+      /**
+       * Number of the coin of @e abort_ref to be refunded.
+       */
+      unsigned int num_coin;
+
+      /**
+       * Refund amount to use.
+       */
+      const char *refund_amount;
+
+      /**
+       * Refund fee to expect.
+       */
+      const char *refund_fee;
+      
+      /**
+       * Handle to the refund operation.
+       */
+      struct TALER_EXCHANGE_RefundHandle *rh;
+
+    } pay_abort_refund;
 
     struct {
 
@@ -2333,6 +2389,20 @@ cleanup_state (struct InterpreterState *is)
         TALER_MERCHANT_pay_cancel (cmd->details.pay_abort.ph);
         cmd->details.pay_abort.ph = NULL;
       }
+      GNUNET_array_grow (cmd->details.pay_abort.res,
+                        cmd->details.pay_abort.num_refunds,
+                        0);
+      break;
+    case OC_PAY_ABORT_REFUND:
+      if (NULL != cmd->details.pay_abort_refund.rh)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Command %u (%s) did not complete\n",
+                    i,
+                    cmd->label);
+       TALER_EXCHANGE_refund_cancel (cmd->details.pay_abort_refund.rh);
+       cmd->details.pay_abort_refund.rh = NULL;
+      }
       break;
     case OC_RUN_AGGREGATOR:
       if (NULL != cmd->details.run_aggregator.aggregator_proc)
@@ -2553,6 +2623,9 @@ build_coins (struct TALER_MERCHANT_PayCoin **pc,
     GNUNET_assert (GNUNET_OK ==
                   TALER_string_to_amount (pref->details.pay.amount_without_fee,
                                           &icoin->amount_without_fee));
+    GNUNET_assert (GNUNET_OK ==
+                  TALER_string_to_amount (pref->details.pay.refund_fee,
+                                          &icoin->refund_fee));
   }
   return GNUNET_OK;
 }
@@ -2571,8 +2644,7 @@ build_coins (struct TALER_MERCHANT_PayCoin **pc,
  * @param merchant_pub public key of the merchant
  * @param h_contract hash of the contract
  * @param num_refunds size of the @a merchant_sigs array, 0 on errors
- * @param merchant_sigs merchant signatures refunding coins, NULL on errors
- * @param rtids refund transaction IDs (array of length @a num_refunds) 
+ * @param res merchant signatures refunding coins, NULL on errors
  * @param obj the received JSON reply, with error details if the request failed
  */
 static void
@@ -2582,8 +2654,7 @@ pay_refund_cb (void *cls,
               const struct TALER_MerchantPublicKeyP *merchant_pub,
               const struct GNUNET_HashCode *h_contract,
               unsigned int num_refunds,
-              const struct TALER_MerchantSignatureP *merchant_sigs,
-              const uint64_t *rtids,
+              const struct TALER_MERCHANT_RefundEntry *res,
               const json_t *obj)
 {
   struct InterpreterState *is = cls;
@@ -2602,8 +2673,51 @@ pay_refund_cb (void *cls,
   if ( (MHD_HTTP_OK == http_status) &&
        (TALER_EC_NONE == ec) )
   {
+    cmd->details.pay_abort.num_refunds = num_refunds;
+    cmd->details.pay_abort.res
+      = GNUNET_new_array (num_refunds,
+                         struct TALER_MERCHANT_RefundEntry);
+    memcpy (cmd->details.pay_abort.res,
+           res,
+           num_refunds * sizeof (struct TALER_MERCHANT_RefundEntry));
+    cmd->details.pay_abort.h_contract = *h_contract;
+    cmd->details.pay_abort.merchant_pub = *merchant_pub;
+  }
+  next_command (is);
+}
+
+
+/**
+ * Callbacks of this type are used to serve the result of submitting a
+ * refund request to an exchange.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful 
deposit;
+ *                    0 if the exchange's reply is bogus (fails to follow the 
protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
+ * @param sign_key exchange key used to sign @a obj, or NULL
+ * @param obj the received JSON reply, should be kept as proof (and, in 
particular,
+ *            be forwarded to the customer)
+ */
+static void
+abort_refund_cb (void *cls,
+                unsigned int http_status,
+                enum TALER_ErrorCode ec,
+                const struct TALER_ExchangePublicKeyP *sign_key,
+                const json_t *obj)
+{
+  struct InterpreterState *is = cls;
+  struct Command *cmd = &is->commands[is->ip];
+  
+  cmd->details.pay_abort_refund.rh = NULL;
+  if (cmd->expected_response_code != http_status)
+  {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "TODO: implement check of returned data\n");
+                "Unexpected response code %u to command %s\n",
+                http_status,
+                cmd->label);
+    fail (is);
+    return;
   }
   next_command (is);
 }
@@ -3217,6 +3331,46 @@ interpreter_run (void *cls)
       fail (is);
     }
     break;
+  case OC_PAY_ABORT_REFUND:
+    {
+      struct TALER_Amount refund_fee;
+      const struct TALER_MERCHANT_RefundEntry *re;
+
+      /* Get original /pay command */
+      GNUNET_assert (NULL != (ref = find_command
+                              (is,
+                               cmd->details.pay_abort_refund.abort_ref)));
+      GNUNET_assert (OC_PAY_ABORT == ref->oc);
+      GNUNET_assert (ref->details.pay_abort.num_refunds >
+                    cmd->details.pay_abort_refund.num_coin);
+      re = &ref->details.pay_abort.res[cmd->details.pay_abort_refund.num_coin];
+                    
+      GNUNET_assert (GNUNET_OK ==
+                    TALER_string_to_amount
+                    (cmd->details.pay_abort_refund.refund_amount,
+                     &amount));
+      GNUNET_assert (GNUNET_OK ==
+                    TALER_string_to_amount
+                    (cmd->details.pay_abort_refund.refund_fee,
+                     &refund_fee));
+      cmd->details.pay_abort_refund.rh
+       = TALER_EXCHANGE_refund2 (exchange,
+                                 &amount,
+                                 &refund_fee,
+                                 &ref->details.pay_abort.h_contract,
+                                 &re->coin_pub,
+                                 re->rtransaction_id,
+                                 &ref->details.pay_abort.merchant_pub,
+                                 &re->merchant_sig,
+                                 &abort_refund_cb,
+                                 is);
+      if (NULL == cmd->details.pay_abort_refund.rh)
+      {
+       GNUNET_break (0);
+       fail (is);
+      }
+    }
+    break;
   case OC_RUN_AGGREGATOR:
     {
       const struct GNUNET_DISK_FileHandle *pr;
@@ -3270,9 +3424,10 @@ interpreter_run (void *cls)
     }
   case OC_CHECK_BANK_TRANSFER:
     {
-      GNUNET_assert (GNUNET_OK == TALER_string_to_amount
-        (cmd->details.check_bank_transfer.amount,
-         &amount));
+      GNUNET_assert (GNUNET_OK ==
+                    TALER_string_to_amount
+                    (cmd->details.check_bank_transfer.amount,
+                     &amount));
       if (GNUNET_OK != TALER_FAKEBANK_check
            (fakebank,
             &amount,
@@ -3806,6 +3961,7 @@ run (void *cls)
       .expected_response_code = MHD_HTTP_OK,
       .details.pay.contract_ref = "create-proposal-1",
       .details.pay.coin_ref = "withdraw-coin-1",
+      .details.pay.refund_fee = "EUR:0.01",
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
@@ -3815,6 +3971,7 @@ run (void *cls)
       .expected_response_code = MHD_HTTP_OK,
       .details.pay.contract_ref = "create-proposal-1",
       .details.pay.coin_ref = "withdraw-coin-1",
+      .details.pay.refund_fee = "EUR:0.01",
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
@@ -3847,6 +4004,7 @@ run (void *cls)
       .expected_response_code = MHD_HTTP_FORBIDDEN,
       .details.pay.contract_ref = "create-proposal-2",
       .details.pay.coin_ref = "withdraw-coin-1",
+      .details.pay.refund_fee = "EUR:0.01",
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
@@ -3974,6 +4132,7 @@ run (void *cls)
       .expected_response_code = MHD_HTTP_OK,
       .details.pay.contract_ref = "create-proposal-2",
       .details.pay.coin_ref = "withdraw-coin-2",
+      .details.pay.refund_fee = "EUR:0.01",
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
@@ -4178,6 +4337,7 @@ run (void *cls)
       .expected_response_code = MHD_HTTP_OK,
       .details.pay.contract_ref = "create-proposal-tip-1",
       .details.pay.coin_ref = "pickup-tip-1",
+      .details.pay.refund_fee = "EUR:0.01",
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
     /* Run transfers. */
@@ -4197,9 +4357,7 @@ run (void *cls)
       .label = "check_bank_empty" },
 
 
-
-
-
+    /* ****************** /pay again logic ************* */
 
     /* Fill reserve with EUR:10.02, as withdraw fee is 1 ct per
        config */
@@ -4213,7 +4371,7 @@ run (void *cls)
       .details.admin_add_incoming.amount = "EUR:10.02" },
     /* Run wirewatch to observe /admin/add/incoming */
     { .oc = OC_RUN_WIREWATCH,
-      .label = "wirewatch-1" },
+      .label = "wirewatch-10" },
     { .oc = OC_CHECK_BANK_TRANSFER,
       .label = "check_bank_transfer-10",
       .details.check_bank_transfer.amount = "EUR:10.02",
@@ -4269,23 +4427,23 @@ run (void *cls)
 
     /* execute simple payment, re-using one ancient coin */
     { .oc = OC_PAY,
-      .label = "pay-fail-partial-double",
+      .label = "pay-fail-partial-double-10",
       .expected_response_code = MHD_HTTP_FORBIDDEN,
       .details.pay.contract_ref = "create-proposal-10",
       .details.pay.coin_ref = "withdraw-coin-10a;withdraw-coin-1",
       /* These amounts are given per coin! */
+      .details.pay.refund_fee = "EUR:0.01",
       .details.pay.amount_with_fee = "EUR:5",
       .details.pay.amount_without_fee = "EUR:4.99" },
 
     /* Try to replay payment reusing coin */
     { .oc = OC_PAY_AGAIN,
-      .label = "pay-again",
+      .label = "pay-again-10",
       .expected_response_code = MHD_HTTP_OK,
-      .details.pay_again.pay_ref = "pay-fail-partial-double",
+      .details.pay.refund_fee = "EUR:0.01",
+      .details.pay_again.pay_ref = "pay-fail-partial-double-10",
       .details.pay_again.coin_ref = "withdraw-coin-10a;withdraw-coin-10b" },
-
-
-
+    
     /* Run transfers. */
     { .oc = OC_RUN_AGGREGATOR,
       .label = "run-aggregator-10" },
@@ -4304,8 +4462,108 @@ run (void *cls)
     { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
       .label = "check_bank_empty-10" },
 
-    
 
+    /* ****************** /pay abort logic ************* */
+
+    /* Fill reserve with EUR:10.02, as withdraw fee is 1 ct per
+       config */
+    { .oc = OC_ADMIN_ADD_INCOMING,
+      .label = "create-reserve-11",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.admin_add_incoming.debit_account_no = 62,
+      .details.admin_add_incoming.credit_account_no = EXCHANGE_ACCOUNT_NO,
+      .details.admin_add_incoming.auth_username = "user62",
+      .details.admin_add_incoming.auth_password = "pass62",
+      .details.admin_add_incoming.amount = "EUR:10.02" },
+    /* Run wirewatch to observe /admin/add/incoming */
+    { .oc = OC_RUN_WIREWATCH,
+      .label = "wirewatch-11" },
+    { .oc = OC_CHECK_BANK_TRANSFER,
+      .label = "check_bank_transfer-11",
+      .details.check_bank_transfer.amount = "EUR:10.02",
+      .details.check_bank_transfer.account_debit = 62,
+      .details.check_bank_transfer.account_credit = EXCHANGE_ACCOUNT_NO
+    },
+
+    /* Withdraw a 5 EUR coin, at fee of 1 ct */
+    { .oc = OC_WITHDRAW_SIGN,
+      .label = "withdraw-coin-11a",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.reserve_withdraw.reserve_reference
+        = "create-reserve-11",
+      .details.reserve_withdraw.amount = "EUR:5" },
+
+    /* Withdraw a 5 EUR coin, at fee of 1 ct */
+    { .oc = OC_WITHDRAW_SIGN,
+      .label = "withdraw-coin-11b",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.reserve_withdraw.reserve_reference
+        = "create-reserve-11",
+      .details.reserve_withdraw.amount = "EUR:5" },
+
+    /* Check that deposit and withdraw operation are in history,
+       and that the balance is now at zero */
+    { .oc = OC_WITHDRAW_STATUS,
+      .label = "withdraw-status-11",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.reserve_status.reserve_reference
+        = "create-reserve-11",
+      .details.reserve_status.expected_balance = "EUR:0" },
+
+    /* Create proposal */
+    { .oc = OC_PROPOSAL,
+      .label = "create-proposal-11",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.proposal.order = "{\
+        \"max_fee\":\
+          {\"currency\":\"EUR\",\
+           \"value\":0,\
+           \"fraction\":50000000},\
+        \"order_id\":\"11\",\
+        \"refund_deadline\":\"\\/Date(0)\\/\",\
+        \"pay_deadline\":\"\\/Date(99999999999)\\/\",\
+        \"amount\":\
+          {\"currency\":\"EUR\",\
+           \"value\":10,\
+           \"fraction\":0},\
+       \"summary\": \"merchant-lib testcase\",\
+        \"products\":\
+          [ {\"description\":\"ice cream\",\
+             \"value\":\"{EUR:10}\"} ] }"},
+
+    /* execute simple payment, re-using one ancient coin */
+    { .oc = OC_PAY,
+      .label = "pay-fail-partial-double-11",
+      .expected_response_code = MHD_HTTP_FORBIDDEN,
+      .details.pay.contract_ref = "create-proposal-11",
+      .details.pay.coin_ref = "withdraw-coin-11a;withdraw-coin-1",
+      /* These amounts are given per coin! */
+      .details.pay.refund_fee = "EUR:0.01",
+      .details.pay.amount_with_fee = "EUR:5",
+      .details.pay.amount_without_fee = "EUR:4.99" },
+
+    /* Try to replay payment reusing coin */
+    { .oc = OC_PAY_ABORT,
+      .label = "pay-abort-11",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.pay_abort.pay_ref = "pay-fail-partial-double-11",
+    },
+
+    { .oc = OC_PAY_ABORT_REFUND,
+      .label = "pay-abort-refund-11",
+      .expected_response_code = MHD_HTTP_OK,
+      .details.pay_abort_refund.abort_ref = "pay-abort-11",
+      .details.pay_abort_refund.num_coin = 0,
+      .details.pay_abort_refund.refund_amount = "EUR:5",
+      .details.pay_abort_refund.refund_fee = "EUR:0.01" },
+    
+    /* Run transfers. */
+    { .oc = OC_RUN_AGGREGATOR,
+      .label = "run-aggregator-11" },
+    /* Check that there are no other unusual transfers */
+    { .oc = OC_CHECK_BANK_TRANSFERS_EMPTY,
+      .label = "check_bank_empty-11" },
+    
     /* end of testcase */
     { .oc = OC_END }
   };

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



reply via email to

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