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_purse_get.c (9028B)


      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_purse_get.c
     21  * @brief Implement the GET /purse/$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_PURSES_RESULT_CLOSURE struct StatusState
     28 #include "taler/exchange/get-purses-PURSE_PUB-merge.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 purse to check,
     45    * needed to resort the purse 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 purse to check,
     79    * needed to resort the purse key.
     80    */
     81   const char *purse_reference;
     82 
     83   /**
     84    * Handle to the "purse status" operation.
     85    */
     86   struct TALER_EXCHANGE_GetPursesHandle *pgh;
     87 
     88   /**
     89    * Expected purse balance.
     90    */
     91   const char *expected_balance;
     92 
     93   /**
     94    * Public key of the purse being analyzed.
     95    */
     96   const struct TALER_PurseContractPublicKeyP *purse_pub;
     97 
     98   /**
     99    * Interpreter state.
    100    */
    101   struct TALER_TESTING_Interpreter *is;
    102 
    103   /**
    104    * Expected HTTP response code.
    105    */
    106   unsigned int expected_response_code;
    107 
    108   /**
    109    * Are we waiting for a merge or a deposit?
    110    */
    111   bool wait_for_merge;
    112 
    113 };
    114 
    115 
    116 /**
    117  * Check that the purse balance and HTTP response code are
    118  * both acceptable.
    119  *
    120  * @param ss closure.
    121  * @param rs HTTP response details
    122  */
    123 static void
    124 purse_status_cb (struct StatusState *ss,
    125                  const struct TALER_EXCHANGE_GetPursesResponse *rs)
    126 {
    127   struct TALER_TESTING_Interpreter *is = ss->is;
    128 
    129   ss->pgh = NULL;
    130   if (ss->expected_response_code != rs->hr.http_status)
    131   {
    132     TALER_TESTING_unexpected_status (is,
    133                                      rs->hr.http_status,
    134                                      ss->expected_response_code);
    135     return;
    136   }
    137   if (MHD_HTTP_OK == ss->expected_response_code)
    138   {
    139     struct TALER_Amount eb;
    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 in purse: %s\n",
    149                   TALER_amount_to_string (&rs->details.ok.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_purse;
    181 
    182   ss->is = is;
    183   create_purse
    184     = TALER_TESTING_interpreter_lookup_command (is,
    185                                                 ss->purse_reference);
    186   GNUNET_assert (NULL != create_purse);
    187   if (GNUNET_OK !=
    188       TALER_TESTING_get_trait_purse_pub (create_purse,
    189                                          &ss->purse_pub))
    190   {
    191     GNUNET_break (0);
    192     TALER_LOG_ERROR ("Failed to find purse_pub for status query\n");
    193     TALER_TESTING_interpreter_fail (is);
    194     return;
    195   }
    196   ss->pgh = TALER_EXCHANGE_get_purses_create (
    197     TALER_TESTING_interpreter_get_context (is),
    198     TALER_TESTING_get_exchange_url (is),
    199     TALER_TESTING_get_keys (is),
    200     ss->purse_pub);
    201   if (NULL == ss->pgh)
    202   {
    203     GNUNET_break (0);
    204     TALER_TESTING_interpreter_fail (is);
    205     return;
    206   }
    207   TALER_EXCHANGE_get_purses_set_options (
    208     ss->pgh,
    209     TALER_EXCHANGE_get_purses_option_timeout (ss->timeout),
    210     TALER_EXCHANGE_get_purses_option_wait_for_merge (ss->wait_for_merge));
    211   if (TALER_EC_NONE !=
    212       TALER_EXCHANGE_get_purses_start (ss->pgh,
    213                                        &purse_status_cb,
    214                                        ss))
    215   {
    216     GNUNET_break (0);
    217     TALER_EXCHANGE_get_purses_cancel (ss->pgh);
    218     ss->pgh = NULL;
    219     TALER_TESTING_interpreter_fail (is);
    220     return;
    221   }
    222   if (! GNUNET_TIME_relative_is_zero (ss->timeout))
    223   {
    224     TALER_TESTING_interpreter_next (is);
    225     return;
    226   }
    227 }
    228 
    229 
    230 /**
    231  * Cleanup the state from a "purse status" CMD, and possibly
    232  * cancel a pending operation thereof.
    233  *
    234  * @param cls closure.
    235  * @param cmd the command which is being cleaned up.
    236  */
    237 static void
    238 status_cleanup (void *cls,
    239                 const struct TALER_TESTING_Command *cmd)
    240 {
    241   struct StatusState *ss = cls;
    242 
    243   if (NULL != ss->pgh)
    244   {
    245     TALER_TESTING_command_incomplete (ss->is,
    246                                       cmd->label);
    247     TALER_EXCHANGE_get_purses_cancel (ss->pgh);
    248     ss->pgh = NULL;
    249   }
    250   GNUNET_free (ss);
    251 }
    252 
    253 
    254 struct TALER_TESTING_Command
    255 TALER_TESTING_cmd_purse_poll (
    256   const char *label,
    257   unsigned int expected_http_status,
    258   const char *purse_ref,
    259   const char *expected_balance,
    260   bool wait_for_merge,
    261   struct GNUNET_TIME_Relative timeout)
    262 {
    263   struct StatusState *ss;
    264 
    265   GNUNET_assert (NULL != purse_ref);
    266   ss = GNUNET_new (struct StatusState);
    267   ss->purse_reference = purse_ref;
    268   ss->expected_balance = expected_balance;
    269   ss->expected_response_code = expected_http_status;
    270   ss->timeout = timeout;
    271   ss->wait_for_merge = wait_for_merge;
    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 /**
    286  * Long poller timed out. Fail the test.
    287  *
    288  * @param cls a `struct PollState`
    289  */
    290 static void
    291 finish_timeout (void *cls)
    292 {
    293   struct PollState *ps = cls;
    294 
    295   ps->tt = NULL;
    296   GNUNET_break (0);
    297   TALER_TESTING_interpreter_fail (ps->is);
    298 }
    299 
    300 
    301 /**
    302  * Run the command.
    303  *
    304  * @param cls closure.
    305  * @param cmd the command being executed.
    306  * @param is the interpreter state.
    307  */
    308 static void
    309 finish_run (void *cls,
    310             const struct TALER_TESTING_Command *cmd,
    311             struct TALER_TESTING_Interpreter *is)
    312 {
    313   struct PollState *ps = cls;
    314   const struct TALER_TESTING_Command *poll_purse;
    315   struct StatusState *ss;
    316 
    317   ps->is = is;
    318   poll_purse
    319     = TALER_TESTING_interpreter_lookup_command (is,
    320                                                 ps->poll_reference);
    321   GNUNET_assert (NULL != poll_purse);
    322   GNUNET_assert (poll_purse->run == &status_run);
    323   ss = poll_purse->cls;
    324   if (NULL == ss->pgh)
    325   {
    326     TALER_TESTING_interpreter_next (is);
    327     return;
    328   }
    329   GNUNET_assert (NULL == ss->ps);
    330   ss->ps = ps;
    331   ps->tt = GNUNET_SCHEDULER_add_delayed (ps->timeout,
    332                                          &finish_timeout,
    333                                          ps);
    334 }
    335 
    336 
    337 /**
    338  * Cleanup the state from a "purse finish" CMD.
    339  *
    340  * @param cls closure.
    341  * @param cmd the command which is being cleaned up.
    342  */
    343 static void
    344 finish_cleanup (void *cls,
    345                 const struct TALER_TESTING_Command *cmd)
    346 {
    347   struct PollState *ps = cls;
    348 
    349   if (NULL != ps->tt)
    350   {
    351     GNUNET_SCHEDULER_cancel (ps->tt);
    352     ps->tt = NULL;
    353   }
    354   GNUNET_free (ps);
    355 }
    356 
    357 
    358 struct TALER_TESTING_Command
    359 TALER_TESTING_cmd_purse_poll_finish (const char *label,
    360                                      struct GNUNET_TIME_Relative timeout,
    361                                      const char *poll_reference)
    362 {
    363   struct PollState *ps;
    364 
    365   GNUNET_assert (NULL != poll_reference);
    366   ps = GNUNET_new (struct PollState);
    367   ps->timeout = timeout;
    368   ps->poll_reference = poll_reference;
    369   {
    370     struct TALER_TESTING_Command cmd = {
    371       .cls = ps,
    372       .label = label,
    373       .run = &finish_run,
    374       .cleanup = &finish_cleanup
    375     };
    376 
    377     return cmd;
    378   }
    379 }