diff options
Diffstat (limited to 'src/testing/testing_api_loop.c')
-rw-r--r-- | src/testing/testing_api_loop.c | 599 |
1 files changed, 0 insertions, 599 deletions
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c deleted file mode 100644 index 0c24c0e26..000000000 --- a/src/testing/testing_api_loop.c +++ /dev/null | |||
@@ -1,599 +0,0 @@ | |||
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 | |||
21 | /** | ||
22 | * @file testing/testing_api_loop.c | ||
23 | * @brief main interpreter loop for testcases | ||
24 | * @author Christian Grothoff (GNU Taler testing) | ||
25 | * @author Marcello Stanisci (GNU Taler testing) | ||
26 | * @author t3sserakt | ||
27 | */ | ||
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 | |||
36 | struct GNUNET_TESTING_Interpreter *is; | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Closure used to sync an asynchronous with an synchronous command. | ||
41 | */ | ||
42 | struct SyncTaskClosure | ||
43 | { | ||
44 | |||
45 | /** | ||
46 | * The asynchronous command the synchronous command waits for. | ||
47 | */ | ||
48 | const struct GNUNET_TESTING_Command *async_cmd; | ||
49 | |||
50 | /** | ||
51 | * The synchronous command that waits for the asynchronous command. | ||
52 | */ | ||
53 | const struct GNUNET_TESTING_Command *sync_cmd; | ||
54 | |||
55 | /** | ||
56 | * The interpreter of the test. | ||
57 | */ | ||
58 | struct GNUNET_TESTING_Interpreter *is; | ||
59 | }; | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Closure used to run the finish task. | ||
64 | */ | ||
65 | struct FinishTaskClosure | ||
66 | { | ||
67 | |||
68 | /** | ||
69 | * The asynchronous command the synchronous command waits for. | ||
70 | */ | ||
71 | const struct GNUNET_TESTING_Command *cmd; | ||
72 | |||
73 | /** | ||
74 | * The interpreter of the test. | ||
75 | */ | ||
76 | struct GNUNET_TESTING_Interpreter *is; | ||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Lookup command by label. | ||
82 | * | ||
83 | * @param label label to look for | ||
84 | * @return NULL if command was not found | ||
85 | */ | ||
86 | const struct GNUNET_TESTING_Command * | ||
87 | GNUNET_TESTING_interpreter_lookup_command (const char *label) | ||
88 | { | ||
89 | if (NULL == label) | ||
90 | { | ||
91 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
92 | "Attempt to lookup command for empty label\n"); | ||
93 | return NULL; | ||
94 | } | ||
95 | /* Search backwards as we most likely reference recent commands */ | ||
96 | for (int i = is->ip; i >= 0; i--) | ||
97 | { | ||
98 | const struct GNUNET_TESTING_Command *cmd = &is->commands[i]; | ||
99 | |||
100 | /* Give precedence to top-level commands. */ | ||
101 | if ( (NULL != cmd->label) && | ||
102 | (0 == strcmp (cmd->label, | ||
103 | label)) ) | ||
104 | return cmd; | ||
105 | |||
106 | if (GNUNET_TESTING_cmd_is_batch (cmd)) | ||
107 | { | ||
108 | #define BATCH_INDEX 1 | ||
109 | struct GNUNET_TESTING_Command *batch; | ||
110 | struct GNUNET_TESTING_Command *current; | ||
111 | struct GNUNET_TESTING_Command *icmd; | ||
112 | const struct GNUNET_TESTING_Command *match; | ||
113 | |||
114 | current = GNUNET_TESTING_cmd_batch_get_current (cmd); | ||
115 | GNUNET_assert (GNUNET_OK == | ||
116 | GNUNET_TESTING_get_trait_cmd (cmd, | ||
117 | BATCH_INDEX, | ||
118 | &batch)); | ||
119 | /* We must do the loop forward, but we can find the last match */ | ||
120 | match = NULL; | ||
121 | for (unsigned int j = 0; | ||
122 | NULL != (icmd = &batch[j])->label; | ||
123 | j++) | ||
124 | { | ||
125 | if (current == icmd) | ||
126 | break; /* do not go past current command */ | ||
127 | if ( (NULL != icmd->label) && | ||
128 | (0 == strcmp (icmd->label, | ||
129 | label)) ) | ||
130 | match = icmd; | ||
131 | } | ||
132 | if (NULL != match) | ||
133 | return match; | ||
134 | } | ||
135 | } | ||
136 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
137 | "Command not found: %s\n", | ||
138 | label); | ||
139 | return NULL; | ||
140 | |||
141 | } | ||
142 | |||
143 | |||
144 | /** | ||
145 | * Run the main interpreter loop that performs exchange operations. | ||
146 | * | ||
147 | * @param cls contains the `struct InterpreterState` | ||
148 | */ | ||
149 | static void | ||
150 | interpreter_run (void *cls); | ||
151 | |||
152 | |||
153 | /** | ||
154 | * Current command is done, run the next one. | ||
155 | */ | ||
156 | static void | ||
157 | interpreter_next (void *cls) | ||
158 | { | ||
159 | struct GNUNET_TESTING_Interpreter *is = cls; | ||
160 | static unsigned long long ipc; | ||
161 | static struct GNUNET_TIME_Absolute last_report; | ||
162 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; | ||
163 | |||
164 | if (GNUNET_SYSERR == is->result) | ||
165 | return; /* ignore, we already failed! */ | ||
166 | if (GNUNET_TESTING_cmd_is_batch (cmd)) | ||
167 | { | ||
168 | GNUNET_TESTING_cmd_batch_next (is); | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | cmd->finish_time = GNUNET_TIME_absolute_get (); | ||
173 | is->ip++; | ||
174 | } | ||
175 | if (0 == (ipc % 1000)) | ||
176 | { | ||
177 | if (0 != ipc) | ||
178 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
179 | "Interpreter executed 1000 instructions in %s\n", | ||
180 | GNUNET_STRINGS_relative_time_to_string ( | ||
181 | GNUNET_TIME_absolute_get_duration (last_report), | ||
182 | GNUNET_YES)); | ||
183 | last_report = GNUNET_TIME_absolute_get (); | ||
184 | } | ||
185 | ipc++; | ||
186 | is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, | ||
187 | is); | ||
188 | } | ||
189 | |||
190 | |||
191 | /** | ||
192 | * This function checks if the finish function of a command returns GNUNET_YES, when the command is finished. In this case the finish function might have called interpreter_next. IF GNUNET_NO was returned this function is added to the scheduler again. In case of an error interpreter_fail is called. | ||
193 | * | ||
194 | */ | ||
195 | static void | ||
196 | run_finish_task_next (void *cls) | ||
197 | { | ||
198 | struct FinishTaskClosure *ftc = cls; | ||
199 | const struct GNUNET_TESTING_Command *cmd = ftc->cmd; | ||
200 | struct GNUNET_TESTING_Interpreter *is = ftc->is; | ||
201 | unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is); | ||
202 | |||
203 | if (GNUNET_YES == finished) | ||
204 | { | ||
205 | is->finish_task = NULL; | ||
206 | } | ||
207 | else if (GNUNET_NO == finished) | ||
208 | { | ||
209 | is->finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD, | ||
210 | &run_finish_task_next, ftc); | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
215 | "Next task finished with an error.\n"); | ||
216 | GNUNET_TESTING_interpreter_fail (); | ||
217 | } | ||
218 | |||
219 | } | ||
220 | |||
221 | |||
222 | /** | ||
223 | * This function checks if the finish function of an asynchronous command returns GNUNET_YES, when the command is finished. In this case the finish function might have called interpreter_next. IF GNUNET_NO was returned this function is added to the scheduler again. In case of an error interpreter_fail is called. | ||
224 | * | ||
225 | * //TODO run_finish_task_next and this function can be merged. | ||
226 | * | ||
227 | */ | ||
228 | static void | ||
229 | run_finish_task_sync (void *cls) | ||
230 | { | ||
231 | struct SyncTaskClosure *stc = cls; | ||
232 | const struct GNUNET_TESTING_Command *cmd = stc->async_cmd; | ||
233 | const struct GNUNET_TESTING_Command *sync_cmd = stc->sync_cmd; | ||
234 | struct FinishTaskClosure *ftc; | ||
235 | struct SyncState *sync_state = sync_cmd->cls; | ||
236 | struct GNUNET_SCHEDULER_Task *finish_task = sync_state->finish_task; | ||
237 | unsigned int finished = cmd->finish (cmd->cls, &interpreter_next, is); | ||
238 | |||
239 | GNUNET_assert (NULL != finish_task); | ||
240 | ftc = GNUNET_new (struct FinishTaskClosure); | ||
241 | ftc->cmd = stc->sync_cmd; | ||
242 | ftc->is = stc->is; | ||
243 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
244 | if (cmd->default_timeout.rel_value_us < now.abs_value_us | ||
245 | - sync_state->start_finish_time.abs_value_us) | ||
246 | { | ||
247 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
248 | "The command with label %s did not finish its asynchronous task in time.\n", | ||
249 | cmd->label); | ||
250 | GNUNET_TESTING_interpreter_fail (); | ||
251 | } | ||
252 | |||
253 | if (GNUNET_YES == finished) | ||
254 | { | ||
255 | finish_task = NULL; | ||
256 | } | ||
257 | else if (GNUNET_NO == finished) | ||
258 | { | ||
259 | finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD, | ||
260 | &run_finish_task_sync, stc); | ||
261 | } | ||
262 | else | ||
263 | { | ||
264 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
265 | "Sync task finished with an error.\n"); | ||
266 | GNUNET_TESTING_interpreter_fail (); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | |||
271 | /** | ||
272 | * run method of the command created by the interpreter to wait for another command to finish. | ||
273 | * | ||
274 | */ | ||
275 | static void | ||
276 | start_finish_on_ref (void *cls, | ||
277 | const struct GNUNET_TESTING_Command *cmd, | ||
278 | struct GNUNET_TESTING_Interpreter *is) | ||
279 | { | ||
280 | struct SyncState *sync_state = cls; | ||
281 | struct SyncTaskClosure *stc; | ||
282 | const struct GNUNET_TESTING_Command *async_cmd; | ||
283 | |||
284 | async_cmd = sync_state->async_cmd; | ||
285 | stc = GNUNET_new (struct SyncTaskClosure); | ||
286 | stc->async_cmd = async_cmd; | ||
287 | stc->sync_cmd = cmd; | ||
288 | stc->is = is; | ||
289 | sync_state->start_finish_time = GNUNET_TIME_absolute_get (); | ||
290 | sync_state->finish_task = GNUNET_SCHEDULER_add_delayed ( | ||
291 | CHECK_FINISHED_PERIOD, | ||
292 | &run_finish_task_sync, | ||
293 | stc); | ||
294 | } | ||
295 | |||
296 | |||
297 | /** | ||
298 | * Create (synchronous) command that waits for another command to finish. | ||
299 | * If @a cmd_ref did not finish after @a timeout, this command will fail | ||
300 | * the test case. | ||
301 | * | ||
302 | * @param finish_label label for this command | ||
303 | * @param cmd_ref reference to a previous command which we should | ||
304 | * wait for (call `finish()` on) | ||
305 | * @param timeout how long to wait at most for @a cmd_ref to finish | ||
306 | * @return a finish-command. | ||
307 | */ | ||
308 | const struct GNUNET_TESTING_Command | ||
309 | GNUNET_TESTING_cmd_finish (const char *finish_label, | ||
310 | const char *cmd_ref, | ||
311 | struct GNUNET_TIME_Relative timeout) | ||
312 | { | ||
313 | const struct GNUNET_TESTING_Command *async_cmd; | ||
314 | struct SyncState *sync_state; | ||
315 | |||
316 | async_cmd = GNUNET_TESTING_interpreter_lookup_command (cmd_ref); | ||
317 | sync_state = GNUNET_new (struct SyncState); | ||
318 | sync_state->async_cmd = async_cmd; | ||
319 | |||
320 | struct GNUNET_TESTING_Command cmd = { | ||
321 | .cls = sync_state, | ||
322 | .label = finish_label, | ||
323 | .run = &start_finish_on_ref, | ||
324 | .asynchronous_finish = GNUNET_NO | ||
325 | }; | ||
326 | |||
327 | return cmd; | ||
328 | } | ||
329 | |||
330 | |||
331 | const struct GNUNET_TESTING_Command | ||
332 | GNUNET_TESTING_cmd_make_unblocking (const struct GNUNET_TESTING_Command cmd) | ||
333 | { | ||
334 | |||
335 | GNUNET_assert (NULL != cmd.finish); | ||
336 | const struct GNUNET_TESTING_Command async_cmd = { | ||
337 | .cls = cmd.cls, | ||
338 | .label = cmd.label, | ||
339 | .run = cmd.run, | ||
340 | .cleanup = cmd.cleanup, | ||
341 | .traits = cmd.traits, | ||
342 | .finish = cmd.finish, | ||
343 | .asynchronous_finish = GNUNET_YES | ||
344 | }; | ||
345 | |||
346 | return async_cmd; | ||
347 | } | ||
348 | |||
349 | |||
350 | /** | ||
351 | * Current command failed, clean up and fail the test case. | ||
352 | * | ||
353 | * @param is interpreter of the test | ||
354 | */ | ||
355 | void | ||
356 | GNUNET_TESTING_interpreter_fail () | ||
357 | { | ||
358 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; | ||
359 | |||
360 | if (GNUNET_SYSERR == is->result) | ||
361 | return; /* ignore, we already failed! */ | ||
362 | |||
363 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
364 | "interpreter_fail!\n"); | ||
365 | |||
366 | if (NULL != cmd) | ||
367 | { | ||
368 | while (GNUNET_TESTING_cmd_is_batch (cmd)) | ||
369 | { | ||
370 | cmd = GNUNET_TESTING_cmd_batch_get_current (cmd); | ||
371 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
372 | "Batch is at command `%s'\n", | ||
373 | cmd->label); | ||
374 | } | ||
375 | |||
376 | } | ||
377 | else | ||
378 | { | ||
379 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
380 | "cmd is NULL.\n"); | ||
381 | } | ||
382 | |||
383 | if (NULL == cmd->label) | ||
384 | { | ||
385 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
386 | "Failed at command `%s'\n", | ||
387 | cmd->label); | ||
388 | |||
389 | } | ||
390 | else | ||
391 | { | ||
392 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
393 | "cmd->label is NULL.\n"); | ||
394 | } | ||
395 | |||
396 | is->result = GNUNET_SYSERR; | ||
397 | GNUNET_SCHEDULER_shutdown (); | ||
398 | } | ||
399 | |||
400 | |||
401 | /** | ||
402 | * Create command array terminator. | ||
403 | * | ||
404 | * @return a end-command. | ||
405 | */ | ||
406 | struct GNUNET_TESTING_Command | ||
407 | GNUNET_TESTING_cmd_end (void) | ||
408 | { | ||
409 | static struct GNUNET_TESTING_Command cmd; | ||
410 | cmd.label = NULL; | ||
411 | |||
412 | return cmd; | ||
413 | } | ||
414 | |||
415 | |||
416 | /** | ||
417 | * Obtain current label. | ||
418 | */ | ||
419 | const char * | ||
420 | GNUNET_TESTING_interpreter_get_current_label (struct | ||
421 | GNUNET_TESTING_Interpreter *is) | ||
422 | { | ||
423 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; | ||
424 | |||
425 | return cmd->label; | ||
426 | } | ||
427 | |||
428 | |||
429 | /** | ||
430 | * Run the main interpreter loop. | ||
431 | * | ||
432 | * @param cls contains the `struct GNUNET_TESTING_Interpreter` | ||
433 | */ | ||
434 | static void | ||
435 | interpreter_run (void *cls) | ||
436 | { | ||
437 | struct FinishTaskClosure *ftc; | ||
438 | struct GNUNET_TESTING_Interpreter *is = cls; | ||
439 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; | ||
440 | |||
441 | is->task = NULL; | ||
442 | |||
443 | if (NULL == cmd->label) | ||
444 | { | ||
445 | |||
446 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
447 | "Running command END %p\n", | ||
448 | is); | ||
449 | is->result = GNUNET_OK; | ||
450 | GNUNET_SCHEDULER_shutdown (); | ||
451 | return; | ||
452 | } | ||
453 | else if (NULL != cmd) | ||
454 | { | ||
455 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
456 | "Running command `%s' %p\n", | ||
457 | cmd->label, | ||
458 | is); | ||
459 | } | ||
460 | cmd->start_time | ||
461 | = cmd->last_req_time | ||
462 | = GNUNET_TIME_absolute_get (); | ||
463 | cmd->num_tries = 1; | ||
464 | cmd->run (cmd->cls, | ||
465 | cmd, | ||
466 | is); | ||
467 | if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish)) | ||
468 | { | ||
469 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
470 | "Next task will not be called directly!\n"); | ||
471 | ftc = GNUNET_new (struct FinishTaskClosure); | ||
472 | ftc->cmd = cmd; | ||
473 | ftc->is = is; | ||
474 | is->finish_task = GNUNET_SCHEDULER_add_delayed (CHECK_FINISHED_PERIOD, | ||
475 | &run_finish_task_next, | ||
476 | ftc); | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | interpreter_next (is); | ||
481 | } | ||
482 | } | ||
483 | |||
484 | |||
485 | /** | ||
486 | * Function run when the test terminates (good or bad). | ||
487 | * Cleans up our state. | ||
488 | * | ||
489 | * @param cls the interpreter state. | ||
490 | */ | ||
491 | static void | ||
492 | do_shutdown (void *cls) | ||
493 | { | ||
494 | (void) cls; | ||
495 | struct GNUNET_TESTING_Command *cmd; | ||
496 | const char *label; | ||
497 | |||
498 | label = is->commands[is->ip].label; | ||
499 | if (NULL == label) | ||
500 | label = "END"; | ||
501 | |||
502 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
503 | "Executing shutdown at `%s'\n", | ||
504 | label); | ||
505 | |||
506 | for (unsigned int j = 0; | ||
507 | NULL != (cmd = &is->commands[j])->label; | ||
508 | j++) { | ||
509 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
510 | "Cleaning up cmd %s\n", | ||
511 | cmd->label); | ||
512 | cmd->cleanup (cmd->cls, | ||
513 | cmd); | ||
514 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
515 | "Cleaned up cmd %s\n", | ||
516 | cmd->label); | ||
517 | } | ||
518 | |||
519 | if (NULL != is->finish_task) | ||
520 | { | ||
521 | GNUNET_SCHEDULER_cancel (is->finish_task); | ||
522 | cmd->finish_task = NULL; | ||
523 | } | ||
524 | |||
525 | if (NULL != is->task) | ||
526 | { | ||
527 | GNUNET_SCHEDULER_cancel (is->task); | ||
528 | is->task = NULL; | ||
529 | } | ||
530 | if (NULL != is->timeout_task) | ||
531 | { | ||
532 | GNUNET_SCHEDULER_cancel (is->timeout_task); | ||
533 | is->timeout_task = NULL; | ||
534 | } | ||
535 | GNUNET_free (is->commands); | ||
536 | } | ||
537 | |||
538 | |||
539 | /** | ||
540 | * Function run when the test terminates (good or bad) with timeout. | ||
541 | * | ||
542 | * @param cls NULL | ||
543 | */ | ||
544 | static void | ||
545 | do_timeout (void *cls) | ||
546 | { | ||
547 | (void) cls; | ||
548 | |||
549 | is->timeout_task = NULL; | ||
550 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
551 | "Terminating test due to timeout\n"); | ||
552 | GNUNET_SCHEDULER_shutdown (); | ||
553 | } | ||
554 | |||
555 | |||
556 | /** | ||
557 | * Run the testsuite. Note, CMDs are copied into | ||
558 | * the interpreter state because they are _usually_ | ||
559 | * defined into the "run" method that returns after | ||
560 | * having scheduled the test interpreter. | ||
561 | * | ||
562 | * @param is the interpreter state | ||
563 | * @param commands the list of command to execute | ||
564 | * @param timeout how long to wait | ||
565 | */ | ||
566 | int | ||
567 | GNUNET_TESTING_run (const char *cfg_filename, | ||
568 | struct GNUNET_TESTING_Command *commands, | ||
569 | struct GNUNET_TIME_Relative timeout) | ||
570 | { | ||
571 | unsigned int i; | ||
572 | |||
573 | is = GNUNET_new (struct GNUNET_TESTING_Interpreter); | ||
574 | |||
575 | if (NULL != is->timeout_task) | ||
576 | { | ||
577 | GNUNET_SCHEDULER_cancel (is->timeout_task); | ||
578 | is->timeout_task = NULL; | ||
579 | } | ||
580 | /* get the number of commands */ | ||
581 | for (i = 0; NULL != commands[i].label; i++) | ||
582 | ; | ||
583 | is->commands = GNUNET_new_array (i + 1, | ||
584 | struct GNUNET_TESTING_Command); | ||
585 | memcpy (is->commands, | ||
586 | commands, | ||
587 | sizeof (struct GNUNET_TESTING_Command) * i); | ||
588 | |||
589 | is->timeout_task = GNUNET_SCHEDULER_add_delayed | ||
590 | (timeout, | ||
591 | &do_timeout, | ||
592 | is); | ||
593 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is); | ||
594 | is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is); | ||
595 | return GNUNET_OK; | ||
596 | } | ||
597 | |||
598 | |||
599 | /* end of testing_api_loop.c */ | ||