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

Generated by: LCOV version 1.14