LCOV - code coverage report
Current view: top level - lib - testing_api_cmd_tip.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 237 283 83.7 %
Date: 2018-05-16 06:16:58 Functions: 18 18 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_tip.c
      22             :  * @brief command to test the tipping.
      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_merchant_service.h"
      30             : #include "taler_merchant_testing_lib.h"
      31             : 
      32             : /**
      33             :  * Obtain the URL to use for an API request.
      34             :  *
      35             :  * @param h the exchange handle to query
      36             :  * @param path Taler API path (i.e. "/reserve/withdraw")
      37             :  * @return the full URL to use with cURL
      38             :  */
      39             : char *
      40             : MAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
      41             :                  const char *path);
      42             : 
      43             : struct TipPickupState
      44             : {
      45             :   const char *merchant_url;
      46             : 
      47             :   const char *exchange_url;
      48             : 
      49             :   struct GNUNET_CURL_Context *ctx;
      50             : 
      51             :   unsigned int http_status;
      52             : 
      53             :   const char *authorize_reference;
      54             : 
      55             :   /**
      56             :    * Set to non-NULL to a label of another pick up operation
      57             :    * that we should replay.
      58             :    */
      59             :   const char *replay_reference;
      60             : 
      61             :   struct TALER_MERCHANT_TipPickupOperation *tpo;
      62             : 
      63             :   struct TALER_TESTING_Interpreter *is;
      64             : 
      65             :   const char **amounts;
      66             : 
      67             :   struct TALER_Amount *amounts_obj;
      68             : 
      69             :   unsigned int num_coins;
      70             :   
      71             :   const struct TALER_EXCHANGE_DenomPublicKey **dks;
      72             : 
      73             :   struct TALER_PlanchetSecretsP *psa;
      74             : 
      75             :   /**
      76             :    * Temporary data structure of @e num_coins entries for the
      77             :    * withdraw operations.
      78             :    */
      79             :   struct WithdrawHandle *withdraws;
      80             : 
      81             :   /**
      82             :    * Set (by the interpreter) to an array of @a num_coins
      83             :    * signatures created from the (successful) tip operation.
      84             :    */
      85             :   struct TALER_DenominationSignature *sigs;
      86             : 
      87             :   enum TALER_ErrorCode expected_ec;
      88             : 
      89             :   struct TALER_EXCHANGE_Handle *exchange;
      90             : };
      91             : 
      92             : 
      93             : struct TipQueryState
      94             : {
      95             :   const char *merchant_url;
      96             : 
      97             :   struct GNUNET_CURL_Context *ctx;
      98             : 
      99             :   unsigned int http_status;
     100             : 
     101             :   const char *instance;
     102             : 
     103             :   struct TALER_MERCHANT_TipQueryOperation *tqo;
     104             : 
     105             :   struct TALER_TESTING_Interpreter *is;
     106             : 
     107             :   const char *expected_amount_picked_up;
     108             : 
     109             :   const char *expected_amount_authorized;
     110             : 
     111             :   const char *expected_amount_available;
     112             : };
     113             : 
     114             : 
     115             : struct TipAuthorizeState
     116             : {
     117             :   const char *merchant_url;
     118             : 
     119             :   struct GNUNET_CURL_Context *ctx;
     120             : 
     121             :   unsigned int http_status;
     122             : 
     123             :   const char *instance;
     124             : 
     125             :   const char *justification;
     126             : 
     127             :   const char *amount;
     128             : 
     129             :   enum TALER_ErrorCode expected_ec;
     130             : 
     131             :   const char *exchange_url;
     132             : 
     133             :   struct GNUNET_HashCode tip_id;
     134             : 
     135             :   struct GNUNET_TIME_Absolute tip_expiration;
     136             : 
     137             :   struct TALER_MERCHANT_TipAuthorizeOperation *tao;
     138             : 
     139             :   struct TALER_TESTING_Interpreter *is;
     140             : };
     141             : 
     142             : /**
     143             :  * Callback for a /tip-authorize request.  Returns the result
     144             :  * of the operation.
     145             :  *
     146             :  * @param cls closure
     147             :  * @param http_status HTTP status returned by the merchant backend
     148             :  * @param ec taler-specific error code
     149             :  * @param tip_id which tip ID should be used to pickup the tip
     150             :  * @param tip_expiration when does the tip expire (needs to be
     151             :  *        picked up before this time)
     152             :  * @param exchange_url at what exchange can the tip be picked up
     153             :  */
     154             : static void
     155           5 : tip_authorize_cb (void *cls,
     156             :                   unsigned int http_status,
     157             :                   enum TALER_ErrorCode ec,
     158             :                   const struct GNUNET_HashCode *tip_id,
     159             :                   struct GNUNET_TIME_Absolute tip_expiration,
     160             :                   const char *exchange_url)
     161             : {
     162           5 :   struct TipAuthorizeState *tas = cls; 
     163             : 
     164           5 :   tas->tao = NULL;
     165           5 :   if (tas->http_status != http_status)
     166             :   {
     167           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     168             :                 "Unexpected response code %u (%d)"
     169             :                 " to command %s\n",
     170             :                 http_status,
     171             :                 ec,
     172             :                 TALER_TESTING_interpreter_get_current_label
     173             :                   (tas->is));
     174             : 
     175           0 :     TALER_TESTING_interpreter_fail (tas->is);
     176           0 :     return;
     177             :   }
     178             : 
     179           5 :   if (tas->expected_ec != ec)
     180             :   {
     181           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     182             :                 "Unexpected error code %d (%u) to command %s\n",
     183             :                 ec,
     184             :                 http_status,
     185             :                 TALER_TESTING_interpreter_get_current_label
     186             :                   (tas->is));
     187           0 :     TALER_TESTING_interpreter_fail (tas->is);
     188           0 :     return;
     189             :   }
     190           5 :   if ( (MHD_HTTP_OK == http_status) &&
     191             :        (TALER_EC_NONE == ec) )
     192             :   {
     193           2 :     if (0 != strcmp (exchange_url,
     194             :                      tas->exchange_url))
     195             :     {
     196           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     197             :                   "Unexpected exchange URL %s to command %s\n",
     198             :                   exchange_url,
     199             :                   TALER_TESTING_interpreter_get_current_label
     200             :                     (tas->is));
     201           0 :       TALER_TESTING_interpreter_fail (tas->is);
     202           0 :       return;
     203             :     }
     204           2 :     tas->tip_id = *tip_id;
     205           2 :     tas->tip_expiration = tip_expiration;
     206             :   }
     207             : 
     208           5 :   TALER_TESTING_interpreter_next (tas->is);
     209             : }
     210             : 
     211             : /**
     212             :  * Extract information from a command that is useful for other
     213             :  * commands.
     214             :  *
     215             :  * @param cls closure
     216             :  * @param ret[out] result (could be anything)
     217             :  * @param trait name of the trait
     218             :  * @param selector more detailed information about which object
     219             :  *                 to return in case there were multiple generated
     220             :  *                 by the command
     221             :  * @return #GNUNET_OK on success
     222             :  */
     223             : static int
     224           3 : tip_authorize_traits (void *cls,
     225             :                       void **ret,
     226             :                       const char *trait,
     227             :                       unsigned int index)
     228             : {
     229           3 :   struct TipAuthorizeState *tas = cls;
     230             : 
     231           3 :   struct TALER_TESTING_Trait traits[] = {
     232           3 :     TALER_TESTING_make_trait_tip_id (0, &tas->tip_id),
     233             :     TALER_TESTING_trait_end (),
     234             :   };
     235             : 
     236           3 :   return TALER_TESTING_get_trait (traits,
     237             :                                   ret,
     238             :                                   trait,
     239             :                                   index);
     240             :   return GNUNET_SYSERR;
     241             : }
     242             : 
     243             : /**
     244             :  * Runs the command.  Note that upon return, the interpreter
     245             :  * will not automatically run the next command, as the command
     246             :  * may continue asynchronously in other scheduler tasks.  Thus,
     247             :  * the command must ensure to eventually call
     248             :  * #TALER_TESTING_interpreter_next() or
     249             :  * #TALER_TESTING_interpreter_fail().
     250             :  *
     251             :  * @param is interpreter state
     252             :  */
     253             : static void
     254           5 : tip_authorize_run (void *cls,
     255             :                    const struct TALER_TESTING_Command *cmd,
     256             :                    struct TALER_TESTING_Interpreter *is)
     257             : {
     258           5 :   struct TipAuthorizeState *tas = cls;
     259             :   struct TALER_Amount amount; 
     260             : 
     261           5 :   tas->is = is;
     262           5 :   if (GNUNET_OK != TALER_string_to_amount (tas->amount,
     263             :                                            &amount))
     264           0 :     TALER_TESTING_FAIL (is);
     265             : 
     266           5 :   tas->tao = TALER_MERCHANT_tip_authorize
     267             :     (tas->ctx,
     268             :      tas->merchant_url,
     269             :      "http://merchant.com/pickup",
     270             :      "http://merchant.com/continue",
     271             :      &amount,
     272             :      tas->instance,
     273             :      tas->justification,
     274             :      tip_authorize_cb,
     275             :      tas);
     276             : 
     277           5 :   GNUNET_assert (NULL != tas->tao);
     278             : }
     279             : 
     280             : 
     281             : /**
     282             :  * FIXME
     283             :  */
     284             : static void
     285           5 : tip_authorize_cleanup (void *cls,
     286             :                        const struct TALER_TESTING_Command *cmd)
     287             : {
     288           5 :   struct TipAuthorizeState *tas = cls;
     289             : 
     290           5 :   if (NULL != tas->tao)
     291             :   {
     292           0 :     TALER_LOG_WARNING ("Tip-autorize operation"
     293             :                        " did not complete\n");
     294           0 :     TALER_MERCHANT_tip_authorize_cancel (tas->tao);
     295             :   }
     296           5 :   GNUNET_free (tas);
     297           5 : }
     298             : 
     299             : 
     300             : /**
     301             :  * FIXME
     302             :  */
     303             : struct TALER_TESTING_Command
     304           3 : TALER_TESTING_cmd_tip_authorize_with_ec
     305             :   (const char *label,
     306             :    const char *merchant_url,
     307             :    const char *exchange_url,
     308             :    struct GNUNET_CURL_Context *ctx,
     309             :    unsigned int http_status,
     310             :    const char *instance,
     311             :    const char *justification,
     312             :    const char *amount,
     313             :    enum TALER_ErrorCode ec)
     314             : {
     315             :   struct TipAuthorizeState *tas;
     316             :   struct TALER_TESTING_Command cmd;
     317             : 
     318           3 :   tas = GNUNET_new (struct TipAuthorizeState);
     319           3 :   tas->merchant_url = merchant_url;
     320           3 :   tas->exchange_url = exchange_url;
     321           3 :   tas->ctx = ctx;
     322           3 :   tas->instance = instance;
     323           3 :   tas->justification = justification;
     324           3 :   tas->amount = amount;
     325           3 :   tas->http_status = http_status;
     326           3 :   tas->expected_ec = ec;
     327             : 
     328           3 :   cmd.label = label;
     329           3 :   cmd.cls = tas;
     330           3 :   cmd.run = &tip_authorize_run;
     331           3 :   cmd.cleanup = &tip_authorize_cleanup;
     332           3 :   cmd.traits = &tip_authorize_traits;
     333             :   
     334           3 :   return cmd;
     335             : }
     336             : 
     337             : 
     338             : /**
     339             :  * FIXME
     340             :  */
     341             : struct TALER_TESTING_Command
     342           2 : TALER_TESTING_cmd_tip_authorize (const char *label,
     343             :                                  const char *merchant_url,
     344             :                                  const char *exchange_url,
     345             :                                  struct GNUNET_CURL_Context *ctx,
     346             :                                  unsigned int http_status,
     347             :                                  const char *instance,
     348             :                                  const char *justification,
     349             :                                  const char *amount)
     350             : {
     351             :   struct TipAuthorizeState *tas;
     352             :   struct TALER_TESTING_Command cmd;
     353             : 
     354           2 :   tas = GNUNET_new (struct TipAuthorizeState);
     355           2 :   tas->merchant_url = merchant_url;
     356           2 :   tas->exchange_url = exchange_url;
     357           2 :   tas->ctx = ctx;
     358           2 :   tas->instance = instance;
     359           2 :   tas->justification = justification;
     360           2 :   tas->amount = amount;
     361           2 :   tas->http_status = http_status;
     362             : 
     363           2 :   cmd.label = label;
     364           2 :   cmd.cls = tas;
     365           2 :   cmd.run = &tip_authorize_run;
     366           2 :   cmd.cleanup = &tip_authorize_cleanup;
     367           2 :   cmd.traits = &tip_authorize_traits;
     368             :   
     369           2 :   return cmd;
     370             : }
     371             : 
     372             : /**
     373             :  * Callback to process a GET /tip-query request
     374             :  *
     375             :  * @param cls closure
     376             :  * @param http_status HTTP status code for this request
     377             :  * @param ec Taler-specific error code
     378             :  * @param raw raw response body
     379             :  */
     380             : static void
     381           4 : tip_query_cb (void *cls,
     382             :               unsigned int http_status,
     383             :               enum TALER_ErrorCode ec,
     384             :               const json_t *raw,
     385             :               struct GNUNET_TIME_Absolute reserve_expiration,
     386             :               struct TALER_ReservePublicKeyP *reserve_pub,
     387             :               struct TALER_Amount *amount_authorized,
     388             :               struct TALER_Amount *amount_available,
     389             :               struct TALER_Amount *amount_picked_up)
     390             : {
     391           4 :   struct TipQueryState *tqs = cls;
     392             :   struct TALER_Amount a;
     393             : 
     394           4 :   tqs->tqo = NULL;
     395           4 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     396             :               "Tip query callback at command `%s'\n",
     397             :               TALER_TESTING_interpreter_get_current_label
     398             :                 (tqs->is));
     399             : 
     400           4 :   GNUNET_assert (NULL != reserve_pub);
     401           4 :   GNUNET_assert (NULL != amount_authorized);
     402           4 :   GNUNET_assert (NULL != amount_available);
     403           4 :   GNUNET_assert (NULL != amount_picked_up);
     404             : 
     405           4 :   if (tqs->expected_amount_available)
     406             :   {
     407           3 :     GNUNET_assert (GNUNET_OK == TALER_string_to_amount
     408             :       (tqs->expected_amount_available, &a));
     409           3 :     TALER_LOG_INFO ("expected available %s, actual %s\n",
     410             :                     TALER_amount_to_string (&a),
     411             :                     TALER_amount_to_string (amount_available));
     412           3 :     if (0 != TALER_amount_cmp (amount_available, &a))
     413           0 :       TALER_TESTING_FAIL (tqs->is);
     414             :   }
     415             : 
     416           4 :   if (tqs->expected_amount_authorized)
     417             :   {
     418           2 :     GNUNET_assert (GNUNET_OK == TALER_string_to_amount
     419             :       (tqs->expected_amount_authorized, &a));
     420           2 :     TALER_LOG_INFO ("expected authorized %s, actual %s\n",
     421             :                     TALER_amount_to_string (&a),
     422             :                     TALER_amount_to_string (amount_authorized));
     423           2 :     if (0 != TALER_amount_cmp (amount_authorized, &a))
     424           0 :       TALER_TESTING_FAIL (tqs->is);
     425             :   }
     426             : 
     427           4 :   if (tqs->expected_amount_picked_up)
     428             :   {
     429           3 :     GNUNET_assert (GNUNET_OK == TALER_string_to_amount
     430             :       (tqs->expected_amount_picked_up, &a));
     431           3 :     TALER_LOG_INFO ("expected picked_up %s, actual %s\n",
     432             :                     TALER_amount_to_string (&a),
     433             :                     TALER_amount_to_string (amount_picked_up));
     434           3 :     if (0 != TALER_amount_cmp (amount_picked_up, &a))
     435           0 :       TALER_TESTING_FAIL (tqs->is);
     436             :   }
     437             : 
     438           4 :   if (tqs->http_status != http_status)
     439           0 :     TALER_TESTING_FAIL (tqs->is);
     440             : 
     441           4 :   TALER_TESTING_interpreter_next (tqs->is);
     442             : }
     443             : 
     444             : /**
     445             :  * FIXME
     446             :  */
     447             : static void
     448           4 : tip_query_cleanup (void *cls,
     449             :                    const struct TALER_TESTING_Command *cmd)
     450             : {
     451           4 :   struct TipQueryState *tqs = cls;
     452             : 
     453           4 :   if (NULL != tqs->tqo)
     454             :   {
     455           0 :     TALER_LOG_WARNING ("Tip-query operation"
     456             :                        " did not complete\n");
     457           0 :     TALER_MERCHANT_tip_query_cancel (tqs->tqo);
     458             :   }
     459           4 :   GNUNET_free (tqs);
     460           4 : }
     461             : 
     462             : /**
     463             :  * FIXME
     464             :  */
     465             : static void
     466           4 : tip_query_run (void *cls,
     467             :                const struct TALER_TESTING_Command *cmd,
     468             :                struct TALER_TESTING_Interpreter *is)
     469             : {
     470           4 :   struct TipQueryState *tqs = cls;
     471             :   
     472           4 :   tqs->is = is;
     473           4 :   tqs->tqo = TALER_MERCHANT_tip_query (tqs->ctx,
     474             :                                        tqs->merchant_url,
     475             :                                        tqs->instance,
     476             :                                        &tip_query_cb,
     477             :                                        tqs);
     478           4 :   GNUNET_assert (NULL != tqs->tqo);
     479           4 : }
     480             : 
     481             : 
     482             : /**
     483             :  * FIXME
     484             :  */
     485             : struct TALER_TESTING_Command
     486           3 : TALER_TESTING_cmd_tip_query_with_amounts
     487             :   (const char *label,
     488             :    const char *merchant_url,
     489             :    struct GNUNET_CURL_Context *ctx,
     490             :    unsigned int http_status,
     491             :    const char *instance,
     492             :    const char *expected_amount_picked_up,
     493             :    const char *expected_amount_authorized,
     494             :    const char *expected_amount_available)
     495             : {
     496             :   struct TipQueryState *tqs;
     497             :   struct TALER_TESTING_Command cmd;
     498             : 
     499           3 :   tqs = GNUNET_new (struct TipQueryState);
     500           3 :   tqs->merchant_url = merchant_url;
     501           3 :   tqs->ctx = ctx;
     502           3 :   tqs->instance = instance;
     503           3 :   tqs->http_status = http_status;
     504           3 :   tqs->expected_amount_picked_up = expected_amount_picked_up;
     505           3 :   tqs->expected_amount_authorized = expected_amount_authorized;
     506           3 :   tqs->expected_amount_available = expected_amount_available;
     507             : 
     508           3 :   cmd.cls = tqs;
     509           3 :   cmd.label = label;
     510           3 :   cmd.run = &tip_query_run;
     511           3 :   cmd.cleanup = &tip_query_cleanup;
     512             :   
     513           3 :   return cmd;
     514             : }
     515             : 
     516             : 
     517             : /**
     518             :  * FIXME
     519             :  */
     520             : struct TALER_TESTING_Command
     521           1 : TALER_TESTING_cmd_tip_query (const char *label,
     522             :                              const char *merchant_url,
     523             :                              struct GNUNET_CURL_Context *ctx,
     524             :                              unsigned int http_status,
     525             :                              const char *instance)
     526             : {
     527             :   struct TipQueryState *tqs;
     528             :   struct TALER_TESTING_Command cmd;
     529             : 
     530           1 :   tqs = GNUNET_new (struct TipQueryState);
     531           1 :   tqs->merchant_url = merchant_url;
     532           1 :   tqs->ctx = ctx;
     533           1 :   tqs->instance = instance;
     534           1 :   tqs->http_status = http_status;
     535             : 
     536           1 :   cmd.cls = tqs;
     537           1 :   cmd.label = label;
     538           1 :   cmd.run = &tip_query_run;
     539           1 :   cmd.cleanup = &tip_query_cleanup;
     540             :   
     541           1 :   return cmd;
     542             : }
     543             : 
     544             : /**
     545             :  * Internal withdraw handle used when withdrawing tips.
     546             :  */
     547             : struct WithdrawHandle
     548             : {
     549             :   /**
     550             :    * Withdraw operation this handle represents.
     551             :    */
     552             :   struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
     553             : 
     554             :   /**
     555             :    * Interpreter state we are part of.
     556             :    */
     557             :   struct TALER_TESTING_Interpreter *is;
     558             : 
     559             :   /**
     560             :    * Offset of this withdraw operation in the current
     561             :    * @e is command.
     562             :    */
     563             :   unsigned int off;
     564             : 
     565             : };
     566             : 
     567             : /**
     568             :  * Callbacks of this type are used to serve the result of
     569             :  * submitting a withdraw request to a exchange.
     570             :  *
     571             :  * @param cls closure, a `struct WithdrawHandle *`
     572             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200)
     573             :  *        for successful status request, 0 if the exchange's
     574             :  *        reply is bogus (fails to follow the protocol)
     575             :  * @param ec taler-specific error code, #TALER_EC_NONE on success
     576             :  * @param sig signature over the coin, NULL on error
     577             :  * @param full_response full response from the exchange
     578             :  *        (for logging, in case of errors)
     579             :  */
     580             : static void
     581           2 : pickup_withdraw_cb (void *cls,
     582             :                     unsigned int http_status,
     583             :                     enum TALER_ErrorCode ec,
     584             :                     const struct TALER_DenominationSignature *sig,
     585             :                     const json_t *full_response)
     586             : {
     587           2 :   struct WithdrawHandle *wh = cls;
     588           2 :   struct TALER_TESTING_Interpreter *is = wh->is;
     589           2 :   struct TipPickupState *tps = is->commands[is->ip].cls;
     590             : 
     591           2 :   wh->wsh = NULL;
     592           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     593             :               "Withdraw operation %u completed with %u (%d)\n",
     594             :               wh->off,
     595             :               http_status,
     596             :               ec);
     597           2 :   GNUNET_assert (wh->off < tps->num_coins);
     598           2 :   if ( (MHD_HTTP_OK != http_status) ||
     599             :        (TALER_EC_NONE != ec) )
     600             :   {
     601           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     602             :                 "Unexpected response code %u (%d)"
     603             :                 " to command %s when withdrawing\n",
     604             :                 http_status,
     605             :                 ec,
     606             :                 TALER_TESTING_interpreter_get_current_label (is));
     607           0 :     TALER_TESTING_interpreter_fail (is);
     608           0 :     return;
     609             :   }
     610           2 :   if (NULL == tps->sigs)
     611           2 :     tps->sigs = GNUNET_new_array
     612             :       (tps->num_coins, struct TALER_DenominationSignature);
     613             : 
     614           2 :   GNUNET_assert (NULL == tps->sigs[wh->off].rsa_signature);
     615           2 :   tps->sigs[wh->off].rsa_signature
     616           2 :     = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
     617             : 
     618           4 :   for (unsigned int i=0; i<tps->num_coins; i++)
     619           2 :     if (NULL != tps->withdraws[wh->off].wsh)
     620           0 :       return; /* still some ops ongoing */
     621             : 
     622           2 :   GNUNET_free (tps->withdraws);
     623           2 :   tps->withdraws = NULL;
     624           2 :   TALER_TESTING_interpreter_next (is);
     625             : }
     626             : 
     627             : 
     628             : /**
     629             :  * Callback for a /tip-pickup request.  Returns the result of
     630             :  * the operation.
     631             :  *
     632             :  * @param cls closure
     633             :  * @param http_status HTTP status returned by the merchant
     634             :  *        backend, "200 OK" on success
     635             :  * @param ec taler-specific error code
     636             :  * @param reserve_pub public key of the reserve that made the
     637             :  *        @a reserve_sigs, NULL on error
     638             :  * @param num_reserve_sigs length of the @a reserve_sigs array,
     639             :  *        0 on error
     640             :  * @param reserve_sigs array of signatures authorizing withdrawals,
     641             :  *        NULL on error
     642             :  * @param json original json response
     643             :  */
     644             : static void
     645           3 : pickup_cb (void *cls,
     646             :            unsigned int http_status,
     647             :            enum TALER_ErrorCode ec,
     648             :            const struct TALER_ReservePublicKeyP *reserve_pub,
     649             :            unsigned int num_reserve_sigs,
     650             :            const struct TALER_ReserveSignatureP *reserve_sigs,
     651             :            const json_t *json)
     652             : {
     653           3 :   struct TipPickupState *tps = cls;
     654             : 
     655           3 :   tps->tpo = NULL;
     656           3 :   if (http_status != tps->http_status)
     657             :   {
     658           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     659             :                 "Unexpected response code %u (%d) to command %s\n",
     660             :                 http_status,
     661             :                 ec,
     662             :                 TALER_TESTING_interpreter_get_current_label
     663             :                   (tps->is));
     664           0 :     TALER_TESTING_FAIL (tps->is);
     665             :   }
     666             : 
     667           3 :   if (ec != tps->expected_ec)
     668           0 :     TALER_TESTING_FAIL (tps->is);
     669             : 
     670             : 
     671           3 :   if ( (MHD_HTTP_OK != http_status) ||
     672             :        (TALER_EC_NONE != ec) )
     673             :   {
     674           1 :     TALER_TESTING_interpreter_next (tps->is);
     675           1 :     return;
     676             :   }
     677           2 :   if (num_reserve_sigs != tps->num_coins)
     678           0 :     TALER_TESTING_FAIL (tps->is);
     679             : 
     680             :   /* pickup successful, now withdraw! */
     681           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     682             :               "Obtained %u signatures for withdrawal"
     683             :               " from picking up a tip\n",
     684             :               num_reserve_sigs);
     685           2 :   GNUNET_assert (NULL == tps->withdraws);
     686           2 :   tps->withdraws = GNUNET_new_array
     687             :     (num_reserve_sigs, struct WithdrawHandle);
     688             : 
     689           4 :   for (unsigned int i=0;i<num_reserve_sigs;i++)
     690             :   {
     691           2 :     struct WithdrawHandle *wh = &tps->withdraws[i];
     692             : 
     693           2 :     wh->off = i;
     694           2 :     wh->is = tps->is;
     695           2 :     GNUNET_assert
     696             :       ( (NULL == wh->wsh) &&
     697             :         ( (NULL == tps->sigs) ||
     698             :           (NULL == tps->sigs[wh->off].rsa_signature) ) );
     699           4 :     wh->wsh = TALER_EXCHANGE_reserve_withdraw2
     700             :       (tps->exchange,
     701           2 :        tps->dks[i],
     702           2 :        &reserve_sigs[i],
     703             :        reserve_pub,
     704           2 :        &tps->psa[i],
     705             :        &pickup_withdraw_cb,
     706             :        wh);
     707           2 :   if (NULL == wh->wsh)
     708           0 :     TALER_TESTING_FAIL (tps->is);
     709             :   }
     710           2 :   if (0 == num_reserve_sigs)
     711           0 :     TALER_TESTING_interpreter_next (tps->is);
     712             : }
     713             : 
     714             : static void
     715           3 : tip_pickup_run (void *cls,
     716             :                 const struct TALER_TESTING_Command *cmd,
     717             :                 struct TALER_TESTING_Interpreter *is)
     718             : {
     719             : 
     720           3 :   struct TipPickupState *tps = cls;
     721             :   unsigned int num_planchets;
     722             :   const struct TALER_TESTING_Command *replay_cmd;
     723             :   const struct TALER_TESTING_Command *authorize_cmd;
     724             :   const struct GNUNET_HashCode *tip_id;
     725             : 
     726           3 :   tps->is = is;
     727           3 :   tps->exchange_url = MAH_path_to_url (tps->exchange, "/");
     728           3 :   if (NULL == tps->replay_reference)
     729             :   {
     730           3 :     replay_cmd = NULL;
     731             : 
     732             :     /* Count planchets. */
     733           9 :     for (num_planchets=0;
     734           6 :          NULL != tps->amounts[num_planchets];
     735           3 :          num_planchets++);
     736             :   }
     737             :   else
     738             :   {
     739             :     unsigned int *np;
     740           0 :     if ( NULL == /* looking for "parent" tip-pickup command */
     741           0 :        ( replay_cmd = TALER_TESTING_interpreter_lookup_command
     742             :          (is, tps->replay_reference)) )
     743           0 :     TALER_TESTING_FAIL (is);   
     744             :     
     745           0 :     if (GNUNET_OK != TALER_TESTING_get_trait_uint
     746             :         (replay_cmd, 0, &np))
     747           0 :       TALER_TESTING_FAIL (is);
     748           0 :     num_planchets = *np;
     749             :   }
     750             : 
     751           3 :   if (NULL ==
     752           3 :      ( authorize_cmd = TALER_TESTING_interpreter_lookup_command
     753             :        (is, tps->authorize_reference)) )
     754           0 :     TALER_TESTING_FAIL (is);
     755             : 
     756           3 :   tps->num_coins = num_planchets;
     757           3 :   {
     758           3 :     struct TALER_PlanchetDetail planchets[num_planchets];
     759             : 
     760           3 :     tps->psa = GNUNET_new_array (num_planchets,
     761             :                                  struct TALER_PlanchetSecretsP);
     762           3 :     tps->dks = GNUNET_new_array
     763             :       (num_planchets,
     764             :        const struct TALER_EXCHANGE_DenomPublicKey *);
     765             : 
     766           3 :     tps->amounts_obj = GNUNET_new_array
     767             :       (num_planchets, struct TALER_Amount);
     768             : 
     769           6 :     for (unsigned int i=0;i<num_planchets;i++)
     770             :     {
     771           3 :       if (NULL == replay_cmd)
     772             :       {
     773           3 :         GNUNET_assert (GNUNET_OK == TALER_string_to_amount
     774             :           (tps->amounts[i], &tps->amounts_obj[i]));
     775             : 
     776           6 :         tps->dks[i] = TALER_TESTING_find_pk
     777             :           (is->keys,
     778           3 :            &tps->amounts_obj[i]);
     779             : 
     780           3 :         if (NULL == tps->dks[i])
     781           0 :           TALER_TESTING_FAIL (is);
     782             : 
     783           3 :         TALER_planchet_setup_random (&tps->psa[i]); 
     784             :       }
     785             :       else
     786             :       {
     787           0 :         if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
     788           0 :             (replay_cmd, i, &tps->dks[i]))
     789           0 :           TALER_TESTING_FAIL (is);
     790             : 
     791             :         struct TALER_PlanchetSecretsP *ps;
     792             : 
     793           0 :         if (GNUNET_OK != TALER_TESTING_get_trait_planchet_secrets
     794             :             (replay_cmd, i, &ps))
     795           0 :           TALER_TESTING_FAIL (is);
     796           0 :         tps->psa[i] = *ps;
     797             :       }
     798             : 
     799           6 :       if (GNUNET_OK != TALER_planchet_prepare (&tps->dks[i]->key,
     800           3 :                                                &tps->psa[i],
     801             :                                                &planchets[i]))
     802           0 :         TALER_TESTING_FAIL (is); 
     803             :     }
     804             :     
     805           3 :     if (GNUNET_OK != TALER_TESTING_get_trait_tip_id
     806             :       (authorize_cmd, 0, &tip_id))
     807           0 :       TALER_TESTING_FAIL (is);
     808             : 
     809           3 :     tps->tpo = TALER_MERCHANT_tip_pickup (tps->ctx,
     810             :                                           tps->merchant_url,
     811             :                                           tip_id,
     812             :                                           num_planchets,
     813             :                                           planchets,
     814             :                                           &pickup_cb,
     815             :                                           tps);
     816           3 :     GNUNET_assert (NULL != tps->tpo);
     817             :   }
     818             : }
     819             : 
     820             : 
     821             : static void
     822           3 : tip_pickup_cleanup (void *cls,
     823             :                     const struct TALER_TESTING_Command *cmd)
     824             : {
     825           3 :   struct TipPickupState *tps = cls;
     826             :   /* FIXME:  free elements *in* the state! */
     827           3 :   if (NULL != tps->tpo)
     828             :   {
     829           0 :     TALER_LOG_WARNING ("Tip-pickup operation"
     830             :                        " did not complete\n");
     831           0 :     TALER_MERCHANT_tip_pickup_cancel (tps->tpo);
     832             :   }
     833             : 
     834           3 :   GNUNET_free (tps);
     835           3 : }
     836             : 
     837             : 
     838             : /**
     839             :  * Extract information from a command that is useful for other
     840             :  * commands.
     841             :  *
     842             :  * @param cls closure
     843             :  * @param ret[out] result (could be anything)
     844             :  * @param trait name of the trait
     845             :  * @param selector more detailed information about which object
     846             :  *                 to return in case there were multiple generated
     847             :  *                 by the command
     848             :  * @return #GNUNET_OK on success
     849             :  */
     850             : static int
     851           5 : tip_pickup_traits (void *cls,
     852             :                    void **ret,
     853             :                    const char *trait,
     854             :                    unsigned int index)
     855           5 : {
     856           5 :   struct TipPickupState *tps = cls;
     857             :   #define NUM_TRAITS (tps->num_coins * 5) + 2
     858           5 :   struct TALER_TESTING_Trait traits[NUM_TRAITS];
     859             :   
     860          10 :   for (unsigned int i=0; i<tps->num_coins; i++)
     861             :   {
     862           5 :     traits[i] = TALER_TESTING_make_trait_planchet_secrets
     863           5 :       (i, &tps->psa[i]);
     864             : 
     865          10 :     traits[i + tps->num_coins] =
     866             :       TALER_TESTING_make_trait_coin_priv
     867           5 :         (i, &tps->psa[i].coin_priv);
     868             : 
     869          10 :     traits[i + (tps->num_coins * 2)] =
     870           5 :       TALER_TESTING_make_trait_denom_pub (i, tps->dks[i]);
     871             : 
     872          10 :     traits[i + (tps->num_coins *3)] =
     873           5 :       TALER_TESTING_make_trait_denom_sig (i, &tps->sigs[i]);
     874             : 
     875          10 :     traits[i + (tps->num_coins *4)] =
     876             :       TALER_TESTING_make_trait_amount_obj
     877           5 :         (i, &tps->amounts_obj[i]);
     878             : 
     879             :   }
     880           5 :   traits[NUM_TRAITS - 2] = TALER_TESTING_make_trait_url
     881             :     (0, tps->exchange_url);
     882           5 :   traits[NUM_TRAITS - 1] = TALER_TESTING_trait_end ();
     883             : 
     884           5 :   return TALER_TESTING_get_trait (traits,
     885             :                                   ret,
     886             :                                   trait,
     887             :                                   index);
     888             :   return GNUNET_SYSERR;
     889             : }
     890             : 
     891             : /**
     892             :  * FIXME
     893             :  */
     894             : struct TALER_TESTING_Command
     895           1 : TALER_TESTING_cmd_tip_pickup_with_ec
     896             :   (const char *label,
     897             :    const char *merchant_url,
     898             :    struct GNUNET_CURL_Context *ctx,
     899             :    unsigned int http_status,
     900             :    const char *authorize_reference,
     901             :    const char **amounts,
     902             :    struct TALER_EXCHANGE_Handle *exchange,
     903             :    enum TALER_ErrorCode ec)
     904             : {
     905             :   struct TipPickupState *tps;
     906             :   struct TALER_TESTING_Command cmd;
     907             : 
     908           1 :   tps = GNUNET_new (struct TipPickupState);
     909           1 :   tps->merchant_url = merchant_url;
     910           1 :   tps->ctx = ctx;
     911           1 :   tps->authorize_reference = authorize_reference;
     912           1 :   tps->amounts = amounts;
     913           1 :   tps->exchange = exchange;
     914           1 :   tps->http_status = http_status;
     915           1 :   tps->expected_ec = ec;
     916             : 
     917           1 :   cmd.cls = tps;
     918           1 :   cmd.label = label;
     919           1 :   cmd.run = &tip_pickup_run;
     920           1 :   cmd.cleanup = &tip_pickup_cleanup;
     921           1 :   cmd.traits = &tip_pickup_traits;
     922             :   
     923           1 :   return cmd;
     924             : }
     925             : 
     926             : 
     927             : /**
     928             :  * FIXME
     929             :  */
     930             : struct TALER_TESTING_Command
     931           2 : TALER_TESTING_cmd_tip_pickup
     932             :   (const char *label,
     933             :    const char *merchant_url,
     934             :    struct GNUNET_CURL_Context *ctx,
     935             :    unsigned int http_status,
     936             :    const char *authorize_reference,
     937             :    const char **amounts,
     938             :    struct TALER_EXCHANGE_Handle *exchange)
     939             : {
     940             :   struct TipPickupState *tps;
     941             :   struct TALER_TESTING_Command cmd;
     942             : 
     943           2 :   tps = GNUNET_new (struct TipPickupState);
     944           2 :   tps->merchant_url = merchant_url;
     945           2 :   tps->ctx = ctx;
     946           2 :   tps->authorize_reference = authorize_reference;
     947           2 :   tps->amounts = amounts;
     948           2 :   tps->exchange = exchange;
     949           2 :   tps->http_status = http_status;
     950             : 
     951           2 :   cmd.cls = tps;
     952           2 :   cmd.label = label;
     953           2 :   cmd.run = &tip_pickup_run;
     954           2 :   cmd.cleanup = &tip_pickup_cleanup;
     955           2 :   cmd.traits = &tip_pickup_traits;
     956             :   
     957           2 :   return cmd;
     958             : }
     959             : 
     960             : 
     961             : /* end of testing_api_cmd_tip.c */

Generated by: LCOV version 1.13