aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/gnunet_testing_ng_lib.h15
-rw-r--r--src/testing/testing_api_loop.c368
2 files changed, 26 insertions, 357 deletions
diff --git a/src/include/gnunet_testing_ng_lib.h b/src/include/gnunet_testing_ng_lib.h
index bfdce7557..0cc768d19 100644
--- a/src/include/gnunet_testing_ng_lib.h
+++ b/src/include/gnunet_testing_ng_lib.h
@@ -27,6 +27,7 @@
27#ifndef GNUNET_TESTING_NG_LIB_H 27#ifndef GNUNET_TESTING_NG_LIB_H
28#define GNUNET_TESTING_NG_LIB_H 28#define GNUNET_TESTING_NG_LIB_H
29 29
30#include "gnunet_util_lib.h"
30#include "gnunet_scheduler_lib.h" 31#include "gnunet_scheduler_lib.h"
31 32
32 33
@@ -760,4 +761,18 @@ struct GNUNET_TESTING_Command
760GNUNET_TESTING_cmd_hello_world (const char *label, 761GNUNET_TESTING_cmd_hello_world (const char *label,
761 char *message); 762 char *message);
762 763
764/**
765 * Offer data from trait
766 *
767 * @param cmd command to extract the url from.
768 * @param pt which url is to be picked, in case
769 * multiple are offered.
770 * @param[out] url where to write the url.
771 * @return #GNUNET_OK on success.
772 */
773int
774GNUNET_TESTING_get_trait_what_am_i (const struct
775 GNUNET_TESTING_Command *cmd,
776 char *what_am_i);
777
763#endif 778#endif
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c
index 724c09c7a..993777de6 100644
--- a/src/testing/testing_api_loop.c
+++ b/src/testing/testing_api_loop.c
@@ -30,12 +30,6 @@
30#include "gnunet_testing_ng_lib.h" 30#include "gnunet_testing_ng_lib.h"
31 31
32/** 32/**
33 * Pipe used to communicate child death via signal.
34 * Must be global, as used in signal handler!
35 */
36static struct GNUNET_DISK_PipeHandle *sigpipe;
37
38/**
39 * Lookup command by label. 33 * Lookup command by label.
40 * 34 *
41 * @param is interpreter state to search 35 * @param is interpreter state to search
@@ -243,7 +237,7 @@ interpreter_run (void *cls)
243 * 237 *
244 * @param cls the interpreter state. 238 * @param cls the interpreter state.
245 */ 239 */
246static void 240/*static void
247do_shutdown (void *cls) 241do_shutdown (void *cls)
248{ 242{
249 struct GNUNET_TESTING_Interpreter *is = cls; 243 struct GNUNET_TESTING_Interpreter *is = cls;
@@ -274,145 +268,8 @@ do_shutdown (void *cls)
274 GNUNET_SCHEDULER_cancel (is->timeout_task); 268 GNUNET_SCHEDULER_cancel (is->timeout_task);
275 is->timeout_task = NULL; 269 is->timeout_task = NULL;
276 } 270 }
277 if (NULL != is->child_death_task)
278 {
279 GNUNET_SCHEDULER_cancel (is->child_death_task);
280 is->child_death_task = NULL;
281 }
282 GNUNET_free (is->commands); 271 GNUNET_free (is->commands);
283} 272}*/
284
285
286/**
287 * Function run when the test terminates (good or bad) with timeout.
288 *
289 * @param cls NULL
290 */
291static void
292do_timeout (void *cls)
293{
294 struct GNUNET_TESTING_Interpreter *is = cls;
295
296 is->timeout_task = NULL;
297 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
298 "Terminating test due to timeout\n");
299 GNUNET_SCHEDULER_shutdown ();
300}
301
302
303/**
304 * Task triggered whenever we receive a SIGCHLD (child
305 * process died).
306 *
307 * @param cls closure
308 */
309static void
310maint_child_death (void *cls)
311{
312 struct GNUNET_TESTING_Interpreter *is = cls;
313 struct GNUNET_TESTING_Command *cmd = &is->commands[is->ip];
314 const struct GNUNET_DISK_FileHandle *pr;
315 struct GNUNET_OS_Process **processp;
316 char c[16];
317 enum GNUNET_OS_ProcessStatusType type;
318 unsigned long code;
319
320 if (GNUNET_TESTING_cmd_is_batch (cmd))
321 {
322 struct GNUNET_TESTING_Command *batch_cmd;
323
324 GNUNET_assert (GNUNET_OK ==
325 GNUNET_TESTING_get_trait_cmd (cmd,
326 0,
327 &batch_cmd));
328 cmd = batch_cmd;
329 }
330
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Got SIGCHLD for `%s'.\n",
333 cmd->label);
334 is->child_death_task = NULL;
335 pr = GNUNET_DISK_pipe_handle (sigpipe,
336 GNUNET_DISK_PIPE_END_READ);
337 GNUNET_break (0 <
338 GNUNET_DISK_file_read (pr,
339 &c,
340 sizeof (c)));
341 if (GNUNET_OK !=
342 GNUNET_TESTING_get_trait_process (cmd,
343 0,
344 &processp))
345 {
346 GNUNET_break (0);
347 GNUNET_TESTING_interpreter_fail (is);
348 return;
349 }
350
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
352 "Got the dead child process handle, waiting for termination ...\n");
353 GNUNET_OS_process_wait_status (*processp,
354 &type,
355 &code);
356 GNUNET_OS_process_destroy (*processp);
357 *processp = NULL;
358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
359 "... definitively terminated\n");
360 switch (type)
361 {
362 case GNUNET_OS_PROCESS_UNKNOWN:
363 GNUNET_break (0);
364 GNUNET_TESTING_interpreter_fail (is);
365 return;
366 case GNUNET_OS_PROCESS_RUNNING:
367 GNUNET_break (0);
368 GNUNET_TESTING_interpreter_fail (is);
369 return;
370 case GNUNET_OS_PROCESS_STOPPED:
371 GNUNET_break (0);
372 GNUNET_TESTING_interpreter_fail (is);
373 return;
374 case GNUNET_OS_PROCESS_EXITED:
375 if (0 != code)
376 {
377 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
378 "Process exited with unexpected status %u\n",
379 (unsigned int) code);
380 GNUNET_TESTING_interpreter_fail (is);
381 return;
382 }
383 break;
384 case GNUNET_OS_PROCESS_SIGNALED:
385 GNUNET_break (0);
386 GNUNET_TESTING_interpreter_fail (is);
387 return;
388 }
389
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391 "Dead child, go on with next command.\n");
392 GNUNET_TESTING_interpreter_next (is);
393}
394
395
396/**
397 * Wait until we receive SIGCHLD signal.
398 * Then obtain the process trait of the current
399 * command, wait on the the zombie and continue
400 * with the next command.
401 */
402void
403GNUNET_TESTING_wait_for_sigchld (struct GNUNET_TESTING_Interpreter *is)
404{
405 const struct GNUNET_DISK_FileHandle *pr;
406
407 GNUNET_assert (NULL == is->child_death_task);
408 pr = GNUNET_DISK_pipe_handle (sigpipe,
409 GNUNET_DISK_PIPE_END_READ);
410 is->child_death_task
411 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
412 pr,
413 &maint_child_death,
414 is);
415}
416 273
417 274
418/** 275/**
@@ -425,228 +282,25 @@ GNUNET_TESTING_wait_for_sigchld (struct GNUNET_TESTING_Interpreter *is)
425 * @param commands the list of command to execute 282 * @param commands the list of command to execute
426 * @param timeout how long to wait 283 * @param timeout how long to wait
427 */ 284 */
428void 285int
429GNUNET_TESTING_run2 (struct GNUNET_TESTING_Interpreter *is, 286GNUNET_TESTING_run (const char *cfg_filename,
430 struct GNUNET_TESTING_Command *commands, 287 struct GNUNET_TESTING_Command *commands,
431 struct GNUNET_TIME_Relative timeout) 288 struct GNUNET_TIME_Relative timeout)
432{ 289{
433 unsigned int i; 290 unsigned int i;
434 291
435 if (NULL != is->timeout_task)
436 {
437 GNUNET_SCHEDULER_cancel (is->timeout_task);
438 is->timeout_task = NULL;
439 }
440 /* get the number of commands */ 292 /* get the number of commands */
441 for (i = 0; NULL != commands[i].label; i++) 293 for (i = 0; NULL != commands[i].label; i++)
442 ; 294 ;
443 is->commands = GNUNET_new_array (i + 1, 295
444 struct GNUNET_TESTING_Command); 296
445 memcpy (is->commands, 297 /*is->timeout_task = GNUNET_SCHEDULER_add_delayed
446 commands,
447 sizeof (struct GNUNET_TESTING_Command) * i);
448 is->timeout_task = GNUNET_SCHEDULER_add_delayed
449 (timeout, 298 (timeout,
450 &do_timeout, 299 &do_timeout,
451 is); 300 is);
452 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is); 301 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
453 is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is); 302 is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is);*/
454} 303 return GNUNET_OK;
455
456
457/**
458 * Run the testsuite. Note, CMDs are copied into
459 * the interpreter state because they are _usually_
460 * defined into the "run" method that returns after
461 * having scheduled the test interpreter.
462 *
463 * @param is the interpreter state
464 * @param commands the list of command to execute
465 */
466void
467GNUNET_TESTING_run (struct GNUNET_TESTING_Interpreter *is,
468 struct GNUNET_TESTING_Command *commands)
469{
470 GNUNET_TESTING_run2 (is,
471 commands,
472 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
473 5));
474}
475
476
477/**
478 * Information used by the wrapper around the main
479 * "run" method.
480 */
481struct MainContext
482{
483 /**
484 * Main "run" method.
485 */
486 GNUNET_TESTING_Main main_cb;
487
488 /**
489 * Closure for @e main_cb.
490 */
491 void *main_cb_cls;
492
493 /**
494 * Interpreter state.
495 */
496 struct GNUNET_TESTING_Interpreter *is;
497};
498
499
500/**
501 * Signal handler called for SIGCHLD. Triggers the
502 * respective handler by writing to the trigger pipe.
503 */
504static void
505sighandler_child_death (void)
506{
507 static char c;
508 int old_errno = errno; /* back-up errno */
509
510 GNUNET_break (1 == GNUNET_DISK_file_write
511 (GNUNET_DISK_pipe_handle (sigpipe,
512 GNUNET_DISK_PIPE_END_WRITE),
513 &c, sizeof (c)));
514 errno = old_errno; /* restore errno */
515}
516
517
518/**
519 * Initialize scheduler loop and curl context for the testcase,
520 * and responsible to run the "run" method.
521 *
522 * @param cls closure, typically the "run" method, the
523 * interpreter state and a closure for "run".
524 */
525static void
526main_wrapper_exchange_agnostic (void *cls)
527{
528 struct MainContext *main_ctx = cls;
529
530 main_ctx->main_cb (main_ctx->main_cb_cls,
531 main_ctx->is);
532}
533
534
535/**
536 * Function run when the test is aborted before we launch the actual
537 * interpreter. Cleans up our state.
538 *
539 * @param cls the main context
540 */
541static void
542do_abort (void *cls)
543{
544 struct MainContext *main_ctx = cls;
545 struct GNUNET_TESTING_Interpreter *is = main_ctx->is;
546
547 is->timeout_task = NULL;
548 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
549 "Executing abort prior to interpreter launch\n");
550}
551
552
553/**
554 * Initialize scheduler loop and curl context for the testcase,
555 * and responsible to run the "run" method.
556 *
557 * @param cls a `struct MainContext *`
558 */
559static void
560main_wrapper_exchange_connect (void *cls)
561{
562 struct MainContext *main_ctx = cls;
563 struct GNUNET_TESTING_Interpreter *is = main_ctx->is;
564 char *exchange_url;
565
566 if (GNUNET_OK !=
567 GNUNET_CONFIGURATION_get_value_string (is->cfg,
568 "exchange",
569 "BASE_URL",
570 &exchange_url))
571 {
572 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
573 "exchange",
574 "BASE_URL");
575 return;
576 }
577 is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
578 main_ctx);
579 is->working = GNUNET_YES;
580
581 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
582 "Starting main test loop\n");
583 main_ctx->main_cb (main_ctx->main_cb_cls,
584 is);
585}
586
587
588/**
589 * Install signal handlers plus schedules the main wrapper
590 * around the "run" method.
591 *
592 * @param main_cb the "run" method which contains all the
593 * commands.
594 * @param main_cb_cls a closure for "run", typically NULL.
595 * @param cfg configuration to use
596 * @param exchanged exchange process handle: will be put in the
597 * state as some commands - e.g. revoke - need to send
598 * signal to it, for example to let it know to reload the
599 * key state.. if NULL, the interpreter will run without
600 * trying to connect to the exchange first.
601 * @param exchange_connect #GNUNET_YES if the test should connect
602 * to the exchange, #GNUNET_NO otherwise
603 * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
604 * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
605 * times.
606 */
607int
608GNUNET_TESTING_setup (GNUNET_TESTING_Main main_cb,
609 void *main_cb_cls,
610 const struct GNUNET_CONFIGURATION_Handle *cfg,
611 struct GNUNET_OS_Process *exchanged,
612 int exchange_connect)
613{
614 struct GNUNET_TESTING_Interpreter is;
615 struct MainContext main_ctx = {
616 .main_cb = main_cb,
617 .main_cb_cls = main_cb_cls,
618 /* needed to init the curl ctx */
619 .is = &is,
620 };
621 struct GNUNET_SIGNAL_Context *shc_chld;
622
623 memset (&is,
624 0,
625 sizeof (is));
626 is.exchanged = exchanged;
627 is.cfg = cfg;
628 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
629 GNUNET_assert (NULL != sigpipe);
630 shc_chld = GNUNET_SIGNAL_handler_install
631 (GNUNET_SIGCHLD,
632 &sighandler_child_death);
633
634
635 /* Blocking */
636 if (GNUNET_YES == exchange_connect)
637 GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect,
638 &main_ctx);
639 else
640 GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic,
641 &main_ctx);
642 if (NULL != is.final_cleanup_cb)
643 is.final_cleanup_cb (is.final_cleanup_cb_cls);
644 GNUNET_SIGNAL_handler_uninstall (shc_chld);
645 GNUNET_DISK_pipe_close (sigpipe);
646 sigpipe = NULL;
647 GNUNET_free (is.auditor_url);
648 GNUNET_free (is.exchange_url);
649 return is.result;
650} 304}
651 305
652 306