LCOV - code coverage report
Current view: top level - lib - testing_api_cmd_pay.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 270 351 76.9 %
Date: 2018-05-16 06:16:58 Functions: 24 24 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2018 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify
       6             :   it under the terms of the GNU General Public License as
       7             :   published by the Free Software Foundation; either version 3, or
       8             :   (at your option) any later version.
       9             : 
      10             :   TALER is distributed in the hope that it will be useful, but
      11             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :   GNU General Public License for more details.
      14             : 
      15             :   You should have received a copy of the GNU General Public
      16             :   License along with TALER; see the file COPYING.  If not, see
      17             :   <http://www.gnu.org/licenses/>
      18             : */
      19             : 
      20             : /**
      21             :  * @file lib/testing_api_cmd_pay.c
      22             :  * @brief command to test the /pay feature.
      23             :  * @author Marcello Stanisci
      24             :  */
      25             : 
      26             : #include "platform.h"
      27             : #include <taler/taler_exchange_service.h>
      28             : #include <taler/taler_testing_lib.h>
      29             : #include <taler/taler_signatures.h>
      30             : #include "taler_merchant_service.h"
      31             : #include "taler_merchant_testing_lib.h"
      32             : 
      33             : #define AMOUNT_WITH_FEE 0
      34             : #define AMOUNT_WITHOUT_FEE 1
      35             : #define REFUND_FEE 2
      36             : 
      37             : struct PayState
      38             : {
      39             :   /**
      40             :    * Contract terms hash code.
      41             :    */
      42             :   struct GNUNET_HashCode h_contract_terms;
      43             : 
      44             :   /**
      45             :    * The interpreter state.
      46             :    */
      47             :   struct TALER_TESTING_Interpreter *is;
      48             : 
      49             :   /**
      50             :    * Expected HTTP response status code.
      51             :    */
      52             :   unsigned int http_status;
      53             : 
      54             :   /**
      55             :    * Reference to a command that can provide a order id,
      56             :    * typically a /proposal test command.
      57             :    */
      58             :   const char *proposal_reference;
      59             : 
      60             :   /**
      61             :    * Reference to a command that can provide a coin, so
      62             :    * we can pay here.
      63             :    */
      64             :   const char *coin_reference;
      65             : 
      66             :   /**
      67             :    * The curl context; used to be fed to the merchant lib.
      68             :    */
      69             :   struct GNUNET_CURL_Context *ctx;
      70             : 
      71             :   /**
      72             :    * The merchant base URL.
      73             :    */
      74             :   const char *merchant_url;
      75             : 
      76             :   /**
      77             :    * Amount to be paid, plus the deposit fee.
      78             :    */
      79             :   const char *amount_with_fee;
      80             : 
      81             :   /**
      82             :    * Amount to be paid, including NO fees.
      83             :    */
      84             :   const char *amount_without_fee;
      85             : 
      86             :   /**
      87             :    * Fee for refunding this payment.
      88             :    */
      89             :   const char *refund_fee;
      90             : 
      91             :   /**
      92             :    * Handle to the /pay operation.
      93             :    */
      94             :   struct TALER_MERCHANT_Pay *po;
      95             : 
      96             :   /**
      97             :    * JSON object of contract terms.  Needed here
      98             :    * to be free'd when this command gets cleaned up.
      99             :    */
     100             :   json_t *ct;
     101             : 
     102             : };
     103             : 
     104             : 
     105             : struct CheckPaymentState
     106             : {
     107             : 
     108             :   /**
     109             :    * Operation handle.
     110             :    */
     111             :   struct TALER_MERCHANT_CheckPaymentOperation *cpo;
     112             : 
     113             :   /**
     114             :    * The interpreter state.
     115             :    */
     116             :   struct TALER_TESTING_Interpreter *is;
     117             : 
     118             :   /**
     119             :    * Expected HTTP response status code.
     120             :    */
     121             :   unsigned int http_status;
     122             : 
     123             :   /**
     124             :    * Reference to a command that can provide a order id,
     125             :    * typically a /proposal test command.
     126             :    */
     127             :   const char *proposal_reference;
     128             : 
     129             :   /**
     130             :    * GNUNET_YES if we expect the proposal was paid.
     131             :    */
     132             :   unsigned int expect_paid;
     133             : 
     134             :   /**
     135             :    * The curl context; used to be fed to the merchant lib.
     136             :    */
     137             :   struct GNUNET_CURL_Context *ctx;
     138             : 
     139             :   /**
     140             :    * The merchant base URL.
     141             :    */
     142             :   const char *merchant_url;
     143             : 
     144             : };
     145             : 
     146             : 
     147             : struct PayAgainState
     148             : {
     149             :   
     150             :   /**
     151             :    * Expected HTTP response code.
     152             :    */
     153             :   unsigned int http_status;
     154             : 
     155             :   /**
     156             :    * Reference to the "pay" command to abort.
     157             :    */
     158             :   const char *pay_reference;
     159             : 
     160             :   /**
     161             :    * Reference to the coins to use.
     162             :    */
     163             :   const char *coin_reference;
     164             : 
     165             :   /**
     166             :    * Main CURL context.
     167             :    */
     168             :   struct GNUNET_CURL_Context *ctx;
     169             : 
     170             :   /**
     171             :    * Merchant URL.
     172             :    */
     173             :   const char *merchant_url;
     174             : 
     175             :   /**
     176             :    * Refund fee.
     177             :    */
     178             :   const char *refund_fee;
     179             : 
     180             :   /**
     181             :    * Handle to a "pay again" operation.
     182             :    */
     183             :   struct TALER_MERCHANT_Pay *pao;
     184             : 
     185             :   /**
     186             :    * Interpreter state.
     187             :    */
     188             :   struct TALER_TESTING_Interpreter *is;
     189             : };
     190             : 
     191             : 
     192             : struct PayAbortState
     193             : {
     194             :   
     195             :   /**
     196             :    * Expected HTTP response code.
     197             :    */
     198             :   unsigned int http_status;
     199             : 
     200             :   /**
     201             :    * Reference to the "pay" command to abort.
     202             :    */
     203             :   const char *pay_reference;
     204             : 
     205             :   /**
     206             :    * Main CURL context.
     207             :    */
     208             :   struct GNUNET_CURL_Context *ctx;
     209             : 
     210             :   /**
     211             :    * Merchant URL.
     212             :    */
     213             :   const char *merchant_url;
     214             : 
     215             :   /**
     216             :    * Handle to a "pay abort" operation.
     217             :    */
     218             :   struct TALER_MERCHANT_Pay *pao;
     219             : 
     220             :   /**
     221             :    * Interpreter state.
     222             :    */
     223             :   struct TALER_TESTING_Interpreter *is;
     224             : 
     225             : 
     226             :   /**
     227             :    * FIXME.
     228             :    */
     229             :   unsigned int num_refunds;
     230             : 
     231             :   /**
     232             :    * FIXME.
     233             :    */
     234             :   struct TALER_MERCHANT_RefundEntry *res;
     235             : 
     236             :   /**
     237             :    * FIXME.
     238             :    */
     239             :   struct GNUNET_HashCode h_contract;
     240             : 
     241             :   /**
     242             :    * Merchant public key.
     243             :    */
     244             :   struct TALER_MerchantPublicKeyP merchant_pub;
     245             : };
     246             : 
     247             : 
     248             : struct PayAbortRefundState
     249             : {
     250             :   const char *abort_reference;
     251             : 
     252             :   unsigned int num_coins;
     253             : 
     254             :   const char *refund_amount;
     255             : 
     256             :   const char *refund_fee;
     257             : 
     258             :   struct TALER_TESTING_Interpreter *is;
     259             : 
     260             :   /**
     261             :    * Handle to the refund operation.
     262             :    */
     263             :   struct TALER_EXCHANGE_RefundHandle *rh;
     264             : 
     265             :   /**
     266             :    * Expected HTTP response code.
     267             :    */
     268             :   unsigned int http_status;
     269             : 
     270             :   struct TALER_EXCHANGE_Handle *exchange;
     271             : };
     272             : 
     273             : 
     274             : 
     275             : /**
     276             :  * Clean up after the command.  Run during forced termination
     277             :  * (CTRL-C) or test failure or test success.
     278             :  *
     279             :  * @param cls closure
     280             :  */
     281             : static void
     282           2 : check_payment_cleanup (void *cls,
     283             :                        const struct TALER_TESTING_Command *cmd)
     284             : {
     285           2 :   struct CheckPaymentState *cps = cls;
     286             : 
     287           2 :   if (NULL != cps->cpo)
     288             :   {
     289           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     290             :                 "Command `%s' was not terminated\n",
     291             :                 TALER_TESTING_interpreter_get_current_label (
     292             :                   cps->is));
     293           0 :     TALER_MERCHANT_check_payment_cancel (cps->cpo);  
     294             :   }
     295           2 :   GNUNET_free (cps);
     296           2 : }
     297             : 
     298             : 
     299             : /**
     300             :  * Callback for GET /proposal issued at backend. Just check
     301             :  * whether response code is as expected.
     302             :  *
     303             :  * @param cls closure
     304             :  * @param http_status HTTP status code we got
     305             :  * @param json full response we got
     306             :  */
     307             : static void
     308           2 : check_payment_cb (void *cls,
     309             :                   unsigned int http_status,
     310             :                   const json_t *obj,
     311             :                   int paid,
     312             :                   int refunded,
     313             :                   struct TALER_Amount *refund_amount,
     314             :                   const char *payment_redirect_url)
     315             : {
     316           2 :   struct CheckPaymentState *cps = cls;
     317             : 
     318           2 :   cps->cpo = NULL;
     319           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     320             :               "check payment: expected paid: %s: %d\n",
     321             :               TALER_TESTING_interpreter_get_current_label (
     322             :                 cps->is),
     323             :               cps->expect_paid);
     324           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     325             :               "check payment: paid: %d\n",
     326             :               paid);
     327           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     328             :               "check payment: url: %s\n",
     329             :               payment_redirect_url);
     330             : 
     331           2 :   if (paid != cps->expect_paid)
     332           0 :     TALER_TESTING_FAIL (cps->is);
     333             : 
     334           2 :   if (cps->http_status != http_status)
     335           0 :     TALER_TESTING_FAIL (cps->is);
     336             : 
     337           2 :   TALER_TESTING_interpreter_next (cps->is);
     338             : }
     339             : 
     340             : /**
     341             :  * Runs the command.  Note that upon return, the interpreter
     342             :  * will not automatically run the next command, as the command
     343             :  * may continue asynchronously in other scheduler tasks.  Thus,
     344             :  * the command must ensure to eventually call
     345             :  * #TALER_TESTING_interpreter_next() or
     346             :  * #TALER_TESTING_interpreter_fail().
     347             :  *
     348             :  * @param is interpreter state
     349             :  */
     350             : static void
     351           2 : check_payment_run (void *cls,
     352             :                    const struct TALER_TESTING_Command *cmd,
     353             :                    struct TALER_TESTING_Interpreter *is)
     354             : {
     355           2 :   struct CheckPaymentState *cps = cls;
     356             :   const struct TALER_TESTING_Command *proposal_cmd;
     357             :   const char *order_id;
     358             : 
     359           2 :   cps->is = is;
     360           2 :   proposal_cmd = TALER_TESTING_interpreter_lookup_command (
     361             :     is, cps->proposal_reference);
     362             : 
     363           2 :   if (NULL == proposal_cmd)
     364           0 :     TALER_TESTING_FAIL (is);
     365             : 
     366           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_order_id (
     367             :     proposal_cmd, 0, &order_id))
     368           0 :     TALER_TESTING_FAIL (is);
     369             : 
     370           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     371             :               "Checking for order id `%s'\n",
     372             :               order_id);
     373             : 
     374           2 :   cps->cpo = TALER_MERCHANT_check_payment (
     375             :     cps->ctx,
     376             :     cps->merchant_url,
     377             :     "default", // only default instance for now.
     378             :     order_id,
     379             :     NULL,
     380             :     NULL,
     381             :     NULL,
     382             :     check_payment_cb,
     383             :     cps);
     384             : 
     385           2 :   GNUNET_assert (NULL != cps->cpo); 
     386             : }
     387             : 
     388             : /**
     389             :  * Make a "check payment" test command.
     390             :  *
     391             :  * @param label command label.
     392             :  * @param merchant_url merchant base url
     393             :  * @param ctx CURL context.
     394             :  * @param http_status expected HTTP response code.
     395             :  * @param proposal_reference the proposal whose payment status
     396             :  *        is going to be checked.
     397             :  * @param expect_paid GNUNET_YES if we expect the proposal to be
     398             :  *        paid, GNUNET_NO otherwise.
     399             :  *
     400             :  * @return the command
     401             :  */
     402             : struct TALER_TESTING_Command
     403           2 : TALER_TESTING_cmd_check_payment (const char *label,
     404             :                                  const char *merchant_url,
     405             :                                  struct GNUNET_CURL_Context *ctx,
     406             :                                  unsigned int http_status,
     407             :                                  const char *proposal_reference,
     408             :                                  unsigned int expect_paid)
     409             : {
     410             :   struct CheckPaymentState *cps;
     411             :   struct TALER_TESTING_Command cmd;
     412             : 
     413           2 :   cps = GNUNET_new (struct CheckPaymentState);
     414           2 :   cps->http_status = http_status;
     415           2 :   cps->proposal_reference = proposal_reference;
     416           2 :   cps->expect_paid = expect_paid;
     417           2 :   cps->ctx = ctx;
     418           2 :   cps->merchant_url = merchant_url;
     419             : 
     420           2 :   cmd.cls = cps;
     421           2 :   cmd.label = label;
     422           2 :   cmd.run = &check_payment_run;
     423           2 :   cmd.cleanup = &check_payment_cleanup;
     424             : 
     425           2 :   return cmd;
     426             : 
     427             : }
     428             : 
     429             : /**
     430             :  * Parse the @a coins specification and grow the @a pc
     431             :  * array with the coins found, updating @a npc.
     432             :  *
     433             :  * @param[in,out] pc pointer to array of coins found
     434             :  * @param[in,out] npc length of array at @a pc
     435             :  * @param[in] coins string specifying coins to add to @a pc,
     436             :  *            clobbered in the process
     437             :  * @param is interpreter state
     438             :  * @param amount_with_fee total amount to be paid for a contract.
     439             :  * @param amount_without_fee to be removed, there is no
     440             :  *        per-contract fee, only per-coin exists.
     441             :  * @param refund_fee per-contract? per-coin?
     442             :  * @return #GNUNET_OK on success
     443             :  */
     444             : static int
     445          10 : build_coins (struct TALER_MERCHANT_PayCoin **pc,
     446             :              unsigned int *npc,
     447             :              char *coins,
     448             :              struct TALER_TESTING_Interpreter *is,
     449             :              const char *amount_with_fee,
     450             :              const char *amount_without_fee,
     451             :              const char *refund_fee)
     452             : {
     453             :   char *token;
     454             : 
     455          34 :   for (token = strtok (coins, ";");
     456             :        NULL != token;
     457          14 :        token = strtok (NULL, ";"))
     458             :   {
     459             :     const struct TALER_TESTING_Command *coin_cmd;
     460             :     char *ctok;
     461             :     unsigned int ci;
     462             :     struct TALER_MERCHANT_PayCoin *icoin;
     463             :     const struct TALER_EXCHANGE_DenomPublicKey *dpk;
     464             : 
     465             :     /* Token syntax is "LABEL[/NUMBER]" */
     466          14 :     ctok = strchr (token, '/');
     467          14 :     ci = 0;
     468          14 :     if (NULL != ctok)
     469             :     {
     470           0 :       *ctok = '\0';
     471           0 :       ctok++;
     472           0 :       if (1 != sscanf (ctok,
     473             :                        "%u",
     474             :                        &ci))
     475             :       {
     476           0 :         GNUNET_break (0);
     477           0 :         return GNUNET_SYSERR;
     478             :       }
     479             :     }
     480             : 
     481          14 :     coin_cmd = TALER_TESTING_interpreter_lookup_command
     482             :       (is, token);
     483             : 
     484          14 :     if (NULL == coin_cmd)
     485             :     {
     486           0 :       GNUNET_break (0);
     487           0 :       return GNUNET_SYSERR;
     488             :     }
     489             : 
     490          14 :     GNUNET_array_grow (*pc,
     491             :                        *npc,
     492             :                        (*npc) + 1);
     493             : 
     494          14 :     icoin = &(*pc)[(*npc)-1];
     495             : 
     496             :     /* FIXME: make the two following 'const'. */
     497             :     struct TALER_CoinSpendPrivateKeyP *coin_priv; 
     498             :     struct TALER_DenominationSignature *denom_sig;
     499             :     const struct TALER_Amount *denom_value;
     500             :     const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     501             : 
     502          14 :     GNUNET_assert
     503             :       (GNUNET_OK == TALER_TESTING_get_trait_coin_priv
     504             :         (coin_cmd, 0, &coin_priv));
     505             : 
     506          14 :     GNUNET_assert
     507             :       (GNUNET_OK == TALER_TESTING_get_trait_denom_pub
     508             :         (coin_cmd, 0, &denom_pub));
     509             : 
     510          14 :     GNUNET_assert
     511             :       (GNUNET_OK == TALER_TESTING_get_trait_denom_sig
     512             :         (coin_cmd, 0, &denom_sig));
     513             : 
     514          14 :     GNUNET_assert
     515             :       (GNUNET_OK == TALER_TESTING_get_trait_amount_obj
     516             :         (coin_cmd, 0, &denom_value));
     517             : 
     518          14 :     icoin->coin_priv = *coin_priv;
     519          14 :     icoin->denom_pub = denom_pub->key;
     520          14 :     icoin->denom_sig = *denom_sig;
     521          14 :     icoin->denom_value = *denom_value;
     522          14 :     icoin->amount_with_fee = *denom_value;
     523             :     
     524          14 :     GNUNET_assert (NULL != (dpk = TALER_TESTING_find_pk
     525             :       (is->keys, &icoin->denom_value)));
     526             : 
     527          14 :     GNUNET_assert (GNUNET_SYSERR != TALER_amount_subtract
     528             :       (&icoin->amount_without_fee,
     529             :        &icoin->denom_value,
     530             :        &dpk->fee_deposit));
     531             : 
     532          14 :     GNUNET_assert
     533             :       (GNUNET_OK == TALER_TESTING_get_trait_url
     534             :         (coin_cmd, 0, &icoin->exchange_url)); 
     535             : 
     536          14 :     GNUNET_assert
     537             :       (GNUNET_OK == TALER_string_to_amount
     538             :         (refund_fee, &icoin->refund_fee));
     539             :   }
     540             : 
     541          10 :   return GNUNET_OK;
     542             : }
     543             : 
     544             : 
     545             : /**
     546             :  * Function called with the result of a /pay operation.
     547             :  *
     548             :  * @param cls closure with the interpreter state
     549             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200)
     550             :  *        for successful deposit; 0 if the exchange's reply is
     551             :  *        bogus (fails to follow the protocol)
     552             :  * @param ec taler-specific error object
     553             :  * @param obj the received JSON reply, should be kept as proof
     554             :  *        (and, in case of errors, be forwarded to the customer)
     555             :  */
     556             : static void
     557           7 : pay_cb (void *cls,
     558             :         unsigned int http_status,
     559             :         enum TALER_ErrorCode ec,
     560             :         const json_t *obj)
     561             : {
     562           7 :   struct PayState *ps = cls;
     563             : 
     564             :   struct GNUNET_CRYPTO_EddsaSignature sig;
     565             :   const char *error_name;
     566             :   unsigned int error_line;
     567             :   const struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
     568             :   const struct TALER_TESTING_Command *proposal_cmd;
     569             : 
     570           7 :   ps->po = NULL;
     571           7 :   if (ps->http_status != http_status)
     572             :   {
     573           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     574             :                 "Unexpected response code %u (%d) to command %s\n",
     575             :                 http_status,
     576             :                 ec,
     577             :                 TALER_TESTING_interpreter_get_current_label (
     578             :                   ps->is));
     579           0 :     TALER_TESTING_FAIL (ps->is);
     580             :   }
     581           7 :   if (MHD_HTTP_OK == http_status)
     582             :   {
     583             :     /* Check signature */
     584             :     struct PaymentResponsePS mr;
     585           8 :     struct GNUNET_JSON_Specification spec[] = {
     586             :       GNUNET_JSON_spec_fixed_auto ("sig",
     587             :                                    &sig),
     588           4 :       GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
     589             :                                    &ps->h_contract_terms),
     590             :       GNUNET_JSON_spec_end ()
     591             :     };
     592             : 
     593           4 :     GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (
     594             :       obj, spec,
     595             :       &error_name,
     596             :       &error_line));
     597             : 
     598           4 :     mr.purpose.purpose = htonl (
     599             :       TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
     600           4 :     mr.purpose.size = htonl (sizeof (mr));
     601           4 :     mr.h_contract_terms = ps->h_contract_terms;
     602             : 
     603             :     /* proposal reference was used at least once, at this point */
     604           4 :     GNUNET_assert
     605             :       ( NULL !=
     606             :       ( proposal_cmd = TALER_TESTING_interpreter_lookup_command
     607             :       (ps->is, ps->proposal_reference)));
     608             : 
     609           4 :     if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
     610             :         (proposal_cmd, 0, &merchant_pub))
     611           0 :       TALER_TESTING_FAIL (ps->is);
     612             : 
     613           4 :     if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (
     614             :       TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
     615             :       &mr.purpose, &sig,
     616             :       merchant_pub))
     617             :     {
     618           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     619             :                   "Merchant signature given in response to /pay"
     620             :                   " invalid\n");
     621           0 :       TALER_TESTING_FAIL (ps->is);
     622             :     }
     623             :   }
     624             : 
     625           7 :   TALER_TESTING_interpreter_next (ps->is);
     626             : }
     627             : 
     628             : /**
     629             :  * FIXME
     630             :  */
     631             : static void
     632           2 : pay_abort_cb (void *cls,
     633             :               unsigned int http_status,
     634             :               enum TALER_ErrorCode ec,
     635             :               const struct TALER_MerchantPublicKeyP *merchant_pub,
     636             :               const struct GNUNET_HashCode *h_contract,
     637             :               unsigned int num_refunds,
     638             :               const struct TALER_MERCHANT_RefundEntry *res,
     639             :               const json_t *obj)
     640             : {
     641           2 :   struct PayAbortState *pas = cls;
     642             : 
     643           2 :   pas->pao = NULL;
     644           2 :   if (pas->http_status != http_status)
     645             :   {
     646           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     647             :                 "Unexpected response code %u (%d) to command %s\n",
     648             :                 http_status,
     649             :                 ec,
     650             :                 TALER_TESTING_interpreter_get_current_label
     651             :                   (pas->is));
     652           0 :     TALER_TESTING_FAIL (pas->is);
     653             :   }
     654           2 :   if ( (MHD_HTTP_OK == http_status) &&
     655             :        (TALER_EC_NONE == ec) )
     656             :   {
     657           1 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     658             :                 "Received %u refunds\n",
     659             :                 num_refunds);
     660           1 :     pas->num_refunds = num_refunds;
     661             : 
     662           1 :     pas->res = GNUNET_new_array
     663             :       (num_refunds, struct TALER_MERCHANT_RefundEntry);
     664             : 
     665           1 :     memcpy (pas->res, res,
     666             :             num_refunds * sizeof
     667             :               (struct TALER_MERCHANT_RefundEntry));
     668           1 :     pas->h_contract = *h_contract;
     669           1 :     pas->merchant_pub = *merchant_pub;
     670             :   }
     671             : 
     672           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     673             :               "Successful pay-abort (HTTP status: %u)\n",
     674             :               http_status);
     675           2 :   TALER_TESTING_interpreter_next (pas->is);
     676             : }
     677             : 
     678             : 
     679             : /**
     680             :  * @param cls the closure.  Will be a "pay" or "pay-abort" state,
     681             :  *        depending on whether the caller was "pay" or "pay abort"
     682             :  *        run method.
     683             :  *
     684             :  * @return handle to the operation, NULL if errors occur.
     685             :  */
     686             : static struct TALER_MERCHANT_Pay *
     687          10 : _pay_run (const char *merchant_url,
     688             :           struct GNUNET_CURL_Context *ctx,
     689             :           const char *coin_reference,
     690             :           const char *proposal_reference,
     691             :           struct TALER_TESTING_Interpreter *is,
     692             :           const char *amount_with_fee,
     693             :           const char *amount_without_fee,
     694             :           const char *refund_fee,
     695             :           struct TALER_MERCHANT_Pay * (*api_func) (),
     696             :           void (*api_cb) (),
     697             :           void *cls)
     698             : {
     699             :   const struct TALER_TESTING_Command *proposal_cmd;
     700             :   const char *contract_terms;
     701             :   const char *order_id;
     702             :   struct GNUNET_TIME_Absolute refund_deadline;
     703             :   struct GNUNET_TIME_Absolute pay_deadline;
     704             :   struct GNUNET_TIME_Absolute timestamp;
     705             :   struct TALER_MerchantPublicKeyP merchant_pub;
     706             :   struct GNUNET_HashCode h_wire;
     707             :   const struct GNUNET_HashCode *h_proposal;
     708             :   struct TALER_Amount total_amount;
     709             :   struct TALER_Amount max_fee;
     710             :   const char *error_name;
     711             :   unsigned int error_line;
     712             :   struct TALER_MERCHANT_PayCoin *pay_coins;
     713             :   unsigned int npay_coins;
     714             :   char *cr;
     715             :   struct TALER_MerchantSignatureP *merchant_sig;
     716             :   struct TALER_MERCHANT_Pay *ret;
     717          10 :   struct PayState *ps = is->commands[is->ip].cls;
     718             : 
     719          10 :   proposal_cmd = TALER_TESTING_interpreter_lookup_command
     720             :     (is, proposal_reference);
     721             : 
     722          10 :   if (NULL == proposal_cmd)
     723             :   {
     724           0 :     GNUNET_break (0);
     725           0 :     return NULL;
     726             :   }
     727             : 
     728          10 :   if (GNUNET_OK != TALER_TESTING_get_trait_contract_terms
     729             :     (proposal_cmd, 0, &contract_terms))
     730             :   {
     731           0 :     GNUNET_break (0);
     732           0 :     return NULL;
     733             :   }
     734             : 
     735             :   json_error_t error;
     736          10 :   if (NULL ==
     737          10 :      (ps->ct = json_loads (contract_terms,
     738             :                            JSON_COMPACT,
     739             :                            &error)))
     740             :   {
     741           0 :     GNUNET_break (0);
     742           0 :     return NULL;
     743             :   }
     744             :   /* Get information that needs to be put verbatim in the
     745             :    * deposit permission */
     746          10 :   struct GNUNET_JSON_Specification spec[] = {
     747             :     GNUNET_JSON_spec_string ("order_id",
     748             :                              &order_id),
     749             :     GNUNET_JSON_spec_absolute_time ("refund_deadline",
     750             :                                     &refund_deadline),
     751             :     GNUNET_JSON_spec_absolute_time ("pay_deadline",
     752             :                                     &pay_deadline),
     753             :     GNUNET_JSON_spec_absolute_time ("timestamp",
     754             :                                     &timestamp),
     755             :     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     756             :                                  &merchant_pub),
     757             :     GNUNET_JSON_spec_fixed_auto ("H_wire",
     758             :                                  &h_wire),
     759             :     TALER_JSON_spec_amount ("amount",
     760             :                             &total_amount),
     761             :     TALER_JSON_spec_amount ("max_fee",
     762             :                             &max_fee),
     763             :     GNUNET_JSON_spec_end()
     764             :   };
     765          10 :   if (GNUNET_OK !=
     766          10 :       GNUNET_JSON_parse (ps->ct,
     767             :                          spec,
     768             :                          &error_name,
     769             :                          &error_line))
     770             :   {
     771           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     772             :                 "Parser failed on %s:%u\n",
     773             :                 error_name,
     774             :                 error_line);
     775           0 :     fprintf (stderr, "%s\n", contract_terms);
     776           0 :     GNUNET_break_op (0);
     777           0 :     return NULL;
     778             :   }
     779             : 
     780          10 :   cr = GNUNET_strdup (coin_reference);
     781          10 :   pay_coins = NULL;
     782          10 :   npay_coins = 0;
     783          10 :   if (GNUNET_OK !=
     784          10 :       build_coins (&pay_coins,
     785             :                    &npay_coins,
     786             :                    cr,
     787             :                    is,
     788             :                    amount_with_fee,
     789             :                    amount_without_fee,
     790             :                    refund_fee))
     791             :   {
     792           0 :     GNUNET_array_grow (pay_coins,
     793             :                        npay_coins,
     794             :                        0);
     795           0 :     GNUNET_free (cr);
     796           0 :     GNUNET_break (0);
     797           0 :     return NULL;
     798             :   }
     799             : 
     800          10 :   GNUNET_free (cr);
     801          10 :   if (GNUNET_OK != TALER_TESTING_get_trait_merchant_sig
     802             :     (proposal_cmd, 0, &merchant_sig))
     803             :   {
     804           0 :     GNUNET_break (0);
     805           0 :     return NULL;
     806             :   }
     807             : 
     808             : 
     809          10 :   if (GNUNET_OK != TALER_TESTING_get_trait_h_contract_terms
     810             :     (proposal_cmd, 0, &h_proposal))
     811             :   {
     812           0 :     GNUNET_break (0);
     813           0 :     return NULL;
     814             :   }
     815             : 
     816          10 :   ret = api_func (ctx,
     817             :                   merchant_url,
     818             :                   "default", // instance
     819             :                   h_proposal,
     820             :                   &total_amount,
     821             :                   &max_fee,
     822             :                   &merchant_pub,
     823             :                   merchant_sig,
     824             :                   timestamp,
     825             :                   refund_deadline,
     826             :                   pay_deadline,
     827             :                   &h_wire,
     828             :                   order_id,
     829             :                   npay_coins,
     830             :                   pay_coins,
     831             :                   api_cb,
     832             :                   cls);
     833             : 
     834          10 :   GNUNET_array_grow (pay_coins,
     835             :                      npay_coins,
     836             :                      0);
     837          10 :   return ret;
     838             : }
     839             : 
     840             : /**
     841             :  * Runs the command.  Note that upon return, the interpreter
     842             :  * will not automatically run the next command, as the command
     843             :  * may continue asynchronously in other scheduler tasks.  Thus,
     844             :  * the command must ensure to eventually call
     845             :  * #TALER_TESTING_interpreter_next() or
     846             :  * #TALER_TESTING_interpreter_fail().
     847             :  *
     848             :  * @param is interpreter state
     849             :  */
     850             : static void
     851           7 : pay_run (void *cls,
     852             :          const struct TALER_TESTING_Command *cmd,
     853             :          struct TALER_TESTING_Interpreter *is)
     854             : {
     855             : 
     856           7 :   struct PayState *ps = cls;
     857             :   
     858           7 :   ps->is = is;
     859           7 :   if ( NULL == 
     860           7 :      ( ps->po = _pay_run (ps->merchant_url,
     861             :                           ps->ctx,
     862             :                           ps->coin_reference,
     863             :                           ps->proposal_reference,
     864             :                           is,
     865             :                           ps->amount_with_fee,
     866             :                           ps->amount_without_fee,
     867             :                           ps->refund_fee,
     868             :                           &TALER_MERCHANT_pay_wallet,
     869             :                           &pay_cb,
     870             :                           ps)) )
     871           0 :     TALER_TESTING_FAIL (is);
     872             : }
     873             : 
     874             : /**
     875             :  * Clean up after the command.  Run during forced termination
     876             :  * (CTRL-C) or test failure or test success.
     877             :  *
     878             :  * @param cls closure
     879             :  */
     880             : static void
     881           7 : pay_cleanup (void *cls,
     882             :              const struct TALER_TESTING_Command *cmd)
     883             : {
     884           7 :   struct PayState *ps = cls;
     885             : 
     886           7 :   if (NULL != ps->ct)
     887           7 :     json_decref (ps->ct);
     888           7 :   if (NULL != ps->po)
     889             :   {
     890           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     891             :                 "Command `%s' did not complete.\n",
     892             :                 TALER_TESTING_interpreter_get_current_label (
     893             :                   ps->is));
     894           0 :     TALER_MERCHANT_pay_cancel (ps->po);
     895             :   }
     896             : 
     897           7 :   GNUNET_free (ps);
     898           7 : }
     899             : 
     900             : 
     901             : /**
     902             :  * Extract information from a command that is useful for other
     903             :  * commands.
     904             :  *
     905             :  * @param cls closure
     906             :  * @param ret[out] result (could be anything)
     907             :  * @param trait name of the trait
     908             :  * @param selector more detailed information about which object
     909             :  *                 to return in case there were multiple generated
     910             :  *                 by the command
     911             :  * @return #GNUNET_OK on success
     912             :  */
     913             : static int
     914          17 : pay_traits (void *cls,
     915             :             void **ret,
     916             :             const char *trait,
     917             :             unsigned int index)
     918             : {
     919             : 
     920          17 :   struct PayState *ps = cls;
     921             :   const char *order_id;
     922             :   const struct TALER_TESTING_Command *proposal_cmd;
     923             :   struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
     924             : 
     925          17 :   if ( NULL ==
     926          17 :      ( proposal_cmd = TALER_TESTING_interpreter_lookup_command
     927             :        (ps->is, ps->proposal_reference)))
     928             :   {
     929           0 :     GNUNET_break (0);
     930           0 :     return GNUNET_SYSERR;
     931             :   }
     932             : 
     933          17 :   if (GNUNET_OK != TALER_TESTING_get_trait_order_id
     934             :       (proposal_cmd, 0, &order_id))
     935             :   {
     936           0 :     GNUNET_break (0);
     937           0 :     return GNUNET_SYSERR;
     938             :   }
     939             : 
     940          17 :   if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
     941             :       (proposal_cmd,
     942             :        0,
     943             :        (const struct GNUNET_CRYPTO_EddsaPublicKey **)
     944             :          &merchant_pub))
     945             :   {
     946           0 :     GNUNET_break (0);
     947           0 :     return GNUNET_SYSERR;
     948             :   }
     949             : 
     950         119 :   struct TALER_TESTING_Trait traits[] = {
     951          17 :     TALER_TESTING_make_trait_amount
     952             :       (AMOUNT_WITH_FEE, ps->amount_with_fee),
     953          17 :     TALER_TESTING_make_trait_amount
     954             :       (AMOUNT_WITHOUT_FEE, ps->amount_without_fee),
     955          17 :     TALER_TESTING_make_trait_amount
     956             :       (REFUND_FEE, ps->refund_fee),
     957          17 :     TALER_TESTING_make_trait_proposal_reference
     958             :       (0, ps->proposal_reference),
     959          17 :     TALER_TESTING_make_trait_coin_reference
     960             :       (0, ps->coin_reference),
     961          17 :     TALER_TESTING_make_trait_order_id (0, order_id),
     962          17 :     TALER_TESTING_make_trait_peer_key_pub (0, merchant_pub),
     963             :     TALER_TESTING_trait_end ()
     964             :   };
     965             : 
     966          17 :   return TALER_TESTING_get_trait (traits,
     967             :                                   ret,
     968             :                                   trait,
     969             :                                   index);
     970             : 
     971             :   return GNUNET_SYSERR;
     972             : }
     973             : 
     974             : /**
     975             :  * Make a "pay" test command.
     976             :  *
     977             :  * @param label command label.
     978             :  * @param merchant_url merchant base url
     979             :  * @param ctx CURL context.
     980             :  * @param http_status expected HTTP response code.
     981             :  * @param proposal_reference the proposal whose payment status
     982             :  *        is going to be checked.
     983             :  * @param coin_reference reference to any command which is able
     984             :  *        to provide coins to use for paying.
     985             :  * @param amount_with_fee amount to pay, including the deposit
     986             :  *        fee
     987             :  * @param amount_without_fee amount to pay, no fees included.
     988             :  * @param refund_fee fee for refunding this payment.
     989             :  *
     990             :  * @return the command
     991             :  */
     992             : struct TALER_TESTING_Command
     993           7 : TALER_TESTING_cmd_pay (const char *label,
     994             :                        const char *merchant_url,
     995             :                        struct GNUNET_CURL_Context *ctx,
     996             :                        unsigned int http_status,
     997             :                        const char *proposal_reference,
     998             :                        const char *coin_reference,
     999             :                        const char *amount_with_fee,
    1000             :                        const char *amount_without_fee,
    1001             :                        const char *refund_fee)
    1002             : {
    1003             :   struct PayState *ps;
    1004             :   struct TALER_TESTING_Command cmd;
    1005             : 
    1006           7 :   ps = GNUNET_new (struct PayState);
    1007           7 :   ps->http_status = http_status;
    1008           7 :   ps->proposal_reference = proposal_reference;
    1009           7 :   ps->coin_reference = coin_reference;
    1010           7 :   ps->ctx = ctx;
    1011           7 :   ps->merchant_url = merchant_url;
    1012           7 :   ps->amount_with_fee = amount_with_fee;
    1013           7 :   ps->amount_without_fee = amount_without_fee;
    1014           7 :   ps->refund_fee = refund_fee;
    1015             : 
    1016           7 :   cmd.cls = ps;
    1017           7 :   cmd.label = label;
    1018           7 :   cmd.run = &pay_run;
    1019           7 :   cmd.cleanup = &pay_cleanup;
    1020           7 :   cmd.traits = &pay_traits;
    1021             : 
    1022           7 :   return cmd;
    1023             : 
    1024             : }
    1025             : 
    1026             : 
    1027             : /**
    1028             :  * Clean up after the command.  Run during forced termination
    1029             :  * (CTRL-C) or test failure or test success.
    1030             :  *
    1031             :  * @param cls closure
    1032             :  */
    1033             : static void
    1034           2 : pay_abort_cleanup (void *cls,
    1035             :                    const struct TALER_TESTING_Command *cmd)
    1036             : {
    1037           2 :   struct PayAbortState *pas = cls;
    1038             : 
    1039           2 :   if (NULL != pas->pao)
    1040             :   {
    1041           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1042             :                 "Command `%s' did not complete.\n",
    1043             :                 TALER_TESTING_interpreter_get_current_label (
    1044             :                   pas->is));
    1045           0 :     TALER_MERCHANT_pay_cancel (pas->pao);
    1046             :   }
    1047             : 
    1048           2 :   GNUNET_free (pas);
    1049           2 : }
    1050             : 
    1051             : /**
    1052             :  * Runs the command.  Note that upon return, the interpreter
    1053             :  * will not automatically run the next command, as the command
    1054             :  * may continue asynchronously in other scheduler tasks.  Thus,
    1055             :  * the command must ensure to eventually call
    1056             :  * #TALER_TESTING_interpreter_next() or
    1057             :  * #TALER_TESTING_interpreter_fail().
    1058             :  *
    1059             :  * @param is interpreter state
    1060             :  */
    1061             : static void
    1062           2 : pay_abort_run (void *cls,
    1063             :                const struct TALER_TESTING_Command *cmd,
    1064             :                struct TALER_TESTING_Interpreter *is)
    1065             : {
    1066             :   
    1067           2 :   struct PayAbortState *pas = cls;
    1068             :   const struct TALER_TESTING_Command *pay_cmd;
    1069             : 
    1070             :   const char *proposal_reference;
    1071             :   const char *coin_reference;
    1072             :   const char *amount_with_fee;
    1073             :   const char *amount_without_fee;
    1074             :   const char *refund_fee;
    1075             :   
    1076           2 :   pas->is = is;
    1077           2 :   pay_cmd = TALER_TESTING_interpreter_lookup_command
    1078             :     (is, pas->pay_reference);
    1079           2 :   if (NULL == pay_cmd)
    1080           0 :     TALER_TESTING_FAIL (is);
    1081             :   
    1082           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_proposal_reference
    1083             :       (pay_cmd, 0, &proposal_reference))
    1084           0 :     TALER_TESTING_FAIL (is);
    1085             : 
    1086           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_coin_reference
    1087             :       (pay_cmd, 0, &coin_reference))
    1088           0 :     TALER_TESTING_FAIL (is);
    1089             : 
    1090           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1091             :     (pay_cmd, AMOUNT_WITH_FEE, &amount_with_fee))
    1092           0 :     TALER_TESTING_FAIL (is);
    1093             : 
    1094           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1095             :     (pay_cmd, AMOUNT_WITHOUT_FEE, &amount_without_fee))
    1096           0 :     TALER_TESTING_FAIL (is);
    1097             : 
    1098           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1099             :     (pay_cmd, REFUND_FEE, &refund_fee))
    1100           0 :     TALER_TESTING_FAIL (is);
    1101             : 
    1102           2 :   if ( NULL ==
    1103           2 :      ( pas->pao = _pay_run (pas->merchant_url,
    1104             :                             pas->ctx,
    1105             :                             coin_reference,
    1106             :                             proposal_reference,
    1107             :                             is,
    1108             :                             amount_with_fee,
    1109             :                             amount_without_fee,
    1110             :                             refund_fee,
    1111             :                             &TALER_MERCHANT_pay_abort,
    1112             :                             &pay_abort_cb,
    1113             :                             pas)) )
    1114           0 :     TALER_TESTING_FAIL (is);
    1115             : }
    1116             : 
    1117             : /**
    1118             :  * Extract information from a command that is useful for other
    1119             :  * commands.
    1120             :  *
    1121             :  * @param cls closure
    1122             :  * @param ret[out] result (could be anything)
    1123             :  * @param trait name of the trait
    1124             :  * @param selector more detailed information about which object
    1125             :  *                 to return in case there were multiple generated
    1126             :  *                 by the command
    1127             :  * @return #GNUNET_OK on success
    1128             :  */
    1129             : static int
    1130           4 : pay_abort_traits (void *cls,
    1131             :                   void **ret,
    1132             :                   const char *trait,
    1133             :                   unsigned int index)
    1134             : {
    1135           4 :   struct PayAbortState *pas = cls;
    1136             : 
    1137          16 :   struct TALER_TESTING_Trait traits[] = {
    1138           4 :     TALER_TESTING_make_trait_peer_key_pub
    1139             :       (0, &pas->merchant_pub.eddsa_pub),
    1140             :     TALER_TESTING_make_trait_h_contract_terms
    1141           4 :       (0, &pas->h_contract),
    1142             :     TALER_TESTING_make_trait_refund_entry
    1143           4 :       (0, pas->res),
    1144           4 :     TALER_TESTING_make_trait_uint (0, &pas->num_refunds),
    1145             :     TALER_TESTING_trait_end ()
    1146             :   };
    1147             : 
    1148           4 :   return TALER_TESTING_get_trait (traits,
    1149             :                                   ret,
    1150             :                                   trait,
    1151             :                                   index);
    1152             : 
    1153             :   return GNUNET_SYSERR;
    1154             : }
    1155             : 
    1156             : /**
    1157             :  * Make a "pay abort" test command.
    1158             :  *
    1159             :  * @param label command label
    1160             :  * @param merchant_url merchant base URL
    1161             :  * @param pay_reference reference to the payment to abort
    1162             :  * @param ctx main CURL context
    1163             :  * @param http_status expected HTTP response code
    1164             :  *
    1165             :  * @return the command
    1166             :  */
    1167             : struct TALER_TESTING_Command
    1168           2 : TALER_TESTING_cmd_pay_abort (const char *label,
    1169             :                              const char *merchant_url,
    1170             :                              const char *pay_reference,
    1171             :                              struct GNUNET_CURL_Context *ctx,
    1172             :                              unsigned int http_status)
    1173             : {
    1174             :   struct PayAbortState *pas;
    1175             :   struct TALER_TESTING_Command cmd;
    1176             : 
    1177           2 :   pas = GNUNET_new (struct PayAbortState);
    1178           2 :   pas->http_status = http_status;
    1179           2 :   pas->pay_reference = pay_reference;
    1180           2 :   pas->ctx = ctx;
    1181           2 :   pas->merchant_url = merchant_url;
    1182             : 
    1183           2 :   cmd.cls = pas;
    1184           2 :   cmd.label = label;
    1185           2 :   cmd.run = &pay_abort_run;
    1186           2 :   cmd.cleanup = &pay_abort_cleanup;
    1187           2 :   cmd.traits = &pay_abort_traits;
    1188             :   
    1189           2 :   return cmd;
    1190             : }
    1191             : 
    1192             : /**
    1193             :  * Function called with the result of a /pay again operation.
    1194             :  *
    1195             :  * @param cls closure with the interpreter state
    1196             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200)
    1197             :  *        for successful deposit; 0 if the exchange's reply is
    1198             :  *        bogus (fails to follow the protocol)
    1199             :  * @param ec taler-specific error object
    1200             :  * @param obj the received JSON reply, should be kept as proof
    1201             :  *        (and, in case of errors, be forwarded to the customer)
    1202             :  */
    1203             : static void
    1204           1 : pay_again_cb (void *cls,
    1205             :               unsigned int http_status,
    1206             :               enum TALER_ErrorCode ec,
    1207             :               const json_t *obj)
    1208             : {
    1209           1 :   struct PayAgainState *pas = cls;
    1210             :   struct GNUNET_CRYPTO_EddsaSignature sig;
    1211             :   const char *error_name;
    1212             :   unsigned int error_line;
    1213             :   const struct TALER_TESTING_Command *pay_cmd;
    1214             :   const struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
    1215             : 
    1216           1 :   pas->pao = NULL;
    1217           1 :   if (pas->http_status != http_status)
    1218             :   {
    1219           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1220             :                 "Unexpected response code %u (%d) to command %s\n",
    1221             :                 http_status,
    1222             :                 ec,
    1223             :                 TALER_TESTING_interpreter_get_current_label
    1224             :                   (pas->is));
    1225           0 :     TALER_TESTING_interpreter_fail (pas->is);
    1226           0 :     return;
    1227             :   }
    1228             : 
    1229           1 :   if ( NULL ==
    1230           1 :      ( pay_cmd = TALER_TESTING_interpreter_lookup_command
    1231             :        (pas->is, pas->pay_reference)))
    1232           0 :     TALER_TESTING_FAIL (pas->is);
    1233             : 
    1234           1 :   if (MHD_HTTP_OK == http_status)
    1235             :   {
    1236             :     struct PaymentResponsePS mr;
    1237             :     /* Check signature */
    1238           1 :     struct GNUNET_JSON_Specification spec[] = {
    1239             :       GNUNET_JSON_spec_fixed_auto ("sig",
    1240             :                                    &sig),
    1241             :       GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
    1242             :                                    &mr.h_contract_terms),
    1243             :       GNUNET_JSON_spec_end ()
    1244             :     };
    1245             : 
    1246           1 :     GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (obj,
    1247             :                                                    spec,
    1248             :                                                    &error_name,
    1249             :                                                    &error_line));
    1250           1 :     mr.purpose.purpose = htonl
    1251             :       (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
    1252           1 :     mr.purpose.size = htonl (sizeof (mr));
    1253             : 
    1254           1 :     if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
    1255             :         (pay_cmd, 0, &merchant_pub))
    1256           0 :       TALER_TESTING_FAIL (pas->is);
    1257             : 
    1258           1 :     if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify
    1259             :       (TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
    1260             :        &mr.purpose,
    1261             :        &sig,
    1262             :        merchant_pub))
    1263             :     {
    1264           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1265             :                   "Merchant signature given in"
    1266             :                   " response to /pay invalid\n");
    1267           0 :       TALER_TESTING_FAIL (pas->is);
    1268             :     }
    1269             :   }
    1270             : 
    1271           1 :   TALER_TESTING_interpreter_next (pas->is);
    1272             : }
    1273             : 
    1274             : /**
    1275             :  * Runs the command.  Note that upon return, the interpreter
    1276             :  * will not automatically run the next command, as the command
    1277             :  * may continue asynchronously in other scheduler tasks.  Thus,
    1278             :  * the command must ensure to eventually call
    1279             :  * #TALER_TESTING_interpreter_next() or
    1280             :  * #TALER_TESTING_interpreter_fail().
    1281             :  *
    1282             :  * @param is interpreter state
    1283             :  */
    1284             : static void
    1285           1 : pay_again_run (void *cls,
    1286             :                const struct TALER_TESTING_Command *cmd,
    1287             :                struct TALER_TESTING_Interpreter *is)
    1288             : {
    1289           1 :   struct PayAgainState *pas = cls;
    1290             :   const struct TALER_TESTING_Command *pay_cmd;
    1291             : 
    1292             :   const char *proposal_reference;
    1293             :   const char *amount_with_fee;
    1294             :   const char *amount_without_fee;
    1295             :   
    1296           1 :   pas->is = is;
    1297           1 :   pay_cmd = TALER_TESTING_interpreter_lookup_command
    1298             :     (is, pas->pay_reference);
    1299           1 :   if (NULL == pay_cmd)
    1300           0 :     TALER_TESTING_FAIL (is);
    1301             :   
    1302           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_proposal_reference
    1303             :       (pay_cmd, 0, &proposal_reference))
    1304           0 :     TALER_TESTING_FAIL (is);
    1305             : 
    1306           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1307             :     (pay_cmd, AMOUNT_WITH_FEE, &amount_with_fee))
    1308           0 :     TALER_TESTING_FAIL (is);
    1309             : 
    1310           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1311             :     (pay_cmd, AMOUNT_WITHOUT_FEE, &amount_without_fee))
    1312           0 :     TALER_TESTING_FAIL (is);
    1313             : 
    1314           1 :   if ( NULL ==
    1315           1 :      ( pas->pao = _pay_run (pas->merchant_url,
    1316             :                             pas->ctx,
    1317             :                             pas->coin_reference,
    1318             :                             proposal_reference,
    1319             :                             is,
    1320             :                             amount_with_fee,
    1321             :                             amount_without_fee,
    1322             :                             pas->refund_fee,
    1323             :                             &TALER_MERCHANT_pay_wallet,
    1324             :                             &pay_again_cb,
    1325             :                             pas)) )
    1326           0 :     TALER_TESTING_FAIL (is);
    1327             : }
    1328             : 
    1329             : /**
    1330             :  * Clean up after the command.  Run during forced termination
    1331             :  * (CTRL-C) or test failure or test success.
    1332             :  *
    1333             :  * @param cls closure
    1334             :  */
    1335             : static void
    1336           1 : pay_again_cleanup (void *cls,
    1337             :                    const struct TALER_TESTING_Command *cmd)
    1338             : {
    1339           1 :   struct PayAgainState *pas = cls;
    1340             : 
    1341           1 :   if (NULL != pas->pao)
    1342             :   {
    1343           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1344             :                 "Command `%s' did not complete.\n",
    1345             :                 TALER_TESTING_interpreter_get_current_label (
    1346             :                   pas->is));
    1347           0 :     TALER_MERCHANT_pay_cancel (pas->pao);
    1348             :   }
    1349             : 
    1350           1 :   GNUNET_free (pas);
    1351           1 : }
    1352             : 
    1353             : /**
    1354             :  * Make a "pay again" test command.
    1355             :  *
    1356             :  * @param label command label
    1357             :  * @param merchant_url merchant base URL
    1358             :  * @param pay_reference reference to the payment to replay
    1359             :  * @param coin_reference reference to the coins to use
    1360             :  * @param ctx main CURL context
    1361             :  * @param http_status expected HTTP response code
    1362             :  *
    1363             :  * @return the command
    1364             :  */
    1365             : struct TALER_TESTING_Command
    1366           1 : TALER_TESTING_cmd_pay_again (const char *label,
    1367             :                              const char *merchant_url,
    1368             :                              const char *pay_reference,
    1369             :                              const char *coin_reference,
    1370             :                              const char *refund_fee,
    1371             :                              struct GNUNET_CURL_Context *ctx,
    1372             :                              unsigned int http_status)
    1373             : {
    1374             : 
    1375             :   struct PayAgainState *pas;
    1376             :   struct TALER_TESTING_Command cmd;
    1377             : 
    1378           1 :   pas = GNUNET_new (struct PayAgainState);
    1379           1 :   pas->http_status = http_status;
    1380           1 :   pas->pay_reference = pay_reference;
    1381           1 :   pas->coin_reference = coin_reference;
    1382           1 :   pas->ctx = ctx;
    1383           1 :   pas->merchant_url = merchant_url;
    1384           1 :   pas->refund_fee = refund_fee;
    1385             : 
    1386           1 :   cmd.cls = pas;
    1387           1 :   cmd.label = label;
    1388           1 :   cmd.run = &pay_again_run;
    1389           1 :   cmd.cleanup = &pay_again_cleanup;
    1390             :   
    1391           1 :   return cmd;
    1392             : }
    1393             : 
    1394             : 
    1395             : /**
    1396             :  * Callbacks of this type are used to serve the result of
    1397             :  * submitting a refund request to an exchange.
    1398             :  *
    1399             :  * @param cls closure
    1400             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
    1401             :  *        successful deposit; 0 if the exchange's reply is bogus
    1402             :  *        (fails to follow the protocol)
    1403             :  * @param ec taler-specific error code, #TALER_EC_NONE on success
    1404             :  * @param sign_key exchange key used to sign @a obj, or NULL
    1405             :  * @param obj the received JSON reply, should be kept as proof
    1406             :  *        (and, in particular, be forwarded to the customer)
    1407             :  */
    1408             : static void
    1409           1 : abort_refund_cb (void *cls,
    1410             :                  unsigned int http_status,
    1411             :                  enum TALER_ErrorCode ec,
    1412             :                  const struct TALER_ExchangePublicKeyP *sign_key,
    1413             :                  const json_t *obj)
    1414             : {
    1415           1 :   struct PayAbortRefundState *pars = cls;
    1416             : 
    1417           1 :   pars->rh = NULL;
    1418           1 :   if (pars->http_status != http_status)
    1419             :   {
    1420           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1421             :                 "Unexpected response code %u (%d) to command %s\n",
    1422             :                 http_status,
    1423             :                 ec,
    1424             :                 TALER_TESTING_interpreter_get_current_label
    1425             :                   (pars->is));
    1426           0 :     TALER_TESTING_interpreter_fail (pars->is);
    1427           0 :     return;
    1428             :   }
    1429           1 :   TALER_TESTING_interpreter_next (pars->is);
    1430             : }
    1431             : 
    1432             : /**
    1433             :  * FIXME.
    1434             :  */
    1435             : static void
    1436           1 : pay_abort_refund_cleanup (void *cls,
    1437             :                           const struct TALER_TESTING_Command *cmd)
    1438             : {
    1439           1 :   struct PayAbortRefundState *pars = cls;
    1440             : 
    1441           1 :   if (NULL != pars->rh)
    1442             :   {
    1443           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1444             :                 "Command `%s' did not complete.\n",
    1445             :                 TALER_TESTING_interpreter_get_current_label (
    1446             :                   pars->is));
    1447           0 :     TALER_EXCHANGE_refund_cancel (pars->rh);
    1448             :   }
    1449           1 :   GNUNET_free (pars);
    1450           1 : }
    1451             : 
    1452             : /**
    1453             :  * FIXME.
    1454             :  */
    1455             : static void
    1456           1 : pay_abort_refund_run (void *cls,
    1457             :                       const struct TALER_TESTING_Command *cmd,
    1458             :                       struct TALER_TESTING_Interpreter *is)
    1459             : {
    1460           1 :   struct PayAbortRefundState *pars = cls;
    1461             :   struct TALER_Amount refund_fee;
    1462             :   struct TALER_Amount refund_amount;
    1463             :   const struct TALER_MERCHANT_RefundEntry *refund_entry;
    1464             :   unsigned int *num_refunds;
    1465             :   const struct TALER_TESTING_Command *abort_cmd;
    1466             :   const struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
    1467             :   const struct GNUNET_HashCode *h_contract_terms;
    1468             : 
    1469           1 :   pars->is = is;
    1470             : 
    1471           1 :   if ( NULL ==
    1472           1 :      ( abort_cmd = TALER_TESTING_interpreter_lookup_command
    1473             :        (is, pars->abort_reference)) )
    1474           0 :     TALER_TESTING_FAIL (is);
    1475             : 
    1476           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_uint
    1477             :       (abort_cmd, 0, &num_refunds))
    1478           0 :     TALER_TESTING_FAIL (is);
    1479             : 
    1480           1 :   if (pars->num_coins >= *num_refunds)
    1481           0 :     TALER_TESTING_FAIL (is);
    1482             : 
    1483           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_h_contract_terms
    1484             :       (abort_cmd, 0, &h_contract_terms))
    1485           0 :     TALER_TESTING_FAIL (is);
    1486             : 
    1487           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
    1488             :       (abort_cmd, 0, &merchant_pub))
    1489           0 :     TALER_TESTING_FAIL (is);
    1490             : 
    1491           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_refund_entry
    1492             :       (abort_cmd, 0, &refund_entry))
    1493           0 :     TALER_TESTING_FAIL (is);
    1494             : 
    1495           1 :   GNUNET_assert (GNUNET_OK == TALER_string_to_amount 
    1496             :     (pars->refund_amount, &refund_amount));
    1497           1 :   GNUNET_assert (GNUNET_OK == TALER_string_to_amount 
    1498             :     (pars->refund_fee, &refund_fee));
    1499             : 
    1500           3 :   pars->rh = TALER_EXCHANGE_refund2
    1501             :     (pars->exchange,
    1502             :      &refund_amount,
    1503             :      &refund_fee,
    1504             :      h_contract_terms,
    1505           1 :      &refund_entry->coin_pub,
    1506           1 :      refund_entry->rtransaction_id,
    1507             :      (const struct TALER_MerchantPublicKeyP *) merchant_pub,
    1508           1 :      &refund_entry->merchant_sig,
    1509             :      &abort_refund_cb,
    1510             :      pars);
    1511             : 
    1512           1 :   GNUNET_assert (NULL != pars->rh);
    1513             : }
    1514             : 
    1515             : 
    1516             : /**
    1517             :  * FIXME.
    1518             :  */
    1519             : struct TALER_TESTING_Command
    1520           1 : TALER_TESTING_cmd_pay_abort_refund
    1521             :   (const char *label,
    1522             :    struct TALER_EXCHANGE_Handle *exchange,
    1523             :    const char *abort_reference,
    1524             :    unsigned int num_coins,
    1525             :    const char *refund_amount,
    1526             :    const char *refund_fee,
    1527             :    unsigned int http_status)
    1528             : {
    1529             :   struct PayAbortRefundState *pars;
    1530             :   struct TALER_TESTING_Command cmd;
    1531             : 
    1532           1 :   pars = GNUNET_new (struct PayAbortRefundState);
    1533           1 :   pars->abort_reference = abort_reference;
    1534           1 :   pars->num_coins = num_coins;
    1535           1 :   pars->refund_amount = refund_amount;
    1536           1 :   pars->refund_fee = refund_fee;
    1537           1 :   pars->http_status = http_status;
    1538           1 :   pars->exchange = exchange;
    1539             : 
    1540           1 :   cmd.cls = pars;
    1541           1 :   cmd.label = label;
    1542           1 :   cmd.run = &pay_abort_refund_run;
    1543           1 :   cmd.cleanup = &pay_abort_refund_cleanup;
    1544             : 
    1545           1 :   return cmd;
    1546             : }
    1547             : 
    1548             : /* end of testing_api_cmd_pay.c */

Generated by: LCOV version 1.13