LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_purse_get.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 71.1 % 97 69
Test Date: 2026-09-11 18:55:36 Functions: 87.5 % 8 7

            Line data    Source code
       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           10 : purse_status_cb (struct StatusState *ss,
     125              :                  const struct TALER_EXCHANGE_GetPursesResponse *rs)
     126              : {
     127           10 :   struct TALER_TESTING_Interpreter *is = ss->is;
     128              : 
     129           10 :   ss->pgh = NULL;
     130           10 :   if (ss->expected_response_code != rs->hr.http_status)
     131              :   {
     132            0 :     TALER_TESTING_unexpected_status (is,
     133              :                                      rs->hr.http_status,
     134              :                                      ss->expected_response_code);
     135            0 :     return;
     136              :   }
     137           10 :   if (MHD_HTTP_OK == ss->expected_response_code)
     138              :   {
     139              :     struct TALER_Amount eb;
     140              : 
     141            6 :     GNUNET_assert (GNUNET_OK ==
     142              :                    TALER_string_to_amount (ss->expected_balance,
     143              :                                            &eb));
     144            6 :     if (0 != TALER_amount_cmp (&eb,
     145              :                                &rs->details.ok.balance))
     146              :     {
     147            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     148              :                   "Unexpected amount in purse: %s\n",
     149              :                   TALER_amount_to_string (&rs->details.ok.balance));
     150            0 :       TALER_TESTING_interpreter_fail (ss->is);
     151            0 :       return;
     152              :     }
     153              :   }
     154           10 :   if (NULL != ss->ps)
     155              :   {
     156              :     /* force continuation on long poller */
     157            8 :     GNUNET_SCHEDULER_cancel (ss->ps->tt);
     158            8 :     ss->ps->tt = NULL;
     159            8 :     TALER_TESTING_interpreter_next (is);
     160            8 :     return;
     161              :   }
     162            2 :   if (GNUNET_TIME_relative_is_zero (ss->timeout))
     163            0 :     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           10 : status_run (void *cls,
     176              :             const struct TALER_TESTING_Command *cmd,
     177              :             struct TALER_TESTING_Interpreter *is)
     178              : {
     179           10 :   struct StatusState *ss = cls;
     180              :   const struct TALER_TESTING_Command *create_purse;
     181              : 
     182           10 :   ss->is = is;
     183              :   create_purse
     184           10 :     = TALER_TESTING_interpreter_lookup_command (is,
     185              :                                                 ss->purse_reference);
     186           10 :   GNUNET_assert (NULL != create_purse);
     187           10 :   if (GNUNET_OK !=
     188           10 :       TALER_TESTING_get_trait_purse_pub (create_purse,
     189              :                                          &ss->purse_pub))
     190              :   {
     191            0 :     GNUNET_break (0);
     192            0 :     TALER_LOG_ERROR ("Failed to find purse_pub for status query\n");
     193            0 :     TALER_TESTING_interpreter_fail (is);
     194           10 :     return;
     195              :   }
     196           10 :   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           10 :   if (NULL == ss->pgh)
     202              :   {
     203            0 :     GNUNET_break (0);
     204            0 :     TALER_TESTING_interpreter_fail (is);
     205            0 :     return;
     206              :   }
     207           10 :   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           10 :   if (TALER_EC_NONE !=
     212           10 :       TALER_EXCHANGE_get_purses_start (ss->pgh,
     213              :                                        &purse_status_cb,
     214              :                                        ss))
     215              :   {
     216            0 :     GNUNET_break (0);
     217            0 :     TALER_EXCHANGE_get_purses_cancel (ss->pgh);
     218            0 :     ss->pgh = NULL;
     219            0 :     TALER_TESTING_interpreter_fail (is);
     220            0 :     return;
     221              :   }
     222           10 :   if (! GNUNET_TIME_relative_is_zero (ss->timeout))
     223              :   {
     224           10 :     TALER_TESTING_interpreter_next (is);
     225           10 :     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           10 : status_cleanup (void *cls,
     239              :                 const struct TALER_TESTING_Command *cmd)
     240              : {
     241           10 :   struct StatusState *ss = cls;
     242              : 
     243           10 :   if (NULL != ss->pgh)
     244              :   {
     245            0 :     TALER_TESTING_command_incomplete (ss->is,
     246              :                                       cmd->label);
     247            0 :     TALER_EXCHANGE_get_purses_cancel (ss->pgh);
     248            0 :     ss->pgh = NULL;
     249              :   }
     250           10 :   GNUNET_free (ss);
     251           10 : }
     252              : 
     253              : 
     254              : struct TALER_TESTING_Command
     255           10 : 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           10 :   GNUNET_assert (NULL != purse_ref);
     266           10 :   ss = GNUNET_new (struct StatusState);
     267           10 :   ss->purse_reference = purse_ref;
     268           10 :   ss->expected_balance = expected_balance;
     269           10 :   ss->expected_response_code = expected_http_status;
     270           10 :   ss->timeout = timeout;
     271           10 :   ss->wait_for_merge = wait_for_merge;
     272              :   {
     273           10 :     struct TALER_TESTING_Command cmd = {
     274              :       .cls = ss,
     275              :       .label = label,
     276              :       .run = &status_run,
     277              :       .cleanup = &status_cleanup
     278              :     };
     279              : 
     280           10 :     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            0 : finish_timeout (void *cls)
     292              : {
     293            0 :   struct PollState *ps = cls;
     294              : 
     295            0 :   ps->tt = NULL;
     296            0 :   GNUNET_break (0);
     297            0 :   TALER_TESTING_interpreter_fail (ps->is);
     298            0 : }
     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           10 : finish_run (void *cls,
     310              :             const struct TALER_TESTING_Command *cmd,
     311              :             struct TALER_TESTING_Interpreter *is)
     312              : {
     313           10 :   struct PollState *ps = cls;
     314              :   const struct TALER_TESTING_Command *poll_purse;
     315              :   struct StatusState *ss;
     316              : 
     317           10 :   ps->is = is;
     318              :   poll_purse
     319           10 :     = TALER_TESTING_interpreter_lookup_command (is,
     320              :                                                 ps->poll_reference);
     321           10 :   GNUNET_assert (NULL != poll_purse);
     322           10 :   GNUNET_assert (poll_purse->run == &status_run);
     323           10 :   ss = poll_purse->cls;
     324           10 :   if (NULL == ss->pgh)
     325              :   {
     326            2 :     TALER_TESTING_interpreter_next (is);
     327            2 :     return;
     328              :   }
     329            8 :   GNUNET_assert (NULL == ss->ps);
     330            8 :   ss->ps = ps;
     331            8 :   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           10 : finish_cleanup (void *cls,
     345              :                 const struct TALER_TESTING_Command *cmd)
     346              : {
     347           10 :   struct PollState *ps = cls;
     348              : 
     349           10 :   if (NULL != ps->tt)
     350              :   {
     351            0 :     GNUNET_SCHEDULER_cancel (ps->tt);
     352            0 :     ps->tt = NULL;
     353              :   }
     354           10 :   GNUNET_free (ps);
     355           10 : }
     356              : 
     357              : 
     358              : struct TALER_TESTING_Command
     359           10 : 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           10 :   GNUNET_assert (NULL != poll_reference);
     366           10 :   ps = GNUNET_new (struct PollState);
     367           10 :   ps->timeout = timeout;
     368           10 :   ps->poll_reference = poll_reference;
     369              :   {
     370           10 :     struct TALER_TESTING_Command cmd = {
     371              :       .cls = ps,
     372              :       .label = label,
     373              :       .run = &finish_run,
     374              :       .cleanup = &finish_cleanup
     375              :     };
     376              : 
     377           10 :     return cmd;
     378              :   }
     379              : }
        

Generated by: LCOV version 2.0-1