GNUnet  0.17.6
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 
192 const struct GNUNET_TESTING_Command *
195  const char *label)
196 {
197  const struct GNUNET_TESTING_Command *cmd;
198 
199  cmd = get_command (is, label, GNUNET_NO);
200  if (NULL == cmd)
201  cmd = get_command (is, label, GNUNET_YES);
202  return cmd;
203 }
204 
205 
211 static void
213 {
214  struct GNUNET_TESTING_Interpreter *is = cls;
215  struct GNUNET_TESTING_Command *cmd;
216  const char *label;
217 
218  is->final_task = NULL;
219  label = is->commands[is->ip].label;
220  if (NULL == label)
221  label = "END";
223  "Interpreter finishes at `%s' with status %d\n",
224  label,
225  is->result);
226  for (unsigned int j = 0;
227  NULL != (cmd = &is->commands[j])->label;
228  j++)
229  {
231  "Cleaning up cmd %s\n",
232  cmd->label);
233  cmd->cleanup (cmd->cls);
235  "Cleaned up cmd %s\n",
236  cmd->label);
237  }
238  if (NULL != is->task)
239  {
240  GNUNET_SCHEDULER_cancel (is->task);
241  is->task = NULL;
242  }
243  if (NULL != is->timeout_task)
244  {
245  GNUNET_SCHEDULER_cancel (is->timeout_task);
246  is->timeout_task = NULL;
247  }
248  GNUNET_free (is->commands);
249  is->rc (is->rc_cls,
250  is->result);
251  GNUNET_free (is);
252 }
253 
254 
260 static void
261 interpreter_run (void *cls);
262 
263 
267 static void
269 {
270  struct GNUNET_TESTING_Interpreter *is = cls;
271  static unsigned long long ipc;
272  static struct GNUNET_TIME_Absolute last_report;
273  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
274 
275  if (GNUNET_SYSERR == is->result)
276  return; /* ignore, we already failed! */
278  if ( (! GNUNET_TESTING_cmd_is_batch_ (cmd)) ||
280  is->ip++;
281  if (0 == (ipc % 1000))
282  {
283  if (0 != ipc)
285  "Interpreter executed 1000 instructions in %s\n",
287  GNUNET_TIME_absolute_get_duration (last_report),
288  GNUNET_YES));
289  last_report = GNUNET_TIME_absolute_get ();
290  }
291  ipc++;
293  is);
294 }
295 
296 
297 void
299 {
300  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
301 
302  if (GNUNET_SYSERR == is->result)
303  {
304  GNUNET_break (0);
305  return; /* ignore, we already failed! */
306  }
307  if (NULL != cmd)
308  {
310  "Failed at command `%s'\n",
311  cmd->label);
312  while (GNUNET_TESTING_cmd_is_batch_ (cmd))
313  {
316  "Failed in batch at command `%s'\n",
317  cmd->label);
318  }
319  }
320  else
321  {
323  "Failed with CMD being NULL!\n");
324  }
325  is->result = GNUNET_SYSERR;
326  GNUNET_assert (NULL == is->final_task);
327  is->final_task = GNUNET_SCHEDULER_add_now (&finish_test,
328  is);
329 }
330 
331 
339 struct GNUNET_TESTING_Command *
342 {
343  return &is->commands[is->ip];
344 }
345 
346 
347 const char *
350 {
351  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
352 
353  return cmd->label;
354 }
355 
356 
362 static void
364 {
365  struct GNUNET_TESTING_Interpreter *is = cls;
366  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
367 
368  is->task = NULL;
369  if (NULL == cmd->label)
370  {
372  "Running command END\n");
373  is->result = GNUNET_OK;
374  finish_test (is);
375  return;
376  }
378  "Running command `%s'\n",
379  cmd->label);
381  "start time of %p expected 0 is `%lu'\n",
382  cmd,
383  cmd->start_time.abs_value_us);
384  cmd->start_time
385  = cmd->last_req_time
388  "start time of %p expected something is `%lu'\n",
389  cmd,
390  cmd->start_time.abs_value_us);
391  cmd->num_tries = 1;
392  if (NULL != cmd->ac)
393  {
394  cmd->ac->is = is;
395  cmd->ac->cont = &interpreter_next;
396  cmd->ac->cont_cls = is;
397  cmd->ac->finished = GNUNET_NO;
398  }
399  cmd->run (cmd->cls,
400  is);
401  if (NULL == cmd->ac)
402  {
404  }
405  else if ( (cmd->asynchronous_finish) &&
406  (NULL != cmd->ac->cont) )
407  {
408  cmd->ac->cont = NULL;
410  }
411 }
412 
413 
419 static void
421 {
422  struct GNUNET_TESTING_Interpreter *is = cls;
423 
424  is->timeout_task = NULL;
426  "Terminating test due to global timeout\n");
427  is->result = GNUNET_SYSERR;
428  finish_test (is);
429 }
430 
431 
439 GNUNET_TESTING_running (const struct GNUNET_TESTING_Command *command)
440 {
441  return 0 != command->start_time.abs_value_us && 0 ==
442  command->finish_time.abs_value_us;
443 }
444 
445 
454 {
457  command->finish_time,
458  now);
459  return 0 < diff.rel_value_us;
460 }
461 
462 
463 void
467  void *rc_cls)
468 {
470  unsigned int i;
471 
473  is->rc = rc;
474  is->rc_cls = rc_cls;
475  /* get the number of commands */
476  for (i = 0; NULL != commands[i].label; i++)
477  ;
478  is->cmds_n = i + 1;
479  is->commands = GNUNET_new_array (is->cmds_n,
480  struct GNUNET_TESTING_Command);
481  memcpy (is->commands,
482  commands,
483  sizeof (struct GNUNET_TESTING_Command) * i);
484  is->timeout_task
486  &do_timeout,
487  is);
489  is);
490 }
491 
492 
497 {
498 
503 
508 
512  int rv;
513 };
514 
515 
522 static void
523 handle_result (void *cls,
525 {
526  struct MainParams *mp = cls;
527 
529  "Test exits with status %d\n",
530  rv);
531  if (GNUNET_OK != rv)
532  mp->rv = EXIT_FAILURE;
534 }
535 
536 
542 static void
543 loop_run (void *cls)
544 {
545  struct MainParams *mp = cls;
546 
548  mp->timeout,
549  &handle_result,
550  mp);
551 }
552 
553 
554 int
557 {
558  struct MainParams mp = {
559  .commands = commands,
560  .timeout = timeout,
561  .rv = EXIT_SUCCESS
562  };
563 
565  &mp);
566  return mp.rv;
567 }
568 
569 
570 void
572 {
573  GNUNET_assert (GNUNET_NO == ac->finished);
574  ac->finished = GNUNET_SYSERR;
576  if (NULL != ac->cont)
577  {
578  ac->cont (ac->cont_cls);
579  ac->cont = NULL;
580  }
581 }
582 
583 
584 void
586 {
587  GNUNET_assert (GNUNET_NO == ac->finished);
588  ac->finished = GNUNET_OK;
589  if (NULL != ac->cont)
590  {
591  ac->cont (ac->cont_cls);
592  ac->cont = NULL;
593  }
594 }
595 
596 
597 /* 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.
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_log(kind,...)
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:96
@ GNUNET_OK
Definition: gnunet_common.h:99
@ GNUNET_YES
@ GNUNET_NO
Definition: gnunet_common.h:98
@ GNUNET_SYSERR
Definition: gnunet_common.h:97
#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.