GNUnet  0.16.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 
58  unsigned int cmds_n;
59 
64 
69 
74 
80  int ip;
81 
86 
87 };
88 
89 
90 const struct GNUNET_TESTING_Command *
92  const char *label,
93  unsigned int future)
94 {
95  int start_i = GNUNET_NO == future ? is->ip : is->cmds_n - 1;
96  int end_i = GNUNET_NO == future ? 0 : is->ip + 1;
97 
99  "start_i: %u end_i: %u\n",
100  start_i,
101  end_i);
102  if (NULL == label)
103  {
105  "Attempt to lookup command for empty label\n");
106  return NULL;
107  }
108 
109  for (int i = start_i; i >= end_i; i--)
110  {
111  const struct GNUNET_TESTING_Command *cmd = &is->commands[i];
112 
113  if (NULL != cmd->label)
115  "label to compare %s\n",
116  cmd->label);
117  /* Give precedence to top-level commands. */
118  if ( (NULL != cmd->label) &&
119  (0 == strcmp (cmd->label,
120  label)) )
121  return cmd;
122 
124  {
125  struct GNUNET_TESTING_Command **batch;
126  struct GNUNET_TESTING_Command *current;
127  const struct GNUNET_TESTING_Command *icmd;
128  const struct GNUNET_TESTING_Command *match;
129 
133  &batch));
134  /* We must do the loop forward, but we can find the last match */
135  match = NULL;
136  for (unsigned int j = 0;
137  NULL != (icmd = &(*batch)[j])->label;
138  j++)
139  {
140  if (current == icmd)
141  break; /* do not go past current command */
142  if ( (NULL != icmd->label) &&
143  (0 == strcmp (icmd->label,
144  label)) )
145  match = icmd;
146  }
147  if (NULL != match)
148  return match;
149  }
150  }
152  "Command `%s' not found\n",
153  label);
154  return NULL;
155 }
156 
157 
166 const struct GNUNET_TESTING_Command *
169  const char *label)
170 {
171  return get_command (is, label, GNUNET_YES);
172 }
173 
174 
183 const struct GNUNET_TESTING_Command *
186  const char *label)
187 {
188  return get_command (is, label, GNUNET_NO);
189 }
190 
191 
200 const struct GNUNET_TESTING_Command *
203  const char *label)
204 {
205  const struct GNUNET_TESTING_Command *cmd;
206 
207  cmd = get_command (is, label, GNUNET_NO);
208  if (NULL == cmd)
209  cmd = get_command (is, label, GNUNET_YES);
210  return cmd;
211 }
212 
213 
219 static void
221 {
222  struct GNUNET_TESTING_Interpreter *is = cls;
223  struct GNUNET_TESTING_Command *cmd;
224  const char *label;
225 
226  is->final_task = NULL;
227  label = is->commands[is->ip].label;
228  if (NULL == label)
229  label = "END";
231  "Interpreter finishes at `%s' with status %d\n",
232  label,
233  is->result);
234  for (unsigned int j = 0;
235  NULL != (cmd = &is->commands[j])->label;
236  j++)
237  {
239  "Cleaning up cmd %s\n",
240  cmd->label);
241  cmd->cleanup (cmd->cls);
243  "Cleaned up cmd %s\n",
244  cmd->label);
245  }
246  if (NULL != is->task)
247  {
248  GNUNET_SCHEDULER_cancel (is->task);
249  is->task = NULL;
250  }
251  if (NULL != is->timeout_task)
252  {
253  GNUNET_SCHEDULER_cancel (is->timeout_task);
254  is->timeout_task = NULL;
255  }
256  GNUNET_free (is->commands);
257  is->rc (is->rc_cls,
258  is->result);
259  GNUNET_free (is);
260 }
261 
262 
268 static void
269 interpreter_run (void *cls);
270 
271 
275 static void
277 {
278  struct GNUNET_TESTING_Interpreter *is = cls;
279  static unsigned long long ipc;
280  static struct GNUNET_TIME_Absolute last_report;
281  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
282 
283  if (GNUNET_SYSERR == is->result)
284  return; /* ignore, we already failed! */
286  if ( (! GNUNET_TESTING_cmd_is_batch_ (cmd)) ||
288  is->ip++;
289  if (0 == (ipc % 1000))
290  {
291  if (0 != ipc)
293  "Interpreter executed 1000 instructions in %s\n",
295  GNUNET_TIME_absolute_get_duration (last_report),
296  GNUNET_YES));
297  last_report = GNUNET_TIME_absolute_get ();
298  }
299  ipc++;
301  is);
302 }
303 
304 
305 void
307 {
308  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
309 
310  if (GNUNET_SYSERR == is->result)
311  {
312  GNUNET_break (0);
313  return; /* ignore, we already failed! */
314  }
315  if (NULL != cmd)
316  {
318  "Failed at command `%s'\n",
319  cmd->label);
320  while (GNUNET_TESTING_cmd_is_batch_ (cmd))
321  {
324  "Failed in batch at command `%s'\n",
325  cmd->label);
326  }
327  }
328  else
329  {
331  "Failed with CMD being NULL!\n");
332  }
333  is->result = GNUNET_SYSERR;
334  GNUNET_assert (NULL == is->final_task);
335  is->final_task = GNUNET_SCHEDULER_add_now (&finish_test,
336  is);
337 }
338 
339 
347 struct GNUNET_TESTING_Command *
350 {
351  return &is->commands[is->ip];
352 }
353 
354 const char *
357 {
358  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
359 
360  return cmd->label;
361 }
362 
363 
369 static void
371 {
372  struct GNUNET_TESTING_Interpreter *is = cls;
373  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
374 
375  is->task = NULL;
376  if (NULL == cmd->label)
377  {
379  "Running command END\n");
380  is->result = GNUNET_OK;
381  finish_test (is);
382  return;
383  }
385  "Running command `%s'\n",
386  cmd->label);
388  "start time of %p expected 0 is `%lu'\n",
389  cmd,
390  cmd->start_time.abs_value_us);
391  cmd->start_time
392  = cmd->last_req_time
395  "start time of %p expected something is `%lu'\n",
396  cmd,
397  cmd->start_time.abs_value_us);
398  cmd->num_tries = 1;
399  if (NULL != cmd->ac)
400  {
401  cmd->ac->is = is;
402  cmd->ac->cont = &interpreter_next;
403  cmd->ac->cont_cls = is;
404  cmd->ac->finished = GNUNET_NO;
405  }
406  cmd->run (cmd->cls,
407  is);
408  if (NULL == cmd->ac)
409  {
411  }
412  else if ( (cmd->asynchronous_finish) &&
413  (NULL != cmd->ac->cont) )
414  {
415  cmd->ac->cont = NULL;
417  }
418 }
419 
420 
426 static void
428 {
429  struct GNUNET_TESTING_Interpreter *is = cls;
430 
431  is->timeout_task = NULL;
433  "Terminating test due to global timeout\n");
434  is->result = GNUNET_SYSERR;
435  finish_test (is);
436 }
437 
438 
446 GNUNET_TESTING_running (const struct GNUNET_TESTING_Command *command)
447 {
448  return 0 != command->start_time.abs_value_us && 0 ==
449  command->finish_time.abs_value_us;
450 }
451 
452 
461 {
464  command->finish_time,
465  now);
466  return 0 < diff.rel_value_us;
467 }
468 
469 
470 void
474  void *rc_cls)
475 {
477  unsigned int i;
478 
480  is->rc = rc;
481  is->rc_cls = rc_cls;
482  /* get the number of commands */
483  for (i = 0; NULL != commands[i].label; i++)
484  ;
485  is->cmds_n = i + 1;
486  is->commands = GNUNET_new_array (is->cmds_n,
487  struct GNUNET_TESTING_Command);
488  memcpy (is->commands,
489  commands,
490  sizeof (struct GNUNET_TESTING_Command) * i);
491  is->timeout_task
493  &do_timeout,
494  is);
496  is);
497 }
498 
499 
504 {
505 
510 
515 
519  int rv;
520 };
521 
522 
529 static void
530 handle_result (void *cls,
532 {
533  struct MainParams *mp = cls;
534 
536  "Test exits with status %d\n",
537  rv);
538  if (GNUNET_OK != rv)
539  mp->rv = EXIT_FAILURE;
541 }
542 
543 
549 static void
550 loop_run (void *cls)
551 {
552  struct MainParams *mp = cls;
553 
555  mp->timeout,
556  &handle_result,
557  mp);
558 }
559 
560 
561 int
564 {
565  struct MainParams mp = {
566  .commands = commands,
567  .timeout = timeout,
568  .rv = EXIT_SUCCESS
569  };
570 
572  &mp);
573  return mp.rv;
574 }
575 
576 
577 void
579 {
580  GNUNET_assert (GNUNET_NO == ac->finished);
581  ac->finished = GNUNET_SYSERR;
583  if (NULL != ac->cont)
584  {
585  ac->cont (ac->cont_cls);
586  ac->cont = NULL;
587  }
588 }
589 
590 
591 void
593 {
594  GNUNET_assert (GNUNET_NO == ac->finished);
595  ac->finished = GNUNET_OK;
596  if (NULL != ac->cont)
597  {
598  ac->cont (ac->cont_cls);
599  ac->cont = NULL;
600  }
601 }
602 
603 
604 /* 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_batch_cmds(const struct GNUNET_TESTING_Command *cmd, struct GNUNET_TESTING_Command ***ret)
#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:533
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition: scheduler.c:705
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:1281
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:957
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:1254
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:435
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:110
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:570
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end)
Compute the time difference between the given start and end times.
Definition: time.c:420
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.
unsigned int cmds_n
Number of GNUNET_TESTING_Command in commands.
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.
uint64_t abs_value_us
The actual value.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
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.
struct GNUNET_TESTING_Command * GNUNET_TESTING_interpreter_get_current_command(struct GNUNET_TESTING_Interpreter *is)
Returns the actual running command.
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.
const struct GNUNET_TESTING_Command * get_command(struct GNUNET_TESTING_Interpreter *is, const char *label, unsigned int future)
static void interpreter_next(void *cls)
Current command is done, run the next one.
enum GNUNET_GenericReturnValue GNUNET_TESTING_finished(struct GNUNET_TESTING_Command *command)
Check if a command is finished.
static void handle_result(void *cls, enum GNUNET_GenericReturnValue rv)
Function called with the final result of the test.
const struct GNUNET_TESTING_Command * GNUNET_TESTING_interpreter_lookup_command_all(struct GNUNET_TESTING_Interpreter *is, const char *label)
Lookup command by label.
const struct GNUNET_TESTING_Command * GNUNET_TESTING_interpreter_lookup_future_command(struct GNUNET_TESTING_Interpreter *is, const char *label)
Lookup command by label.
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.
enum GNUNET_GenericReturnValue GNUNET_TESTING_running(const struct GNUNET_TESTING_Command *command)
Check if the command is running.
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.