diff options
author | Christian Grothoff <christian@grothoff.org> | 2021-10-04 12:15:43 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-10-04 12:15:43 +0200 |
commit | f146e80752e73247acb9d6c7463188a82d26a774 (patch) | |
tree | 13ed03d817ce04daa133507778ac6a1b71bf147f /src/testing/testing_api_loop.c | |
parent | 7ecc3a03a0670a1620c603502c9958b95e6dc1d0 (diff) | |
download | gnunet-f146e80752e73247acb9d6c7463188a82d26a774.tar.gz gnunet-f146e80752e73247acb9d6c7463188a82d26a774.zip |
-taking a first stab at cleaning up the testing mess
Diffstat (limited to 'src/testing/testing_api_loop.c')
-rw-r--r-- | src/testing/testing_api_loop.c | 388 |
1 files changed, 100 insertions, 288 deletions
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c index 0c24c0e26..1c8eb1db6 100644 --- a/src/testing/testing_api_loop.c +++ b/src/testing/testing_api_loop.c | |||
@@ -24,67 +24,29 @@ | |||
24 | * @author Christian Grothoff (GNU Taler testing) | 24 | * @author Christian Grothoff (GNU Taler testing) |
25 | * @author Marcello Stanisci (GNU Taler testing) | 25 | * @author Marcello Stanisci (GNU Taler testing) |
26 | * @author t3sserakt | 26 | * @author t3sserakt |
27 | */ | 27 | * |
28 | * FIXME: | ||
29 | * - interpreter failure is NOT returned properly yet! | ||
30 | * - abuse of shutdown logic for interpreter termination | ||
31 | * => API design flaw to be fixed! | ||
32 | */ | ||
28 | #include "platform.h" | 33 | #include "platform.h" |
29 | #include "gnunet_util_lib.h" | 34 | #include "gnunet_util_lib.h" |
30 | #include "gnunet_testing_ng_lib.h" | 35 | #include "gnunet_testing_ng_lib.h" |
31 | #include "testing.h" | 36 | #include "testing.h" |
32 | 37 | ||
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 | 38 | ||
80 | /** | 39 | /** |
81 | * Lookup command by label. | 40 | * Lookup command by label. |
82 | * | 41 | * |
42 | * @param is interpreter to lookup command in | ||
83 | * @param label label to look for | 43 | * @param label label to look for |
84 | * @return NULL if command was not found | 44 | * @return NULL if command was not found |
85 | */ | 45 | */ |
86 | const struct GNUNET_TESTING_Command * | 46 | const struct GNUNET_TESTING_Command * |
87 | GNUNET_TESTING_interpreter_lookup_command (const char *label) | 47 | GNUNET_TESTING_interpreter_lookup_command ( |
48 | struct GNUNET_TESTING_Interpreter *is, | ||
49 | const char *label) | ||
88 | { | 50 | { |
89 | if (NULL == label) | 51 | if (NULL == label) |
90 | { | 52 | { |
@@ -189,210 +151,35 @@ interpreter_next (void *cls) | |||
189 | 151 | ||
190 | 152 | ||
191 | /** | 153 | /** |
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. | 154 | * Current command failed, clean up and fail the test case. |
352 | * | 155 | * |
353 | * @param is interpreter of the test | 156 | * @param is interpreter of the test |
354 | */ | 157 | */ |
355 | void | 158 | void |
356 | GNUNET_TESTING_interpreter_fail () | 159 | GNUNET_TESTING_interpreter_fail (struct GNUNET_TESTING_Interpreter *is) |
357 | { | 160 | { |
358 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; | 161 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; |
359 | 162 | ||
360 | if (GNUNET_SYSERR == is->result) | 163 | if (GNUNET_SYSERR == is->result) |
361 | return; /* ignore, we already failed! */ | 164 | return; /* ignore, we already failed! */ |
362 | |||
363 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
364 | "interpreter_fail!\n"); | ||
365 | |||
366 | if (NULL != cmd) | 165 | if (NULL != cmd) |
367 | { | 166 | { |
167 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
168 | "Failed at command `%s'\n", | ||
169 | cmd->label); | ||
368 | while (GNUNET_TESTING_cmd_is_batch (cmd)) | 170 | while (GNUNET_TESTING_cmd_is_batch (cmd)) |
369 | { | 171 | { |
370 | cmd = GNUNET_TESTING_cmd_batch_get_current (cmd); | 172 | cmd = GNUNET_TESTING_cmd_batch_get_current (cmd); |
371 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 173 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
372 | "Batch is at command `%s'\n", | 174 | "Failed in batch at command `%s'\n", |
373 | cmd->label); | 175 | cmd->label); |
374 | } | 176 | } |
375 | |||
376 | } | 177 | } |
377 | else | 178 | else |
378 | { | 179 | { |
379 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 180 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
380 | "cmd is NULL.\n"); | 181 | "Failed with CMD being 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 | } | 182 | } |
395 | |||
396 | is->result = GNUNET_SYSERR; | 183 | is->result = GNUNET_SYSERR; |
397 | GNUNET_SCHEDULER_shutdown (); | 184 | GNUNET_SCHEDULER_shutdown (); |
398 | } | 185 | } |
@@ -406,8 +193,9 @@ GNUNET_TESTING_interpreter_fail () | |||
406 | struct GNUNET_TESTING_Command | 193 | struct GNUNET_TESTING_Command |
407 | GNUNET_TESTING_cmd_end (void) | 194 | GNUNET_TESTING_cmd_end (void) |
408 | { | 195 | { |
409 | static struct GNUNET_TESTING_Command cmd; | 196 | static struct GNUNET_TESTING_Command cmd = { |
410 | cmd.label = NULL; | 197 | .label = NULL |
198 | }; | ||
411 | 199 | ||
412 | return cmd; | 200 | return cmd; |
413 | } | 201 | } |
@@ -417,8 +205,8 @@ GNUNET_TESTING_cmd_end (void) | |||
417 | * Obtain current label. | 205 | * Obtain current label. |
418 | */ | 206 | */ |
419 | const char * | 207 | const char * |
420 | GNUNET_TESTING_interpreter_get_current_label (struct | 208 | GNUNET_TESTING_interpreter_get_current_label ( |
421 | GNUNET_TESTING_Interpreter *is) | 209 | struct GNUNET_TESTING_Interpreter *is) |
422 | { | 210 | { |
423 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; | 211 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; |
424 | 212 | ||
@@ -434,46 +222,36 @@ GNUNET_TESTING_interpreter_get_current_label (struct | |||
434 | static void | 222 | static void |
435 | interpreter_run (void *cls) | 223 | interpreter_run (void *cls) |
436 | { | 224 | { |
437 | struct FinishTaskClosure *ftc; | ||
438 | struct GNUNET_TESTING_Interpreter *is = cls; | 225 | struct GNUNET_TESTING_Interpreter *is = cls; |
439 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; | 226 | struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip]; |
440 | 227 | ||
441 | is->task = NULL; | 228 | is->task = NULL; |
442 | |||
443 | if (NULL == cmd->label) | 229 | if (NULL == cmd->label) |
444 | { | 230 | { |
445 | |||
446 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 231 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
447 | "Running command END %p\n", | 232 | "Running command END\n"); |
448 | is); | ||
449 | is->result = GNUNET_OK; | 233 | is->result = GNUNET_OK; |
450 | GNUNET_SCHEDULER_shutdown (); | 234 | GNUNET_SCHEDULER_shutdown (); |
451 | return; | 235 | return; |
452 | } | 236 | } |
453 | else if (NULL != cmd) | 237 | if (NULL != cmd) |
454 | { | 238 | { |
455 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 239 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
456 | "Running command `%s' %p\n", | 240 | "Running command `%s'\n", |
457 | cmd->label, | 241 | cmd->label); |
458 | is); | ||
459 | } | 242 | } |
460 | cmd->start_time | 243 | cmd->start_time |
461 | = cmd->last_req_time | 244 | = cmd->last_req_time |
462 | = GNUNET_TIME_absolute_get (); | 245 | = GNUNET_TIME_absolute_get (); |
463 | cmd->num_tries = 1; | 246 | cmd->num_tries = 1; |
464 | cmd->run (cmd->cls, | 247 | cmd->run (cmd->cls, |
465 | cmd, | ||
466 | is); | 248 | is); |
467 | if ((NULL != cmd->finish) && (GNUNET_NO == cmd->asynchronous_finish)) | 249 | if ( (NULL != cmd->finish) && |
250 | (! cmd->asynchronous_finish) ) | ||
468 | { | 251 | { |
469 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 252 | cmd->finish (cmd->cls, |
470 | "Next task will not be called directly!\n"); | 253 | &interpreter_next, |
471 | ftc = GNUNET_new (struct FinishTaskClosure); | 254 | is); |
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 | } | 255 | } |
478 | else | 256 | else |
479 | { | 257 | { |
@@ -491,37 +269,33 @@ interpreter_run (void *cls) | |||
491 | static void | 269 | static void |
492 | do_shutdown (void *cls) | 270 | do_shutdown (void *cls) |
493 | { | 271 | { |
494 | (void) cls; | 272 | struct GNUNET_TESTING_Interpreter *is = cls; |
495 | struct GNUNET_TESTING_Command *cmd; | 273 | struct GNUNET_TESTING_Command *cmd; |
496 | const char *label; | 274 | const char *label; |
497 | 275 | ||
498 | label = is->commands[is->ip].label; | 276 | label = is->commands[is->ip].label; |
499 | if (NULL == label) | 277 | if (NULL == label) |
500 | label = "END"; | 278 | label = "END"; |
501 | |||
502 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 279 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
503 | "Executing shutdown at `%s'\n", | 280 | "Executing shutdown at `%s'\n", |
504 | label); | 281 | label); |
505 | |||
506 | for (unsigned int j = 0; | 282 | for (unsigned int j = 0; |
507 | NULL != (cmd = &is->commands[j])->label; | 283 | NULL != (cmd = &is->commands[j])->label; |
508 | j++) { | 284 | j++) |
285 | { | ||
509 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 286 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
510 | "Cleaning up cmd %s\n", | 287 | "Cleaning up cmd %s\n", |
511 | cmd->label); | 288 | cmd->label); |
512 | cmd->cleanup (cmd->cls, | 289 | cmd->cleanup (cmd->cls); |
513 | cmd); | ||
514 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 290 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
515 | "Cleaned up cmd %s\n", | 291 | "Cleaned up cmd %s\n", |
516 | cmd->label); | 292 | cmd->label); |
517 | } | 293 | } |
518 | |||
519 | if (NULL != is->finish_task) | 294 | if (NULL != is->finish_task) |
520 | { | 295 | { |
521 | GNUNET_SCHEDULER_cancel (is->finish_task); | 296 | GNUNET_SCHEDULER_cancel (is->finish_task); |
522 | cmd->finish_task = NULL; | 297 | is->finish_task = NULL; |
523 | } | 298 | } |
524 | |||
525 | if (NULL != is->task) | 299 | if (NULL != is->task) |
526 | { | 300 | { |
527 | GNUNET_SCHEDULER_cancel (is->task); | 301 | GNUNET_SCHEDULER_cancel (is->task); |
@@ -533,18 +307,19 @@ do_shutdown (void *cls) | |||
533 | is->timeout_task = NULL; | 307 | is->timeout_task = NULL; |
534 | } | 308 | } |
535 | GNUNET_free (is->commands); | 309 | GNUNET_free (is->commands); |
310 | GNUNET_free (is); | ||
536 | } | 311 | } |
537 | 312 | ||
538 | 313 | ||
539 | /** | 314 | /** |
540 | * Function run when the test terminates (good or bad) with timeout. | 315 | * Function run when the test terminates (good or bad) with timeout. |
541 | * | 316 | * |
542 | * @param cls NULL | 317 | * @param cls the interpreter state |
543 | */ | 318 | */ |
544 | static void | 319 | static void |
545 | do_timeout (void *cls) | 320 | do_timeout (void *cls) |
546 | { | 321 | { |
547 | (void) cls; | 322 | struct GNUNET_TESTING_Interpreter *is = cls; |
548 | 323 | ||
549 | is->timeout_task = NULL; | 324 | is->timeout_task = NULL; |
550 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 325 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
@@ -553,30 +328,15 @@ do_timeout (void *cls) | |||
553 | } | 328 | } |
554 | 329 | ||
555 | 330 | ||
556 | /** | 331 | enum GNUNET_GenericReturnValue |
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, | 332 | GNUNET_TESTING_run (const char *cfg_filename, |
568 | struct GNUNET_TESTING_Command *commands, | 333 | struct GNUNET_TESTING_Command *commands, |
569 | struct GNUNET_TIME_Relative timeout) | 334 | struct GNUNET_TIME_Relative timeout) |
570 | { | 335 | { |
336 | struct GNUNET_TESTING_Interpreter *is; | ||
571 | unsigned int i; | 337 | unsigned int i; |
572 | 338 | ||
573 | is = GNUNET_new (struct GNUNET_TESTING_Interpreter); | 339 | 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 */ | 340 | /* get the number of commands */ |
581 | for (i = 0; NULL != commands[i].label; i++) | 341 | for (i = 0; NULL != commands[i].label; i++) |
582 | ; | 342 | ; |
@@ -585,15 +345,67 @@ GNUNET_TESTING_run (const char *cfg_filename, | |||
585 | memcpy (is->commands, | 345 | memcpy (is->commands, |
586 | commands, | 346 | commands, |
587 | sizeof (struct GNUNET_TESTING_Command) * i); | 347 | sizeof (struct GNUNET_TESTING_Command) * i); |
588 | 348 | is->timeout_task | |
589 | is->timeout_task = GNUNET_SCHEDULER_add_delayed | 349 | = GNUNET_SCHEDULER_add_delayed (timeout, |
590 | (timeout, | 350 | &do_timeout, |
591 | &do_timeout, | 351 | is); |
592 | is); | 352 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, |
593 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is); | 353 | is); |
594 | is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is); | 354 | is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, |
355 | is); | ||
595 | return GNUNET_OK; | 356 | return GNUNET_OK; |
596 | } | 357 | } |
597 | 358 | ||
598 | 359 | ||
360 | /** | ||
361 | * Closure for #loop_run(). | ||
362 | */ | ||
363 | struct MainParams | ||
364 | { | ||
365 | const char *cfg_filename; | ||
366 | struct GNUNET_TESTING_Command *commands; | ||
367 | struct GNUNET_TIME_Relative timeout; | ||
368 | int rv; | ||
369 | }; | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Main function to run the test cases. | ||
374 | * | ||
375 | * @param cls a `struct MainParams *` | ||
376 | */ | ||
377 | static void | ||
378 | loop_run (void *cls) | ||
379 | { | ||
380 | struct MainParams *mp = cls; | ||
381 | |||
382 | if (GNUNET_OK != | ||
383 | GNUNET_TESTING_run (mp->cfg_filename, | ||
384 | mp->commands, | ||
385 | mp->timeout)) | ||
386 | { | ||
387 | GNUNET_break (0); | ||
388 | mp->rv = EXIT_FAILURE; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | |||
393 | int | ||
394 | GNUNET_TESTING_main (const char *cfg_filename, | ||
395 | struct GNUNET_TESTING_Command *commands, | ||
396 | struct GNUNET_TIME_Relative timeout) | ||
397 | { | ||
398 | struct MainParams mp = { | ||
399 | .cfg_filename = cfg_filename, | ||
400 | .commands = commands, | ||
401 | .timeout = timeout, | ||
402 | .rv = EXIT_SUCCESS | ||
403 | }; | ||
404 | |||
405 | GNUNET_SCHEDULER_run (&loop_run, | ||
406 | &mp); | ||
407 | return mp.rv; | ||
408 | } | ||
409 | |||
410 | |||
599 | /* end of testing_api_loop.c */ | 411 | /* end of testing_api_loop.c */ |