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

Generated by: LCOV version 2.0-1