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


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