LCOV - code coverage report
Current view: top level - testing - testing_api_loop.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 169 321 52.6 %
Date: 2022-08-25 06:15:09 Functions: 16 23 69.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2018 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it
       6             :   under the terms of the GNU General Public License as published
       7             :   by the Free Software Foundation; either version 3, or (at your
       8             :   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             : /**
      21             :  * @file testing/testing_api_loop.c
      22             :  * @brief main interpreter loop for testcases
      23             :  * @author Christian Grothoff
      24             :  * @author Marcello Stanisci
      25             :  */
      26             : #include "platform.h"
      27             : #include "taler_json_lib.h"
      28             : #include <gnunet/gnunet_curl_lib.h>
      29             : #include "taler_signatures.h"
      30             : #include "taler_testing_lib.h"
      31             : #include "taler_fakebank_lib.h"
      32             : 
      33             : /**
      34             :  * Pipe used to communicate child death via signal.
      35             :  * Must be global, as used in signal handler!
      36             :  */
      37             : static struct GNUNET_DISK_PipeHandle *sigpipe;
      38             : 
      39             : 
      40             : const struct TALER_TESTING_Command *
      41           2 : TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
      42             :                                           const char *label)
      43             : {
      44           2 :   if (NULL == label)
      45             :   {
      46           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
      47             :                 "Attempt to lookup command for empty label\n");
      48           0 :     return NULL;
      49             :   }
      50             :   /* Search backwards as we most likely reference recent commands */
      51           4 :   for (int i = is->ip; i >= 0; i--)
      52             :   {
      53           4 :     const struct TALER_TESTING_Command *cmd = &is->commands[i];
      54             : 
      55             :     /* Give precedence to top-level commands.  */
      56           4 :     if ( (NULL != cmd->label) &&
      57           4 :          (0 == strcmp (cmd->label,
      58             :                        label)) )
      59           2 :       return cmd;
      60             : 
      61           2 :     if (TALER_TESTING_cmd_is_batch (cmd))
      62             :     {
      63             :       struct TALER_TESTING_Command **batch;
      64             :       struct TALER_TESTING_Command *current;
      65             :       struct TALER_TESTING_Command *icmd;
      66             :       const struct TALER_TESTING_Command *match;
      67             : 
      68           0 :       current = TALER_TESTING_cmd_batch_get_current (cmd);
      69           0 :       GNUNET_assert (GNUNET_OK ==
      70             :                      TALER_TESTING_get_trait_batch_cmds (cmd,
      71             :                                                          &batch));
      72             :       /* We must do the loop forward, but we can find the last match */
      73           0 :       match = NULL;
      74           0 :       for (unsigned int j = 0;
      75           0 :            NULL != (icmd = &(*batch)[j])->label;
      76           0 :            j++)
      77             :       {
      78           0 :         if (current == icmd)
      79           0 :           break; /* do not go past current command */
      80           0 :         if ( (NULL != icmd->label) &&
      81           0 :              (0 == strcmp (icmd->label,
      82             :                            label)) )
      83           0 :           match = icmd;
      84             :       }
      85           0 :       if (NULL != match)
      86           0 :         return match;
      87             :     }
      88             :   }
      89           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
      90             :               "Command not found: %s\n",
      91             :               label);
      92           0 :   return NULL;
      93             : 
      94             : }
      95             : 
      96             : 
      97             : /**
      98             :  * Obtain main execution context for the main loop.
      99             :  */
     100             : struct GNUNET_CURL_Context *
     101          10 : TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is)
     102             : {
     103          10 :   return is->ctx;
     104             : }
     105             : 
     106             : 
     107             : struct TALER_FAKEBANK_Handle *
     108           0 : TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is)
     109             : {
     110           0 :   return is->fakebank;
     111             : }
     112             : 
     113             : 
     114             : void
     115           2 : TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is,
     116             :                                  struct TALER_TESTING_Command *commands,
     117             :                                  const char *bank_url)
     118             : {
     119             :   char *currency;
     120             : 
     121           2 :   if (GNUNET_OK !=
     122           2 :       TALER_config_get_currency (is->cfg,
     123             :                                  &currency))
     124             :   {
     125           0 :     is->result = GNUNET_SYSERR;
     126           0 :     return;
     127             :   }
     128           2 :   is->fakebank = TALER_TESTING_run_fakebank (bank_url,
     129             :                                              currency);
     130           2 :   GNUNET_free (currency);
     131           2 :   if (NULL == is->fakebank)
     132             :   {
     133           0 :     GNUNET_break (0);
     134           0 :     is->result = GNUNET_SYSERR;
     135           0 :     return;
     136             :   }
     137           2 :   TALER_TESTING_run (is,
     138             :                      commands);
     139             : }
     140             : 
     141             : 
     142             : /**
     143             :  * Run the main interpreter loop that performs exchange operations.
     144             :  *
     145             :  * @param cls contains the `struct InterpreterState`
     146             :  */
     147             : static void
     148             : interpreter_run (void *cls);
     149             : 
     150             : 
     151             : void
     152          22 : TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
     153             : {
     154             :   static unsigned long long ipc;
     155             :   static struct GNUNET_TIME_Absolute last_report;
     156          22 :   struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
     157             : 
     158          22 :   if (GNUNET_SYSERR == is->result)
     159           0 :     return; /* ignore, we already failed! */
     160          22 :   if (TALER_TESTING_cmd_is_batch (cmd))
     161             :   {
     162           0 :     TALER_TESTING_cmd_batch_next (is);
     163             :   }
     164             :   else
     165             :   {
     166          22 :     cmd->finish_time = GNUNET_TIME_absolute_get ();
     167          22 :     is->ip++;
     168             :   }
     169          22 :   if (0 == (ipc % 1000))
     170             :   {
     171           3 :     if (0 != ipc)
     172           0 :       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
     173             :                   "Interpreter executed 1000 instructions in %s\n",
     174             :                   GNUNET_STRINGS_relative_time_to_string (
     175             :                     GNUNET_TIME_absolute_get_duration (last_report),
     176             :                     GNUNET_YES));
     177           3 :     last_report = GNUNET_TIME_absolute_get ();
     178             :   }
     179          22 :   ipc++;
     180          22 :   is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
     181             :                                        is);
     182             : }
     183             : 
     184             : 
     185             : void
     186           0 : TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
     187             : {
     188           0 :   struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
     189             : 
     190           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     191             :               "Failed at command `%s'\n",
     192             :               cmd->label);
     193           0 :   while (TALER_TESTING_cmd_is_batch (cmd))
     194             :   {
     195           0 :     cmd = TALER_TESTING_cmd_batch_get_current (cmd);
     196           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     197             :                 "Batch is at command `%s'\n",
     198             :                 cmd->label);
     199             :   }
     200           0 :   is->result = GNUNET_SYSERR;
     201           0 :   GNUNET_SCHEDULER_shutdown ();
     202           0 : }
     203             : 
     204             : 
     205             : struct TALER_TESTING_Command
     206           3 : TALER_TESTING_cmd_end (void)
     207             : {
     208             :   static struct TALER_TESTING_Command cmd;
     209           3 :   cmd.label = NULL;
     210             : 
     211           3 :   return cmd;
     212             : }
     213             : 
     214             : 
     215             : const char *
     216           0 : TALER_TESTING_interpreter_get_current_label (struct
     217             :                                              TALER_TESTING_Interpreter *is)
     218             : {
     219           0 :   struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
     220             : 
     221           0 :   return cmd->label;
     222             : }
     223             : 
     224             : 
     225             : static void
     226          25 : interpreter_run (void *cls)
     227             : {
     228          25 :   struct TALER_TESTING_Interpreter *is = cls;
     229          25 :   struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
     230             : 
     231          25 :   is->task = NULL;
     232          25 :   if (NULL == cmd->label)
     233             :   {
     234             : 
     235           3 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     236             :                 "Running command END\n");
     237           3 :     is->result = GNUNET_OK;
     238           3 :     GNUNET_SCHEDULER_shutdown ();
     239           3 :     return;
     240             :   }
     241             : 
     242          22 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     243             :               "Running command `%s'\n",
     244             :               cmd->label);
     245             :   cmd->start_time
     246          22 :     = cmd->last_req_time
     247          22 :       = GNUNET_TIME_absolute_get ();
     248          22 :   cmd->num_tries = 1;
     249          22 :   cmd->run (cmd->cls,
     250             :             cmd,
     251             :             is);
     252             : }
     253             : 
     254             : 
     255             : /**
     256             :  * Function run when the test terminates (good or bad).
     257             :  * Cleans up our state.
     258             :  *
     259             :  * @param cls the interpreter state.
     260             :  */
     261             : static void
     262           3 : do_shutdown (void *cls)
     263             : {
     264           3 :   struct TALER_TESTING_Interpreter *is = cls;
     265             :   struct TALER_TESTING_Command *cmd;
     266             :   const char *label;
     267             : 
     268           3 :   label = is->commands[is->ip].label;
     269           3 :   if (NULL == label)
     270           3 :     label = "END";
     271           3 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     272             :               "Executing shutdown at `%s'\n",
     273             :               label);
     274           3 :   for (unsigned int j = 0;
     275          25 :        NULL != (cmd = &is->commands[j])->label;
     276          22 :        j++)
     277          22 :     if (NULL != cmd->cleanup)
     278          22 :       cmd->cleanup (cmd->cls,
     279             :                     cmd);
     280           3 :   if (NULL != is->exchange)
     281             :   {
     282           0 :     TALER_LOG_DEBUG ("Disconnecting the exchange\n");
     283           0 :     TALER_EXCHANGE_disconnect (is->exchange);
     284           0 :     is->exchange = NULL;
     285             :   }
     286           3 :   if (NULL != is->task)
     287             :   {
     288           0 :     GNUNET_SCHEDULER_cancel (is->task);
     289           0 :     is->task = NULL;
     290             :   }
     291           3 :   if (NULL != is->fakebank)
     292             :   {
     293           2 :     TALER_FAKEBANK_stop (is->fakebank);
     294           2 :     is->fakebank = NULL;
     295             :   }
     296           3 :   if (NULL != is->ctx)
     297             :   {
     298           3 :     GNUNET_CURL_fini (is->ctx);
     299           3 :     is->ctx = NULL;
     300             :   }
     301           3 :   if (NULL != is->rc)
     302             :   {
     303           3 :     GNUNET_CURL_gnunet_rc_destroy (is->rc);
     304           3 :     is->rc = NULL;
     305             :   }
     306           3 :   if (NULL != is->timeout_task)
     307             :   {
     308           3 :     GNUNET_SCHEDULER_cancel (is->timeout_task);
     309           3 :     is->timeout_task = NULL;
     310             :   }
     311           3 :   if (NULL != is->child_death_task)
     312             :   {
     313           0 :     GNUNET_SCHEDULER_cancel (is->child_death_task);
     314           0 :     is->child_death_task = NULL;
     315             :   }
     316           3 :   GNUNET_free (is->commands);
     317           3 : }
     318             : 
     319             : 
     320             : /**
     321             :  * Function run when the test terminates (good or bad) with timeout.
     322             :  *
     323             :  * @param cls the `struct TALER_TESTING_Interpreter *`
     324             :  */
     325             : static void
     326           0 : do_timeout (void *cls)
     327             : {
     328           0 :   struct TALER_TESTING_Interpreter *is = cls;
     329             : 
     330           0 :   is->timeout_task = NULL;
     331           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     332             :               "Terminating test due to timeout\n");
     333           0 :   GNUNET_SCHEDULER_shutdown ();
     334           0 : }
     335             : 
     336             : 
     337             : /**
     338             :  * Task triggered whenever we receive a SIGCHLD (child
     339             :  * process died).
     340             :  *
     341             :  * @param cls the `struct TALER_TESTING_Interpreter *`
     342             :  */
     343             : static void
     344           1 : maint_child_death (void *cls)
     345             : {
     346           1 :   struct TALER_TESTING_Interpreter *is = cls;
     347           1 :   struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
     348             :   const struct GNUNET_DISK_FileHandle *pr;
     349             :   struct GNUNET_OS_Process **processp;
     350             :   char c[16];
     351             :   enum GNUNET_OS_ProcessStatusType type;
     352             :   unsigned long code;
     353             : 
     354           1 :   while (TALER_TESTING_cmd_is_batch (cmd))
     355           0 :     cmd = TALER_TESTING_cmd_batch_get_current (cmd);
     356           1 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     357             :               "Got SIGCHLD for `%s'.\n",
     358             :               cmd->label);
     359           1 :   is->child_death_task = NULL;
     360           1 :   pr = GNUNET_DISK_pipe_handle (sigpipe,
     361             :                                 GNUNET_DISK_PIPE_END_READ);
     362           1 :   GNUNET_break (0 <
     363             :                 GNUNET_DISK_file_read (pr,
     364             :                                        &c,
     365             :                                        sizeof (c)));
     366           1 :   if (GNUNET_OK !=
     367           1 :       TALER_TESTING_get_trait_process (cmd,
     368             :                                        &processp))
     369             :   {
     370           0 :     GNUNET_break (0);
     371           0 :     TALER_TESTING_interpreter_fail (is);
     372           0 :     return;
     373             :   }
     374             : 
     375           1 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     376             :               "Got the dead child process handle, waiting for termination ...\n");
     377           1 :   GNUNET_assert (GNUNET_OK ==
     378             :                  GNUNET_OS_process_wait_status (*processp,
     379             :                                                 &type,
     380             :                                                 &code));
     381           1 :   GNUNET_OS_process_destroy (*processp);
     382           1 :   *processp = NULL;
     383           1 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     384             :               "... definitively terminated\n");
     385           1 :   switch (type)
     386             :   {
     387           0 :   case GNUNET_OS_PROCESS_UNKNOWN:
     388           0 :     GNUNET_break (0);
     389           0 :     TALER_TESTING_interpreter_fail (is);
     390           0 :     return;
     391           0 :   case GNUNET_OS_PROCESS_RUNNING:
     392           0 :     GNUNET_break (0);
     393           0 :     TALER_TESTING_interpreter_fail (is);
     394           0 :     return;
     395           0 :   case GNUNET_OS_PROCESS_STOPPED:
     396           0 :     GNUNET_break (0);
     397           0 :     TALER_TESTING_interpreter_fail (is);
     398           0 :     return;
     399           1 :   case GNUNET_OS_PROCESS_EXITED:
     400           1 :     if (0 != code)
     401             :     {
     402           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     403             :                   "Process exited with unexpected status %u\n",
     404             :                   (unsigned int) code);
     405           0 :       TALER_TESTING_interpreter_fail (is);
     406           0 :       return;
     407             :     }
     408           1 :     break;
     409           0 :   case GNUNET_OS_PROCESS_SIGNALED:
     410           0 :     GNUNET_break (0);
     411           0 :     TALER_TESTING_interpreter_fail (is);
     412           0 :     return;
     413             :   }
     414             : 
     415           1 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     416             :               "Dead child, go on with next command.\n");
     417           1 :   TALER_TESTING_interpreter_next (is);
     418             : }
     419             : 
     420             : 
     421             : void
     422           1 : TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
     423             : {
     424             :   const struct GNUNET_DISK_FileHandle *pr;
     425             : 
     426           1 :   GNUNET_assert (NULL == is->child_death_task);
     427           1 :   pr = GNUNET_DISK_pipe_handle (sigpipe,
     428             :                                 GNUNET_DISK_PIPE_END_READ);
     429             :   is->child_death_task
     430           1 :     = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
     431             :                                       pr,
     432             :                                       &maint_child_death,
     433             :                                       is);
     434           1 : }
     435             : 
     436             : 
     437             : void
     438           3 : TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
     439             :                     struct TALER_TESTING_Command *commands,
     440             :                     struct GNUNET_TIME_Relative timeout)
     441             : {
     442             :   unsigned int i;
     443             : 
     444           3 :   if (NULL != is->timeout_task)
     445             :   {
     446           0 :     GNUNET_SCHEDULER_cancel (is->timeout_task);
     447           0 :     is->timeout_task = NULL;
     448             :   }
     449             :   /* get the number of commands */
     450          25 :   for (i = 0; NULL != commands[i].label; i++)
     451             :     ;
     452           3 :   is->commands = GNUNET_malloc_large ( (i + 1)
     453             :                                        * sizeof (struct TALER_TESTING_Command));
     454           3 :   GNUNET_assert (NULL != is->commands);
     455           3 :   memcpy (is->commands,
     456             :           commands,
     457             :           sizeof (struct TALER_TESTING_Command) * i);
     458           3 :   is->timeout_task = GNUNET_SCHEDULER_add_delayed (
     459             :     timeout,
     460             :     &do_timeout,
     461             :     is);
     462           3 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
     463             :                                  is);
     464           3 :   is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
     465             :                                        is);
     466           3 : }
     467             : 
     468             : 
     469             : void
     470           3 : TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
     471             :                    struct TALER_TESTING_Command *commands)
     472             : {
     473           3 :   TALER_TESTING_run2 (is,
     474             :                       commands,
     475             :                       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
     476             :                                                      5));
     477           3 : }
     478             : 
     479             : 
     480             : /**
     481             :  * Information used by the wrapper around the main
     482             :  * "run" method.
     483             :  */
     484             : struct MainContext
     485             : {
     486             :   /**
     487             :    * Main "run" method.
     488             :    */
     489             :   TALER_TESTING_Main main_cb;
     490             : 
     491             :   /**
     492             :    * Closure for @e main_cb.
     493             :    */
     494             :   void *main_cb_cls;
     495             : 
     496             :   /**
     497             :    * Interpreter state.
     498             :    */
     499             :   struct TALER_TESTING_Interpreter *is;
     500             : 
     501             :   /**
     502             :    * URL of the exchange.
     503             :    */
     504             :   char *exchange_url;
     505             : 
     506             : };
     507             : 
     508             : 
     509             : /**
     510             :  * Signal handler called for SIGCHLD.  Triggers the
     511             :  * respective handler by writing to the trigger pipe.
     512             :  */
     513             : static void
     514           1 : sighandler_child_death (void)
     515             : {
     516             :   static char c;
     517           1 :   int old_errno = errno;  /* back-up errno */
     518             : 
     519           1 :   GNUNET_break (1 == GNUNET_DISK_file_write
     520             :                   (GNUNET_DISK_pipe_handle (sigpipe,
     521             :                                             GNUNET_DISK_PIPE_END_WRITE),
     522             :                   &c, sizeof (c)));
     523           1 :   errno = old_errno;    /* restore errno */
     524           1 : }
     525             : 
     526             : 
     527             : void
     528           0 : TALER_TESTING_cert_cb (void *cls,
     529             :                        const struct TALER_EXCHANGE_HttpResponse *hr,
     530             :                        const struct TALER_EXCHANGE_Keys *keys,
     531             :                        enum TALER_EXCHANGE_VersionCompatibility compat)
     532             : {
     533           0 :   struct MainContext *main_ctx = cls;
     534           0 :   struct TALER_TESTING_Interpreter *is = main_ctx->is;
     535             : 
     536             :   (void) compat;
     537           0 :   if (NULL == keys)
     538             :   {
     539           0 :     if (GNUNET_NO == is->working)
     540             :     {
     541           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     542             :                   "Got NULL response for /keys during startup (%u/%d), retrying!\n",
     543             :                   hr->http_status,
     544             :                   (int) hr->ec);
     545           0 :       TALER_EXCHANGE_disconnect (is->exchange);
     546           0 :       GNUNET_assert (
     547             :         NULL != (is->exchange
     548             :                    = TALER_EXCHANGE_connect (is->ctx,
     549             :                                              main_ctx->exchange_url,
     550             :                                              &TALER_TESTING_cert_cb,
     551             :                                              main_ctx,
     552             :                                              TALER_EXCHANGE_OPTION_END)));
     553           0 :       return;
     554             :     }
     555             :     else
     556             :     {
     557           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     558             :                   "Got NULL response for /keys during execution (%u/%d)!\n",
     559             :                   hr->http_status,
     560             :                   (int) hr->ec);
     561             :     }
     562             :   }
     563             :   else
     564             :   {
     565           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     566             :                 "Got %d DK from /keys in generation %u\n",
     567             :                 keys->num_denom_keys,
     568             :                 is->key_generation + 1);
     569             :   }
     570           0 :   is->key_generation++;
     571           0 :   is->keys = keys;
     572             : 
     573             :   /* /keys has been called for some reason and
     574             :    * the interpreter is already running. */
     575           0 :   if (GNUNET_YES == is->working)
     576           0 :     return;
     577           0 :   is->working = GNUNET_YES;
     578             :   /* Trigger the next command. */
     579           0 :   TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n",
     580             :                    is->ip);
     581           0 :   GNUNET_SCHEDULER_add_now (&interpreter_run,
     582             :                             is);
     583             : }
     584             : 
     585             : 
     586             : /**
     587             :  * Initialize scheduler loop and curl context for the testcase,
     588             :  * and responsible to run the "run" method.
     589             :  *
     590             :  * @param cls closure, typically the "run" method, the
     591             :  *        interpreter state and a closure for "run".
     592             :  */
     593             : static void
     594           3 : main_wrapper_exchange_agnostic (void *cls)
     595             : {
     596           3 :   struct MainContext *main_ctx = cls;
     597             : 
     598           3 :   main_ctx->main_cb (main_ctx->main_cb_cls,
     599             :                      main_ctx->is);
     600           3 : }
     601             : 
     602             : 
     603             : /**
     604             :  * Function run when the test is aborted before we launch the actual
     605             :  * interpreter.  Cleans up our state.
     606             :  *
     607             :  * @param cls the main context
     608             :  */
     609             : static void
     610           0 : do_abort (void *cls)
     611             : {
     612           0 :   struct MainContext *main_ctx = cls;
     613           0 :   struct TALER_TESTING_Interpreter *is = main_ctx->is;
     614             : 
     615           0 :   is->timeout_task = NULL;
     616           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     617             :               "Executing abort prior to interpreter launch\n");
     618           0 :   if (NULL != is->exchange)
     619             :   {
     620           0 :     TALER_EXCHANGE_disconnect (is->exchange);
     621           0 :     is->exchange = NULL;
     622             :   }
     623           0 :   if (NULL != is->fakebank)
     624             :   {
     625           0 :     TALER_FAKEBANK_stop (is->fakebank);
     626           0 :     is->fakebank = NULL;
     627             :   }
     628           0 :   if (NULL != is->ctx)
     629             :   {
     630           0 :     GNUNET_CURL_fini (is->ctx);
     631           0 :     is->ctx = NULL;
     632             :   }
     633           0 :   if (NULL != is->rc)
     634             :   {
     635           0 :     GNUNET_CURL_gnunet_rc_destroy (is->rc);
     636           0 :     is->rc = NULL;
     637             :   }
     638           0 : }
     639             : 
     640             : 
     641             : /**
     642             :  * Initialize scheduler loop and curl context for the testcase,
     643             :  * and responsible to run the "run" method.
     644             :  *
     645             :  * @param cls a `struct MainContext *`
     646             :  */
     647             : static void
     648           0 : main_wrapper_exchange_connect (void *cls)
     649             : {
     650           0 :   struct MainContext *main_ctx = cls;
     651           0 :   struct TALER_TESTING_Interpreter *is = main_ctx->is;
     652             :   char *exchange_url;
     653             : 
     654           0 :   if (GNUNET_OK !=
     655           0 :       GNUNET_CONFIGURATION_get_value_string (is->cfg,
     656             :                                              "exchange",
     657             :                                              "BASE_URL",
     658             :                                              &exchange_url))
     659             :   {
     660           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     661             :                                "exchange",
     662             :                                "BASE_URL");
     663           0 :     return;
     664             :   }
     665           0 :   main_ctx->exchange_url = exchange_url;
     666           0 :   is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
     667             :                                                     main_ctx);
     668           0 :   is->working = GNUNET_YES;
     669           0 :   GNUNET_assert (NULL == is->exchange);
     670           0 :   GNUNET_break (
     671             :     NULL != (is->exchange =
     672             :                TALER_EXCHANGE_connect (is->ctx,
     673             :                                        exchange_url,
     674             :                                        &TALER_TESTING_cert_cb,
     675             :                                        main_ctx,
     676             :                                        TALER_EXCHANGE_OPTION_END)));
     677           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     678             :               "Starting main test loop\n");
     679           0 :   main_ctx->main_cb (main_ctx->main_cb_cls,
     680             :                      is);
     681             : }
     682             : 
     683             : 
     684             : /**
     685             :  * Load the exchange and auditor key material into @a is.
     686             :  *
     687             :  * @param[in,out] is state to initialize
     688             :  */
     689             : static enum GNUNET_GenericReturnValue
     690           3 : load_keys (struct TALER_TESTING_Interpreter *is)
     691             : {
     692             :   char *fn;
     693             : 
     694           3 :   if (GNUNET_OK !=
     695           3 :       GNUNET_CONFIGURATION_get_value_filename (is->cfg,
     696             :                                                "exchange-offline",
     697             :                                                "MASTER_PRIV_FILE",
     698             :                                                &fn))
     699             :   {
     700           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     701             :                                "exchange-offline",
     702             :                                "MASTER_PRIV_FILE");
     703           0 :     return GNUNET_SYSERR;
     704             :   }
     705           3 :   if (GNUNET_SYSERR ==
     706           3 :       GNUNET_DISK_directory_create_for_file (fn))
     707             :   {
     708           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     709             :                 "Could not setup directory for master private key file `%s'\n",
     710             :                 fn);
     711           0 :     GNUNET_free (fn);
     712           0 :     return GNUNET_SYSERR;
     713             :   }
     714           3 :   if (GNUNET_SYSERR ==
     715           3 :       GNUNET_CRYPTO_eddsa_key_from_file (fn,
     716             :                                          GNUNET_YES,
     717             :                                          &is->master_priv.eddsa_priv))
     718             :   {
     719           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     720             :                 "Could not load master private key from `%s'\n",
     721             :                 fn);
     722           0 :     GNUNET_free (fn);
     723           0 :     return GNUNET_SYSERR;
     724             :   }
     725           3 :   GNUNET_free (fn);
     726           3 :   GNUNET_CRYPTO_eddsa_key_get_public (&is->master_priv.eddsa_priv,
     727             :                                       &is->master_pub.eddsa_pub);
     728             : 
     729           3 :   if (GNUNET_OK !=
     730           3 :       GNUNET_CONFIGURATION_get_value_filename (is->cfg,
     731             :                                                "auditor",
     732             :                                                "AUDITOR_PRIV_FILE",
     733             :                                                &fn))
     734             :   {
     735           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     736             :                                "auditor",
     737             :                                "AUDITOR_PRIV_FILE");
     738           0 :     return GNUNET_SYSERR;
     739             :   }
     740           3 :   if (GNUNET_SYSERR ==
     741           3 :       GNUNET_DISK_directory_create_for_file (fn))
     742             :   {
     743           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     744             :                 "Could not setup directory for auditor private key file `%s'\n",
     745             :                 fn);
     746           0 :     GNUNET_free (fn);
     747           0 :     return GNUNET_SYSERR;
     748             :   }
     749           3 :   if (GNUNET_SYSERR ==
     750           3 :       GNUNET_CRYPTO_eddsa_key_from_file (fn,
     751             :                                          GNUNET_YES,
     752             :                                          &is->auditor_priv.eddsa_priv))
     753             :   {
     754           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     755             :                 "Could not load auditor private key from `%s'\n",
     756             :                 fn);
     757           0 :     GNUNET_free (fn);
     758           0 :     return GNUNET_SYSERR;
     759             :   }
     760           3 :   GNUNET_free (fn);
     761           3 :   GNUNET_CRYPTO_eddsa_key_get_public (&is->auditor_priv.eddsa_priv,
     762             :                                       &is->auditor_pub.eddsa_pub);
     763           3 :   return GNUNET_OK;
     764             : }
     765             : 
     766             : 
     767             : /**
     768             :  * Load the exchange and auditor URLs from the configuration into @a is.
     769             :  *
     770             :  * @param[in,out] is state to initialize
     771             :  */
     772             : static enum GNUNET_GenericReturnValue
     773           3 : load_urls (struct TALER_TESTING_Interpreter *is)
     774             : {
     775           3 :   if (GNUNET_OK !=
     776           3 :       GNUNET_CONFIGURATION_get_value_string (is->cfg,
     777             :                                              "auditor",
     778             :                                              "BASE_URL",
     779             :                                              &is->auditor_url))
     780             :   {
     781           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     782             :                                "auditor",
     783             :                                "BASE_URL");
     784           0 :     return GNUNET_SYSERR;
     785             :   }
     786           3 :   if (GNUNET_OK !=
     787           3 :       GNUNET_CONFIGURATION_get_value_string (is->cfg,
     788             :                                              "exchange",
     789             :                                              "BASE_URL",
     790             :                                              &is->exchange_url))
     791             :   {
     792           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     793             :                                "exchange",
     794             :                                "BASE_URL");
     795           0 :     GNUNET_free (is->auditor_url);
     796           0 :     return GNUNET_SYSERR;
     797             :   }
     798           3 :   return GNUNET_OK;
     799             : }
     800             : 
     801             : 
     802             : enum GNUNET_GenericReturnValue
     803           3 : TALER_TESTING_setup (TALER_TESTING_Main main_cb,
     804             :                      void *main_cb_cls,
     805             :                      const struct GNUNET_CONFIGURATION_Handle *cfg,
     806             :                      struct GNUNET_OS_Process *exchanged,
     807             :                      int exchange_connect)
     808             : {
     809           3 :   struct TALER_TESTING_Interpreter is = {
     810             :     .cfg = cfg,
     811             :     .exchanged = exchanged
     812             :   };
     813           3 :   struct MainContext main_ctx = {
     814             :     .main_cb = main_cb,
     815             :     .main_cb_cls = main_cb_cls,
     816             :     /* needed to init the curl ctx */
     817             :     .is = &is,
     818             :   };
     819             :   struct GNUNET_SIGNAL_Context *shc_chld;
     820             : 
     821           3 :   if (GNUNET_OK !=
     822           3 :       load_keys (&is))
     823           0 :     return GNUNET_SYSERR;
     824           3 :   if (GNUNET_OK !=
     825           3 :       load_urls (&is))
     826           0 :     return GNUNET_SYSERR;
     827           3 :   sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
     828           3 :   GNUNET_assert (NULL != sigpipe);
     829           3 :   shc_chld = GNUNET_SIGNAL_handler_install (
     830             :     GNUNET_SIGCHLD,
     831             :     &sighandler_child_death);
     832           3 :   is.ctx = GNUNET_CURL_init (
     833             :     &GNUNET_CURL_gnunet_scheduler_reschedule,
     834             :     &is.rc);
     835           3 :   GNUNET_CURL_enable_async_scope_header (is.ctx,
     836             :                                          "Taler-Correlation-Id");
     837           3 :   GNUNET_assert (NULL != is.ctx);
     838           3 :   is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
     839             : 
     840             :   /* Blocking */
     841           3 :   if (GNUNET_YES == exchange_connect)
     842           0 :     GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect,
     843             :                           &main_ctx);
     844             :   else
     845           3 :     GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic,
     846             :                           &main_ctx);
     847           3 :   if (NULL != is.final_cleanup_cb)
     848           0 :     is.final_cleanup_cb (is.final_cleanup_cb_cls);
     849           3 :   GNUNET_free (main_ctx.exchange_url);
     850           3 :   GNUNET_SIGNAL_handler_uninstall (shc_chld);
     851           3 :   GNUNET_DISK_pipe_close (sigpipe);
     852           3 :   sigpipe = NULL;
     853           3 :   GNUNET_free (is.auditor_url);
     854           3 :   GNUNET_free (is.exchange_url);
     855           3 :   return is.result;
     856             : }
     857             : 
     858             : 
     859             : /* end of testing_api_loop.c */

Generated by: LCOV version 1.14