exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

testing_api_cmd_reserve_get.c (9957B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2022 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  * @file testing/testing_api_cmd_reserve_get.c
     21  * @brief Implement the GET /reserve/$RID test command.
     22  * @author Marcello Stanisci
     23  */
     24 #include "taler/taler_json_lib.h"
     25 #include <gnunet/gnunet_curl_lib.h>
     26 #include "taler/taler_testing_lib.h"
     27 
     28 
     29 /**
     30  * State for a "poll" CMD.
     31  */
     32 struct PollState
     33 {
     34 
     35   /**
     36    * How long do we give the exchange to respond?
     37    */
     38   struct GNUNET_TIME_Relative timeout;
     39 
     40   /**
     41    * Label to the command which created the reserve to check,
     42    * needed to resort the reserve key.
     43    */
     44   const char *poll_reference;
     45 
     46   /**
     47    * Timeout to wait for at most.
     48    */
     49   struct GNUNET_SCHEDULER_Task *tt;
     50 
     51   /**
     52    * The interpreter we are using.
     53    */
     54   struct TALER_TESTING_Interpreter *is;
     55 };
     56 
     57 
     58 /**
     59  * State for a "status" CMD.
     60  */
     61 struct StatusState
     62 {
     63 
     64   /**
     65    * How long do we give the exchange to respond?
     66    */
     67   struct GNUNET_TIME_Relative timeout;
     68 
     69   /**
     70    * Poller waiting for us.
     71    */
     72   struct PollState *ps;
     73 
     74   /**
     75    * Label to the command which created the reserve to check,
     76    * needed to resort the reserve key.
     77    */
     78   const char *reserve_reference;
     79 
     80   /**
     81    * Handle to the "reserve status" operation.
     82    */
     83   struct TALER_EXCHANGE_GetReservesHandle *rsh;
     84 
     85   /**
     86    * Expected reserve balance.
     87    */
     88   const char *expected_balance;
     89 
     90   /**
     91    * Public key of the reserve being analyzed.
     92    */
     93   const struct TALER_ReservePublicKeyP *reserve_pubp;
     94 
     95   /**
     96    * Expected HTTP response code.
     97    */
     98   unsigned int expected_response_code;
     99 
    100   /**
    101    * Interpreter state.
    102    */
    103   struct TALER_TESTING_Interpreter *is;
    104 
    105 };
    106 
    107 
    108 /**
    109  * Check that the reserve balance and HTTP response code are
    110  * both acceptable.
    111  *
    112  * @param cls closure.
    113  * @param rs HTTP response details
    114  */
    115 static void
    116 reserve_status_cb (void *cls,
    117                    const struct TALER_EXCHANGE_GetReservesResponse *rs)
    118 {
    119   struct StatusState *ss = cls;
    120   struct TALER_TESTING_Interpreter *is = ss->is;
    121   struct TALER_Amount eb;
    122 
    123   ss->rsh = NULL;
    124   if (ss->expected_response_code != rs->hr.http_status)
    125   {
    126     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    127                 "Unexpected HTTP response code: %d in %s:%u\n",
    128                 rs->hr.http_status,
    129                 __FILE__,
    130                 __LINE__);
    131     json_dumpf (rs->hr.reply,
    132                 stderr,
    133                 0);
    134     TALER_TESTING_interpreter_fail (ss->is);
    135     return;
    136   }
    137   if (MHD_HTTP_OK == ss->expected_response_code)
    138   {
    139     GNUNET_assert (GNUNET_OK ==
    140                    TALER_string_to_amount (ss->expected_balance,
    141                                            &eb));
    142     if (0 != TALER_amount_cmp (&eb,
    143                                &rs->details.ok.balance))
    144     {
    145       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    146                   "Unexpected amount %s in reserve, wanted %s\n",
    147                   TALER_amount_to_string (&rs->details.ok.balance),
    148                   ss->expected_balance);
    149       TALER_TESTING_interpreter_fail (ss->is);
    150       return;
    151     }
    152   }
    153   if (NULL != ss->ps)
    154   {
    155     /* force continuation on long poller */
    156     GNUNET_SCHEDULER_cancel (ss->ps->tt);
    157     ss->ps->tt = NULL;
    158     TALER_TESTING_interpreter_next (is);
    159     return;
    160   }
    161   if (GNUNET_TIME_relative_is_zero (ss->timeout))
    162     TALER_TESTING_interpreter_next (is);
    163 }
    164 
    165 
    166 /**
    167  * Run the command.
    168  *
    169  * @param cls closure.
    170  * @param cmd the command being executed.
    171  * @param is the interpreter state.
    172  */
    173 static void
    174 status_run (void *cls,
    175             const struct TALER_TESTING_Command *cmd,
    176             struct TALER_TESTING_Interpreter *is)
    177 {
    178   struct StatusState *ss = cls;
    179   const struct TALER_TESTING_Command *create_reserve;
    180   const char *exchange_url;
    181 
    182   ss->is = is;
    183   exchange_url = TALER_TESTING_get_exchange_url (is);
    184   if (NULL == exchange_url)
    185   {
    186     GNUNET_break (0);
    187     return;
    188   }
    189   create_reserve
    190     = TALER_TESTING_interpreter_lookup_command (is,
    191                                                 ss->reserve_reference);
    192   GNUNET_assert (NULL != create_reserve);
    193   if (GNUNET_OK !=
    194       TALER_TESTING_get_trait_reserve_pub (create_reserve,
    195                                            &ss->reserve_pubp))
    196   {
    197     GNUNET_break (0);
    198     TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n");
    199     TALER_TESTING_interpreter_fail (is);
    200     return;
    201   }
    202   ss->rsh = TALER_EXCHANGE_get_reserves_create (
    203     TALER_TESTING_interpreter_get_context (is),
    204     exchange_url,
    205     ss->reserve_pubp);
    206   if (NULL == ss->rsh)
    207   {
    208     GNUNET_break (0);
    209     TALER_TESTING_interpreter_fail (is);
    210     return;
    211   }
    212   if (! GNUNET_TIME_relative_is_zero (ss->timeout))
    213     TALER_EXCHANGE_get_reserves_set_options (
    214       ss->rsh,
    215       TALER_EXCHANGE_get_reserves_option_timeout (ss->timeout));
    216   if (TALER_EC_NONE !=
    217       TALER_EXCHANGE_get_reserves_start (ss->rsh,
    218                                          &reserve_status_cb,
    219                                          ss))
    220   {
    221     GNUNET_break (0);
    222     TALER_EXCHANGE_get_reserves_cancel (ss->rsh);
    223     ss->rsh = NULL;
    224     TALER_TESTING_interpreter_fail (is);
    225     return;
    226   }
    227   if (! GNUNET_TIME_relative_is_zero (ss->timeout))
    228   {
    229     TALER_TESTING_interpreter_next (is);
    230     return;
    231   }
    232 }
    233 
    234 
    235 /**
    236  * Cleanup the state from a "reserve status" CMD, and possibly
    237  * cancel a pending operation thereof.
    238  *
    239  * @param cls closure.
    240  * @param cmd the command which is being cleaned up.
    241  */
    242 static void
    243 status_cleanup (void *cls,
    244                 const struct TALER_TESTING_Command *cmd)
    245 {
    246   struct StatusState *ss = cls;
    247 
    248   if (NULL != ss->rsh)
    249   {
    250     TALER_TESTING_command_incomplete (ss->is,
    251                                       cmd->label);
    252     TALER_EXCHANGE_get_reserves_cancel (ss->rsh);
    253     ss->rsh = NULL;
    254   }
    255   GNUNET_free (ss);
    256 }
    257 
    258 
    259 struct TALER_TESTING_Command
    260 TALER_TESTING_cmd_status (const char *label,
    261                           const char *reserve_reference,
    262                           const char *expected_balance,
    263                           unsigned int expected_response_code)
    264 {
    265   struct StatusState *ss;
    266 
    267   GNUNET_assert (NULL != reserve_reference);
    268   ss = GNUNET_new (struct StatusState);
    269   ss->reserve_reference = reserve_reference;
    270   ss->expected_balance = expected_balance;
    271   ss->expected_response_code = expected_response_code;
    272   {
    273     struct TALER_TESTING_Command cmd = {
    274       .cls = ss,
    275       .label = label,
    276       .run = &status_run,
    277       .cleanup = &status_cleanup
    278     };
    279 
    280     return cmd;
    281   }
    282 }
    283 
    284 
    285 struct TALER_TESTING_Command
    286 TALER_TESTING_cmd_reserve_poll (const char *label,
    287                                 const char *reserve_reference,
    288                                 const char *expected_balance,
    289                                 struct GNUNET_TIME_Relative timeout,
    290                                 unsigned int expected_response_code)
    291 {
    292   struct StatusState *ss;
    293 
    294   GNUNET_assert (NULL != reserve_reference);
    295   ss = GNUNET_new (struct StatusState);
    296   ss->reserve_reference = reserve_reference;
    297   ss->expected_balance = expected_balance;
    298   ss->expected_response_code = expected_response_code;
    299   ss->timeout = timeout;
    300   {
    301     struct TALER_TESTING_Command cmd = {
    302       .cls = ss,
    303       .label = label,
    304       .run = &status_run,
    305       .cleanup = &status_cleanup
    306     };
    307 
    308     return cmd;
    309   }
    310 }
    311 
    312 
    313 /**
    314  * Long poller timed out. Fail the test.
    315  *
    316  * @param cls a `struct PollState`
    317  */
    318 static void
    319 finish_timeout (void *cls)
    320 {
    321   struct PollState *ps = cls;
    322 
    323   ps->tt = NULL;
    324   GNUNET_break (0);
    325   TALER_TESTING_interpreter_fail (ps->is);
    326 }
    327 
    328 
    329 /**
    330  * Run the command.
    331  *
    332  * @param cls closure.
    333  * @param cmd the command being executed.
    334  * @param is the interpreter state.
    335  */
    336 static void
    337 finish_run (void *cls,
    338             const struct TALER_TESTING_Command *cmd,
    339             struct TALER_TESTING_Interpreter *is)
    340 {
    341   struct PollState *ps = cls;
    342   const struct TALER_TESTING_Command *poll_reserve;
    343   struct StatusState *ss;
    344 
    345   ps->is = is;
    346   poll_reserve
    347     = TALER_TESTING_interpreter_lookup_command (is,
    348                                                 ps->poll_reference);
    349   GNUNET_assert (NULL != poll_reserve);
    350   GNUNET_assert (poll_reserve->run == &status_run);
    351   ss = poll_reserve->cls;
    352   if (NULL == ss->rsh)
    353   {
    354     TALER_TESTING_interpreter_next (is);
    355     return;
    356   }
    357   GNUNET_assert (NULL == ss->ps);
    358   ss->ps = ps;
    359   ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout,
    360                                          &finish_timeout,
    361                                          ps);
    362 }
    363 
    364 
    365 /**
    366  * Cleanup the state from a "reserve finish" CMD.
    367  *
    368  * @param cls closure.
    369  * @param cmd the command which is being cleaned up.
    370  */
    371 static void
    372 finish_cleanup (void *cls,
    373                 const struct TALER_TESTING_Command *cmd)
    374 {
    375   struct PollState *ps = cls;
    376 
    377   if (NULL != ps->tt)
    378   {
    379     GNUNET_SCHEDULER_cancel (ps->tt);
    380     ps->tt = NULL;
    381   }
    382   GNUNET_free (ps);
    383 }
    384 
    385 
    386 struct TALER_TESTING_Command
    387 TALER_TESTING_cmd_reserve_poll_finish (const char *label,
    388                                        struct GNUNET_TIME_Relative timeout,
    389                                        const char *poll_reference)
    390 {
    391   struct PollState *ps;
    392 
    393   GNUNET_assert (NULL != poll_reference);
    394   ps = GNUNET_new (struct PollState);
    395   ps->timeout = timeout;
    396   ps->poll_reference = poll_reference;
    397   {
    398     struct TALER_TESTING_Command cmd = {
    399       .cls = ps,
    400       .label = label,
    401       .run = &finish_run,
    402       .cleanup = &finish_cleanup
    403     };
    404 
    405     return cmd;
    406   }
    407 }