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 (9985B)


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