GNUnet  0.11.x
testing_api_loop.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2021 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet 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 GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_testing_ng_lib.h"
31 #include "testing.h"
32 
38 {
39 
44 
48  void *rc_cls;
49 
54 
59 
64 
69 
75  int ip;
76 
81 
82 };
83 
84 
85 const struct GNUNET_TESTING_Command *
88  const char *label)
89 {
90  if (NULL == label)
91  {
93  "Attempt to lookup command for empty label\n");
94  return NULL;
95  }
96  /* Search backwards as we most likely reference recent commands */
97  for (int i = is->ip; i >= 0; i--)
98  {
99  const struct GNUNET_TESTING_Command *cmd = &is->commands[i];
100 
101  /* Give precedence to top-level commands. */
102  if ( (NULL != cmd->label) &&
103  (0 == strcmp (cmd->label,
104  label)) )
105  return cmd;
106 
108  {
109 #define BATCH_INDEX 1
110  struct GNUNET_TESTING_Command *batch;
111  struct GNUNET_TESTING_Command *current;
112  struct GNUNET_TESTING_Command *icmd;
113  const struct GNUNET_TESTING_Command *match;
114 
118  BATCH_INDEX,
119  &batch));
120  /* We must do the loop forward, but we can find the last match */
121  match = NULL;
122  for (unsigned int j = 0;
123  NULL != (icmd = &batch[j])->label;
124  j++)
125  {
126  if (current == icmd)
127  break; /* do not go past current command */
128  if ( (NULL != icmd->label) &&
129  (0 == strcmp (icmd->label,
130  label)) )
131  match = icmd;
132  }
133  if (NULL != match)
134  return match;
135  }
136  }
138  "Command `%s' not found\n",
139  label);
140  return NULL;
141 }
142 
143 
149 static void
151 {
152  struct GNUNET_TESTING_Interpreter *is = cls;
153  struct GNUNET_TESTING_Command *cmd;
154  const char *label;
155 
156  is->final_task = NULL;
157  label = is->commands[is->ip].label;
158  if (NULL == label)
159  label = "END";
161  "Interpreter finishes at `%s' with status %d\n",
162  label,
163  is->result);
164  for (unsigned int j = 0;
165  NULL != (cmd = &is->commands[j])->label;
166  j++)
167  {
169  "Cleaning up cmd %s\n",
170  cmd->label);
171  cmd->cleanup (cmd->cls);
173  "Cleaned up cmd %s\n",
174  cmd->label);
175  }
176  if (NULL != is->task)
177  {
178  GNUNET_SCHEDULER_cancel (is->task);
179  is->task = NULL;
180  }
181  if (NULL != is->timeout_task)
182  {
183  GNUNET_SCHEDULER_cancel (is->timeout_task);
184  is->timeout_task = NULL;
185  }
186  GNUNET_free (is->commands);
187  is->rc (is->rc_cls,
188  is->result);
189  GNUNET_free (is);
190 }
191 
192 
198 static void
199 interpreter_run (void *cls);
200 
201 
205 static void
207 {
208  struct GNUNET_TESTING_Interpreter *is = cls;
209  static unsigned long long ipc;
210  static struct GNUNET_TIME_Absolute last_report;
211  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
212 
213  if (GNUNET_SYSERR == is->result)
214  return; /* ignore, we already failed! */
216  if ( (! GNUNET_TESTING_cmd_is_batch_ (cmd)) ||
218  is->ip++;
219  if (0 == (ipc % 1000))
220  {
221  if (0 != ipc)
223  "Interpreter executed 1000 instructions in %s\n",
225  GNUNET_TIME_absolute_get_duration (last_report),
226  GNUNET_YES));
227  last_report = GNUNET_TIME_absolute_get ();
228  }
229  ipc++;
231  is);
232 }
233 
234 
235 void
237 {
238  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
239 
240  if (GNUNET_SYSERR == is->result)
241  {
242  GNUNET_break (0);
243  return; /* ignore, we already failed! */
244  }
245  if (NULL != cmd)
246  {
248  "Failed at command `%s'\n",
249  cmd->label);
250  while (GNUNET_TESTING_cmd_is_batch_ (cmd))
251  {
254  "Failed in batch at command `%s'\n",
255  cmd->label);
256  }
257  }
258  else
259  {
261  "Failed with CMD being NULL!\n");
262  }
263  is->result = GNUNET_SYSERR;
264  GNUNET_assert (NULL == is->final_task);
265  is->final_task = GNUNET_SCHEDULER_add_now (&finish_test,
266  is);
267 }
268 
269 
270 const char *
273 {
274  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
275 
276  return cmd->label;
277 }
278 
279 
285 static void
287 {
288  struct GNUNET_TESTING_Interpreter *is = cls;
289  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
290 
291  is->task = NULL;
292  if (NULL == cmd->label)
293  {
295  "Running command END\n");
296  is->result = GNUNET_OK;
297  finish_test (is);
298  return;
299  }
301  "Running command `%s'\n",
302  cmd->label);
303  cmd->start_time
304  = cmd->last_req_time
306  cmd->num_tries = 1;
307  if (NULL != cmd->ac)
308  {
309  cmd->ac->is = is;
310  cmd->ac->cont = &interpreter_next;
311  cmd->ac->cont_cls = is;
312  cmd->ac->finished = GNUNET_NO;
313  }
314  cmd->run (cmd->cls,
315  is);
316  if (NULL == cmd->ac)
317  {
319  }
320  else if ( (cmd->asynchronous_finish) &&
321  (NULL != cmd->ac->cont) )
322  {
323  cmd->ac->cont = NULL;
325  }
326 }
327 
328 
334 static void
336 {
337  struct GNUNET_TESTING_Interpreter *is = cls;
338 
339  is->timeout_task = NULL;
341  "Terminating test due to global timeout\n");
342  is->result = GNUNET_SYSERR;
343  finish_test (is);
344 }
345 
346 
347 void
351  void *rc_cls)
352 {
354  unsigned int i;
355 
357  is->rc = rc;
358  is->rc_cls = rc_cls;
359  /* get the number of commands */
360  for (i = 0; NULL != commands[i].label; i++)
361  ;
362  is->commands = GNUNET_new_array (i + 1,
363  struct GNUNET_TESTING_Command);
364  memcpy (is->commands,
365  commands,
366  sizeof (struct GNUNET_TESTING_Command) * i);
367  is->timeout_task
369  &do_timeout,
370  is);
372  is);
373 }
374 
375 
380 {
381 
386 
391 
395  int rv;
396 };
397 
398 
405 static void
406 handle_result (void *cls,
408 {
409  struct MainParams *mp = cls;
410 
412  "Test exits with status %d\n",
413  rv);
414  if (GNUNET_OK != rv)
415  mp->rv = EXIT_FAILURE;
417 }
418 
419 
425 static void
426 loop_run (void *cls)
427 {
428  struct MainParams *mp = cls;
429 
431  mp->timeout,
432  &handle_result,
433  mp);
434 }
435 
436 
437 int
440 {
441  struct MainParams mp = {
442  .commands = commands,
443  .timeout = timeout,
444  .rv = EXIT_SUCCESS
445  };
446 
448  &mp);
449  return mp.rv;
450 }
451 
452 
453 void
455 {
456  GNUNET_assert (GNUNET_NO == ac->finished);
457  ac->finished = GNUNET_SYSERR;
459  if (NULL != ac->cont)
460  {
461  ac->cont (ac->cont_cls);
462  ac->cont = NULL;
463  }
464 }
465 
466 
467 void
469 {
470  GNUNET_assert (GNUNET_NO == ac->finished);
471  ac->finished = GNUNET_OK;
472  if (NULL != ac->cont)
473  {
474  ac->cont (ac->cont_cls);
475  ac->cont = NULL;
476  }
477 }
478 
479 
480 /* end of testing_api_loop.c */
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static struct GNUNET_NT_InterfaceScanner * is
Network scanner to determine network types.
static struct VoipCommand commands[]
List of supported commands.
static struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
#define GNUNET_log(kind,...)
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:92
@ GNUNET_OK
Definition: gnunet_common.h:95
@ GNUNET_YES
Definition: gnunet_common.h:97
@ GNUNET_NO
Definition: gnunet_common.h:94
@ GNUNET_SYSERR
Definition: gnunet_common.h:93
void(* GNUNET_TESTING_ResultCallback)(void *cls, enum GNUNET_GenericReturnValue rv)
Function called with the final result of the test.
enum GNUNET_GenericReturnValue GNUNET_TESTING_get_trait_cmd(const struct GNUNET_TESTING_Command *cmd, unsigned int index, struct GNUNET_TESTING_Command **_cmd)
Obtain a command from cmd.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_MESSAGE
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:531
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:720
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1296
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1269
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition: time.c:263
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:86
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:557
Entry in list of pending tasks.
Definition: scheduler.c:135
State each asynchronous command must have in its closure.
GNUNET_SCHEDULER_TaskCallback cont
Function to call when done.
void * cont_cls
Closure for cont.
struct GNUNET_TESTING_Interpreter * is
Interpreter we are part of.
enum GNUNET_GenericReturnValue finished
Indication if the command finished (GNUNET_OK).
A command to be run by the interpreter.
struct GNUNET_TIME_Absolute finish_time
When did the execution of this command finish?
void(* cleanup)(void *cls)
Clean up after the command.
struct GNUNET_TIME_Absolute last_req_time
When did we start the last run of this command? Delta to finish_time gives the latency for the last s...
struct GNUNET_TESTING_AsyncContext * ac
Pointer to the asynchronous context in the command's closure.
void(* run)(void *cls, struct GNUNET_TESTING_Interpreter *is)
Runs the command.
bool asynchronous_finish
If "true", the interpreter should not immediately call finish, even if finish is non-NULL.
unsigned int num_tries
How often did we try to execute this command? (In case it is a request that is repated....
struct GNUNET_TIME_Absolute start_time
When did the execution of this command start?
const char * label
Label for the command.
void * cls
Closure for all commands with command-specific context information.
Global state of the interpreter, used by a command to access information about other commands.
GNUNET_TESTING_ResultCallback rc
Function to call with the test result.
void * rc_cls
Closure for rc.
struct GNUNET_SCHEDULER_Task * final_task
Final task that returns the result.
struct GNUNET_SCHEDULER_Task * timeout_task
Task run on timeout.
int ip
Instruction pointer.
struct GNUNET_SCHEDULER_Task * task
Interpreter task (if one is scheduled).
struct GNUNET_TESTING_Command * commands
Commands the interpreter will run.
enum GNUNET_GenericReturnValue result
Result of the testcases, GNUNET_OK on success.
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.
Closure for loop_run().
int rv
Set to #EXIT_FAILURE on error.
struct GNUNET_TIME_Relative timeout
Global timeout for the test.
struct GNUNET_TESTING_Command * commands
NULL-label terminated array of commands.
struct GNUNET_TESTING_Command * GNUNET_TESTING_cmd_batch_get_current_(const struct GNUNET_TESTING_Command *cmd)
Obtain what command the batch is at.
bool GNUNET_TESTING_cmd_batch_next_(void *cls)
Advance internal pointer to next command.
bool GNUNET_TESTING_cmd_is_batch_(const struct GNUNET_TESTING_Command *cmd)
Test if this command is a batch command.
void GNUNET_TESTING_async_finish(struct GNUNET_TESTING_AsyncContext *ac)
The asynchronous command of ac has finished.
void GNUNET_TESTING_async_fail(struct GNUNET_TESTING_AsyncContext *ac)
The asynchronous command of ac has failed.
static void do_timeout(void *cls)
Function run when the test terminates (good or bad) with timeout.
void GNUNET_TESTING_run(struct GNUNET_TESTING_Command *commands, struct GNUNET_TIME_Relative timeout, GNUNET_TESTING_ResultCallback rc, void *rc_cls)
Run the testsuite.
static void interpreter_run(void *cls)
Run the main interpreter loop that performs exchange operations.
static void interpreter_next(void *cls)
Current command is done, run the next one.
static void handle_result(void *cls, enum GNUNET_GenericReturnValue rv)
Function called with the final result of the test.
#define BATCH_INDEX
const char * GNUNET_TESTING_interpreter_get_current_label(struct GNUNET_TESTING_Interpreter *is)
Obtain label of the command being now run.
const struct GNUNET_TESTING_Command * GNUNET_TESTING_interpreter_lookup_command(struct GNUNET_TESTING_Interpreter *is, const char *label)
Lookup command by label.
void GNUNET_TESTING_interpreter_fail(struct GNUNET_TESTING_Interpreter *is)
Current command failed, clean up and fail the test case.
static void finish_test(void *cls)
Finish the test run, return the final result.
static void loop_run(void *cls)
Main function to run the test cases.
int GNUNET_TESTING_main(struct GNUNET_TESTING_Command *commands, struct GNUNET_TIME_Relative timeout)
Start a GNUnet scheduler event loop and run the testsuite.