LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_purse_get.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 66 87 75.9 %
Date: 2025-06-05 21:03:14 Functions: 7 8 87.5 %

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

Generated by: LCOV version 1.16