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 
33 #define CHECK_FINISHED_PERIOD \
34  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
35 
37 
42 {
43 
48 
53 
58 };
59 
64 {
65 
69  const struct GNUNET_TESTING_Command *cmd;
70 
75 };
76 
83 const struct GNUNET_TESTING_Command *
85 {
86  if (NULL == label)
87  {
89  "Attempt to lookup command for empty label\n");
90  return NULL;
91  }
92  /* Search backwards as we most likely reference recent commands */
93  for (int i = is->ip; i >= 0; i--)
94  {
95  const struct GNUNET_TESTING_Command *cmd = &is->commands[i];
96 
97  /* Give precedence to top-level commands. */
98  if ( (NULL != cmd->label) &&
99  (0 == strcmp (cmd->label,
100  label)) )
101  return cmd;
102 
103  if (GNUNET_TESTING_cmd_is_batch (cmd))
104  {
105 #define BATCH_INDEX 1
106  struct GNUNET_TESTING_Command *batch;
107  struct GNUNET_TESTING_Command *current;
108  struct GNUNET_TESTING_Command *icmd;
109  const struct GNUNET_TESTING_Command *match;
110 
111  current = GNUNET_TESTING_cmd_batch_get_current (cmd);
114  BATCH_INDEX,
115  &batch));
116  /* We must do the loop forward, but we can find the last match */
117  match = NULL;
118  for (unsigned int j = 0;
119  NULL != (icmd = &batch[j])->label;
120  j++)
121  {
122  if (current == icmd)
123  break; /* do not go past current command */
124  if ( (NULL != icmd->label) &&
125  (0 == strcmp (icmd->label,
126  label)) )
127  match = icmd;
128  }
129  if (NULL != match)
130  return match;
131  }
132  }
134  "Command not found: %s\n",
135  label);
136  return NULL;
137 
138 }
139 
140 
146 static void
147 interpreter_run (void *cls);
148 
149 
153 static void
155 {
156  struct GNUNET_TESTING_Interpreter *is = cls;
157  static unsigned long long ipc;
158  static struct GNUNET_TIME_Absolute last_report;
159  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
160 
161  if (GNUNET_SYSERR == is->result)
162  return; /* ignore, we already failed! */
163  if (GNUNET_TESTING_cmd_is_batch (cmd))
164  {
166  }
167  else
168  {
170  is->ip++;
171  }
172  if (0 == (ipc % 1000))
173  {
174  if (0 != ipc)
176  "Interpreter executed 1000 instructions in %s\n",
178  GNUNET_TIME_absolute_get_duration (last_report),
179  GNUNET_YES));
180  last_report = GNUNET_TIME_absolute_get ();
181  }
182  ipc++;
184  is);
185 }
186 
187 
188 static void
190 {
191  struct FinishTaskClosure *ftc = cls;
192  const struct GNUNET_TESTING_Command *cmd = ftc->cmd;
193  struct GNUNET_TESTING_Interpreter *is = ftc->is;
194  unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is);
195 
196  if (GNUNET_YES == finished)
197  {
198  is->finish_task = NULL;
199  }
200  else if (GNUNET_NO == finished)
201  {
203  &run_finish_task_next, ftc);
204  }
205  else
206  {
208  "Next task finished with an error.\n");
210  }
211 
212 }
213 
214 
215 static void
217 {
218  struct SyncTaskClosure *stc = cls;
219  const struct GNUNET_TESTING_Command *cmd = stc->async_cmd;
220  const struct GNUNET_TESTING_Command *sync_cmd = stc->sync_cmd;
221  struct FinishTaskClosure *ftc;
222  struct SyncState *sync_state = sync_cmd->cls;
223  struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task;
224  unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is);
225 
226  GNUNET_assert (NULL != finish_task);
227  ftc = GNUNET_new (struct FinishTaskClosure);
228  ftc->cmd = stc->sync_cmd;
229  ftc->is = stc->is;
232  - sync_state->start_finish_time.abs_value_us)
233  {
235  "The command with label %s did not finish its asynchronous task in time.\n",
236  cmd->label);
238  }
239 
240  if (GNUNET_YES == finished)
241  {
242  finish_task = NULL;
243  }
244  else if (GNUNET_NO == finished)
245  {
247  &run_finish_task_sync, stc);
248  }
249  else
250  {
252  "Sync task finished with an error.\n");
254  }
255 }
256 
257 
258 static void
260  const struct GNUNET_TESTING_Command *cmd,
261  struct GNUNET_TESTING_Interpreter *is)
262 {
263  struct SyncState *sync_state = cls;
264  struct SyncTaskClosure *stc;
265  const struct GNUNET_TESTING_Command *async_cmd;
266 
267  async_cmd = sync_state->async_cmd;
268  stc = GNUNET_new (struct SyncTaskClosure);
269  stc->async_cmd = async_cmd;
270  stc->sync_cmd = cmd;
271  stc->is = is;
276  stc);
277 }
278 
279 
280 const struct GNUNET_TESTING_Command
281 GNUNET_TESTING_cmd_finish (const char *finish_label,
282  const char *cmd_ref,
284 {
285  const struct GNUNET_TESTING_Command *async_cmd;
286  struct SyncState *sync_state;
287 
288  async_cmd = GNUNET_TESTING_interpreter_lookup_command (cmd_ref);
289  sync_state = GNUNET_new (struct SyncState);
290  sync_state->async_cmd = async_cmd;
291 
292  struct GNUNET_TESTING_Command cmd = {
293  .cls = sync_state,
294  .label = finish_label,
296  .asynchronous_finish = GNUNET_NO
297  };
298 
299  return cmd;
300 }
301 
302 
303 const struct GNUNET_TESTING_Command
305 {
306 
307  GNUNET_assert (NULL != cmd.finish);
308  const struct GNUNET_TESTING_Command async_cmd = {
309  .cls = cmd.cls,
310  .label = cmd.label,
311  .run = cmd.run,
312  .cleanup = cmd.cleanup,
313  .traits = cmd.traits,
314  .finish = cmd.finish,
315  .asynchronous_finish = GNUNET_YES
316  };
317 
318  return async_cmd;
319 }
320 
321 
327 void
329 {
330  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
331 
332  if (GNUNET_SYSERR == is->result)
333  return; /* ignore, we already failed! */
334 
336  "interpreter_fail!\n");
337 
338  if (NULL != cmd)
339  {
340  while (GNUNET_TESTING_cmd_is_batch (cmd))
341  {
344  "Batch is at command `%s'\n",
345  cmd->label);
346  }
347 
348  }
349  else
350  {
352  "cmd is NULL.\n");
353  }
354 
355  if (NULL == cmd->label)
356  {
358  "Failed at command `%s'\n",
359  cmd->label);
360 
361  }
362  else
363  {
365  "cmd->label is NULL.\n");
366  }
367 
368  is->result = GNUNET_SYSERR;
370 }
371 
372 
380 {
381  static struct GNUNET_TESTING_Command cmd;
382  cmd.label = NULL;
383 
384  return cmd;
385 }
386 
387 
391 const char *
394 {
395  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
396 
397  return cmd->label;
398 }
399 
400 
406 static void
408 {
409  struct FinishTaskClosure *ftc;
410  struct GNUNET_TESTING_Interpreter *is = cls;
411  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
412 
413  is->task = NULL;
414 
415  if (NULL == cmd->label)
416  {
417 
419  "Running command END %p\n",
420  is);
421  is->result = GNUNET_OK;
423  return;
424  }
425  else if (NULL != cmd)
426  {
428  "Running command `%s' %p\n",
429  cmd->label,
430  is);
431  }
432  cmd->start_time
433  = cmd->last_req_time
435  cmd->num_tries = 1;
436  cmd->run (cmd->cls,
437  cmd,
438  is);
439  if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish))
440  {
442  "Next task will not be called directly!\n");
443  ftc = GNUNET_new (struct FinishTaskClosure);
444  ftc->cmd = cmd;
445  ftc->is = is;
448  ftc);
449  }
450  else
451  {
452  interpreter_next (is);
453  }
454 }
455 
456 
463 static void
465 {
466  (void) cls;
467  struct GNUNET_TESTING_Command *cmd;
468  const char *label;
469 
470  label = is->commands[is->ip].label;
471  if (NULL == label)
472  label = "END";
473 
475  "Executing shutdown at `%s'\n",
476  label);
477 
478  for (unsigned int j = 0;
479  NULL != (cmd = &is->commands[j])->label;
480  j++) {
481  cmd->cleanup (cmd->cls,
482  cmd);
483  }
484 
485  if (NULL != is->finish_task)
486  {
488  cmd->finish_task = NULL;
489  }
490 
491  if (NULL != is->task)
492  {
494  is->task = NULL;
495  }
496  if (NULL != is->timeout_task)
497  {
499  is->timeout_task = NULL;
500  }
501  GNUNET_free (is->commands);
502 }
503 
504 
510 static void
512 {
513  (void) cls;
514 
515  is->timeout_task = NULL;
517  "Terminating test due to timeout\n");
519 }
520 
521 
532 int
536 {
537  unsigned int i;
538 
540 
541  if (NULL != is->timeout_task)
542  {
544  is->timeout_task = NULL;
545  }
546  /* get the number of commands */
547  for (i = 0; NULL != commands[i].label; i++)
548  ;
549  is->commands = GNUNET_new_array (i + 1,
550  struct GNUNET_TESTING_Command);
551  memcpy (is->commands,
552  commands,
553  sizeof (struct GNUNET_TESTING_Command) * i);
554 
556  (timeout,
557  &do_timeout,
558  is);
561  return GNUNET_OK;
562 }
563 
564 
565 /* end of testing_api_loop.c */
const struct GNUNET_TESTING_Command GNUNET_TESTING_cmd_make_unblocking(const struct GNUNET_TESTING_Command cmd)
Turn asynchronous command into non blocking command by setting asynchronous_finish to true...
bool asynchronous_finish
If "true", the interpreter should not immediately call finish, even if finish is non-NULL.
void(* cleanup)(void *cls, const struct GNUNET_TESTING_Command *cmd)
Clean up after the command.
void GNUNET_TESTING_cmd_batch_next(struct GNUNET_TESTING_Interpreter *is)
Advance internal pointer to next command.
static char * cfg_filename
Name of the configuration file.
struct GNUNET_SCHEDULER_Task * finish_task
Task for running the finish method of the asynchronous task the command is waiting for...
static void interpreter_next(void *cls)
Current command is done, run the next one.
uint64_t rel_value_us
The actual value.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1331
const struct GNUNET_TESTING_Command * GNUNET_TESTING_interpreter_lookup_command(const char *label)
Lookup command by label.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * label
Label for the command.
A command to be run by the interpreter.
struct GNUNET_TIME_Relative default_timeout
In case asynchronous_finish is true, how long should we wait for this command to complete? If finish did not complete after this amount of time, the interpreter will fail.
static void do_shutdown(void *cls)
Function run when the test terminates (good or bad).
static void finish_task(struct TaskEntry *task)
#define GNUNET_new(type)
Allocate a struct or union of the given type.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:531
uint64_t abs_value_us
The actual value.
static void interpreter_run(void *cls)
Run the main interpreter loop that performs exchange operations.
Struct to use for command-specific context information closure of a command waiting for another comma...
struct GNUNET_TIME_Absolute finish_time
When did the execution of this command finish?
Closure used to sync an asynchronous with an synchronous command.
struct GNUNET_TESTING_Interpreter * is
The interpreter of the test.
int GNUNET_TESTING_run(const char *cfg_filename, struct GNUNET_TESTING_Command *commands, struct GNUNET_TIME_Relative timeout)
Run the testsuite.
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
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
Global state of the interpreter, used by a command to access information about other commands...
Definition: testing.h:34
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
static void do_timeout(void *cls)
Function run when the test terminates (good or bad) with timeout.
static struct VoipCommand commands[]
List of supported commands.
struct GNUNET_TESTING_Interpreter * is
struct GNUNET_TIME_Absolute start_time
When did the execution of this command start?
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
const char * GNUNET_TESTING_interpreter_get_current_label(struct GNUNET_TESTING_Interpreter *is)
Obtain current label.
struct GNUNET_SCHEDULER_Task * finish_task
Finish task of a blocking call to a commands finish method.
Definition: testing.h:50
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define CHECK_FINISHED_PERIOD
struct GNUNET_TIME_Absolute start_finish_time
When did the execution of this commands finish function start?
#define BATCH_INDEX
const struct GNUNET_TESTING_Command * cmd
The asynchronous command the synchronous command waits for.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:86
const struct GNUNET_TESTING_Command * async_cmd
The asynchronous command the synchronous command of this closure waits for.
const struct GNUNET_TESTING_Command * async_cmd
The asynchronous command the synchronous command waits for.
const struct GNUNET_TESTING_Command GNUNET_TESTING_cmd_finish(const char *finish_label, const char *cmd_ref, struct GNUNET_TIME_Relative timeout)
Create (synchronous) command that waits for another command to finish.
struct GNUNET_TESTING_Command * commands
Commands the interpreter will run.
Definition: testing.h:40
int GNUNET_TESTING_cmd_is_batch(const struct GNUNET_TESTING_Command *cmd)
Test if this command is a batch command.
int ip
Instruction pointer.
Definition: testing.h:67
void(* run)(void *cls, const struct GNUNET_TESTING_Command *cmd, struct GNUNET_TESTING_Interpreter *i)
Runs 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...
static void run_finish_task_sync(void *cls)
int GNUNET_TESTING_get_trait_cmd(const struct GNUNET_TESTING_Command *cmd, unsigned int index, struct GNUNET_TESTING_Command **_cmd)
Obtain a command from cmd.
static void start_finish_on_ref(void *cls, const struct GNUNET_TESTING_Command *cmd, struct GNUNET_TESTING_Interpreter *is)
static void run_finish_task_next(void *cls)
struct GNUNET_TESTING_Command GNUNET_TESTING_cmd_end(void)
Create command array terminator.
struct GNUNET_SCHEDULER_Task * task
Interpreter task (if one is scheduled).
Definition: testing.h:45
Closure used to run the finish task.
struct GNUNET_TESTING_Command * GNUNET_TESTING_cmd_batch_get_current(const struct GNUNET_TESTING_Command *cmd)
Obtain what command the batch is at.
struct GNUNET_TESTING_Interpreter * is
The interpreter of the test.
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
void * cls
Closure for all commands with command-specific context information.
int(* finish)(void *cls, GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls)
Wait for any asynchronous execution of run to conclude, then call finish_cont.
void GNUNET_TESTING_interpreter_fail()
Current command failed, clean up and fail the test case.
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
void * cls
Closure for all commands with command-specific context information.
const struct GNUNET_TESTING_Command * sync_cmd
The synchronous command that waits for the asynchronous command.
int result
Result of the testcases, GNUNET_OK on success.
Definition: testing.h:72
struct GNUNET_SCHEDULER_Task * timeout_task
Task run on timeout.
Definition: testing.h:60
Time for absolute times used by GNUnet, in microseconds.
unsigned int num_tries
How often did we try to execute this command? (In case it is a request that is repated.) Note that a command must have some built-in retry mechanism for this value to be useful.
struct GNUNET_SCHEDULER_Task * finish_task
Task for running the finish function.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972