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 
34 
39 {
40 
45 
50 
55 };
56 
61 {
62 
66  const struct GNUNET_TESTING_Command *cmd;
67 
72 };
73 
80 const struct GNUNET_TESTING_Command *
82 {
83  if (NULL == label)
84  {
86  "Attempt to lookup command for empty label\n");
87  return NULL;
88  }
89  /* Search backwards as we most likely reference recent commands */
90  for (int i = is->ip; i >= 0; i--)
91  {
92  const struct GNUNET_TESTING_Command *cmd = &is->commands[i];
93 
94  /* Give precedence to top-level commands. */
95  if ( (NULL != cmd->label) &&
96  (0 == strcmp (cmd->label,
97  label)) )
98  return cmd;
99 
100  if (GNUNET_TESTING_cmd_is_batch (cmd))
101  {
102 #define BATCH_INDEX 1
103  struct GNUNET_TESTING_Command *batch;
104  struct GNUNET_TESTING_Command *current;
105  struct GNUNET_TESTING_Command *icmd;
106  const struct GNUNET_TESTING_Command *match;
107 
108  current = GNUNET_TESTING_cmd_batch_get_current (cmd);
111  BATCH_INDEX,
112  &batch));
113  /* We must do the loop forward, but we can find the last match */
114  match = NULL;
115  for (unsigned int j = 0;
116  NULL != (icmd = &batch[j])->label;
117  j++)
118  {
119  if (current == icmd)
120  break; /* do not go past current command */
121  if ( (NULL != icmd->label) &&
122  (0 == strcmp (icmd->label,
123  label)) )
124  match = icmd;
125  }
126  if (NULL != match)
127  return match;
128  }
129  }
131  "Command not found: %s\n",
132  label);
133  return NULL;
134 
135 }
136 
137 
143 static void
144 interpreter_run (void *cls);
145 
146 
150 static void
152 {
153  struct GNUNET_TESTING_Interpreter *is = cls;
154  static unsigned long long ipc;
155  static struct GNUNET_TIME_Absolute last_report;
156  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
157 
158  if (GNUNET_SYSERR == is->result)
159  return; /* ignore, we already failed! */
160  if (GNUNET_TESTING_cmd_is_batch (cmd))
161  {
163  }
164  else
165  {
167  is->ip++;
168  }
169  if (0 == (ipc % 1000))
170  {
171  if (0 != ipc)
173  "Interpreter executed 1000 instructions in %s\n",
175  GNUNET_TIME_absolute_get_duration (last_report),
176  GNUNET_YES));
177  last_report = GNUNET_TIME_absolute_get ();
178  }
179  ipc++;
181  is);
182 }
183 
184 
185 static void
187 {
188  struct FinishTaskClosure *ftc = cls;
189  const struct GNUNET_TESTING_Command *cmd = ftc->cmd;
190  struct GNUNET_TESTING_Interpreter *is = ftc->is;
191 
192  if (cmd->finish (cmd->cls, &interpreter_next, is))
193  {
195  }
196  else
197  {
198  is->finish_task = NULL;
199  }
200 
201 }
202 
203 
204 static void
206 {
207  struct SyncTaskClosure *stc = cls;
208  const struct GNUNET_TESTING_Command *cmd = stc->async_cmd;
209  const struct GNUNET_TESTING_Command *sync_cmd = stc->sync_cmd;
210  struct FinishTaskClosure *ftc;
211  struct SyncState *sync_state = sync_cmd->cls;
212  struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task;
213 
214  GNUNET_assert (NULL != finish_task);
215  ftc = GNUNET_new (struct FinishTaskClosure);
216  ftc->cmd = stc->sync_cmd;
217  ftc->is = stc->is;
220  - sync_state->start_finish_time.abs_value_us)
221  {
223  "The command with label %s did not finish its asynchronous task in time.\n",
224  cmd->label);
225  is->result = GNUNET_SYSERR;
227  }
228 
229  if (cmd->finish (cmd->cls, run_finish_task_next, ftc))
230  {
231  finish_task = GNUNET_SCHEDULER_add_now (&run_finish_task_sync, stc);
232  }
233  else
234  {
235  finish_task = NULL;
236  }
237 }
238 
239 
240 static void
242  const struct GNUNET_TESTING_Command *cmd,
243  struct GNUNET_TESTING_Interpreter *is)
244 {
245  struct SyncState *sync_state = cls;
246  struct SyncTaskClosure *stc;
247  const struct GNUNET_TESTING_Command *async_cmd;
248 
249  async_cmd = sync_state->async_cmd;
250  stc = GNUNET_new (struct SyncTaskClosure);
251  stc->async_cmd = async_cmd;
252  stc->sync_cmd = cmd;
253  stc->is = is;
256  stc);
257 }
258 
259 
260 const struct GNUNET_TESTING_Command
261 GNUNET_TESTING_cmd_finish (const char *finish_label,
262  const char *cmd_ref,
264 {
265  const struct GNUNET_TESTING_Command *async_cmd;
266  struct SyncState *sync_state;
267 
268  async_cmd = GNUNET_TESTING_interpreter_lookup_command (cmd_ref);
269  sync_state = GNUNET_new (struct SyncState);
270  sync_state->async_cmd = async_cmd;
271 
272  struct GNUNET_TESTING_Command cmd = {
273  .cls = sync_state,
274  .label = finish_label,
276  .asynchronous_finish = GNUNET_NO
277  };
278 
279  return cmd;
280 }
281 
282 
283 const struct GNUNET_TESTING_Command
285 {
286 
287  GNUNET_assert (NULL != cmd.finish);
288  const struct GNUNET_TESTING_Command async_cmd = {
289  .cls = cmd.cls,
290  .label = cmd.label,
291  .run = cmd.run,
292  .cleanup = cmd.cleanup,
293  .traits = cmd.traits,
294  .finish = cmd.finish,
295  .asynchronous_finish = GNUNET_YES
296  };
297 
298  return async_cmd;
299 }
300 
301 
307 void
309 {
310  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
311 
313  "Failed at command `%s'\n",
314  cmd->label);
315  while (GNUNET_TESTING_cmd_is_batch (cmd))
316  {
319  "Batch is at command `%s'\n",
320  cmd->label);
321  }
322  is->result = GNUNET_SYSERR;
324 }
325 
326 
334 {
335  static struct GNUNET_TESTING_Command cmd;
336  cmd.label = NULL;
337 
338  return cmd;
339 }
340 
341 
345 const char *
348 {
349  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
350 
351  return cmd->label;
352 }
353 
354 
360 static void
362 {
363  struct FinishTaskClosure *ftc;
364  struct GNUNET_TESTING_Interpreter *is = cls;
365  struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
366 
367  is->task = NULL;
368 
369  if (NULL == cmd->label)
370  {
371 
373  "Running command END\n");
374  is->result = GNUNET_OK;
376  return;
377  }
378 
380  "Running command `%s'\n",
381  cmd->label);
382  cmd->start_time
383  = cmd->last_req_time
385  cmd->num_tries = 1;
386  cmd->run (cmd->cls,
387  cmd,
388  is);
389  if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish))
390  {
391  ftc = GNUNET_new (struct FinishTaskClosure);
392  ftc->cmd = cmd;
393  ftc->is = is;
395  }
396  else
397  {
398  interpreter_next (is);
399  }
400 }
401 
402 
409 static void
411 {
412  (void) cls;
413  struct GNUNET_TESTING_Command *cmd;
414  const char *label;
415 
416  label = is->commands[is->ip].label;
417  if (NULL == label)
418  label = "END";
419 
421  "Executing shutdown at `%s'\n",
422  label);
423 
424  for (unsigned int j = 0;
425  NULL != (cmd = &is->commands[j])->label;
426  j++) {
427  cmd->cleanup (cmd->cls,
428  cmd);
429  if (NULL != cmd->finish_task)
430  {
432  cmd->finish_task = NULL;
433  }
434  }
435 
436  if (NULL != is->task)
437  {
439  is->task = NULL;
440  }
441  if (NULL != is->timeout_task)
442  {
444  is->timeout_task = NULL;
445  }
446  GNUNET_free (is->commands);
447 }
448 
449 
455 static void
457 {
458  (void) cls;
459 
460  is->timeout_task = NULL;
462  "Terminating test due to timeout\n");
464 }
465 
466 
477 int
481 {
482  unsigned int i;
483 
485 
486  if (NULL != is->timeout_task)
487  {
489  is->timeout_task = NULL;
490  }
491  /* get the number of commands */
492  for (i = 0; NULL != commands[i].label; i++)
493  ;
494  is->commands = GNUNET_new_array (i + 1,
495  struct GNUNET_TESTING_Command);
496  memcpy (is->commands,
497  commands,
498  sizeof (struct GNUNET_TESTING_Command) * i);
499 
501  (timeout,
502  &do_timeout,
503  is);
506  return GNUNET_OK;
507 }
508 
509 
510 /* end of testing_api_loop.c */
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.
bool(* finish)(void *cls, GNUNET_SCHEDULER_TaskCallback cont, void *cont_cls)
Wait for any asynchronous execution of run to conclude, then call finish_cont.
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
void GNUNET_TESTING_interpreter_fail(struct GNUNET_TESTING_Interpreter *is)
Current command failed, clean up and fail the test case.
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
const struct GNUNET_TESTING_Command GNUNET_TESTING_cmd_make_asynchronous(const struct GNUNET_TESTING_Command cmd)
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:702
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.
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.
#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