2 * src/runner.c - type representing the runner.
4 * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package.
10 * This file contains all the definitions of the functions related with
11 * the tesh runner type.
20 #include <errno.h> /* for error code */
21 #include <stdlib.h> /* for calloc() */
27 #include <sys/resource.h>
34 #define _RUNNER_HASHCODE 0xFEFEAAAA
36 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
38 #if (!defined(__BUILTIN) && defined(__CHKCMD) && !defined(WIN32))
39 static const char* builtin[] =
86 #define __BUILTIN_MAX ((size_t)42)
94 /* the unique tesh runner */
98 /* wait for the tesh runner terminaison */
103 runner_start_routine(void* p);
106 /* check the syntax of the tesh files if
107 * the check_syntax_flag is specified. Returns
108 * 0 if the syntax is clean.
111 check_syntax(void);*/
120 runner_start_routine(void* p)
125 li.QuadPart=- runner->timeout * 10000000; /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */
127 /* create the waitable timer */
128 timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);
130 /* set a timer to wait for timeout seconds */
131 SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);
133 /* wait for the timer */
134 WaitForSingleObject(timer_handle, INFINITE);
138 exit_code = ELEADTIME;
140 runner->timeouted = 1;
141 xbt_os_sem_release(units_sem);
149 runner_start_routine(void* p)
152 int timeout = runner->timeout;
155 while(timeout-- && runner->waiting)
163 }while(EINTR == errno);
168 /* TODO process the error */
174 exit_code = ELEADTIME;
176 runner->timeouted = 1;
177 xbt_os_sem_release(units_sem);
187 runner_init(/*int check_syntax_flag, */int timeout, fstreams_t fstreams)
192 char buffer[PATH_MAX + 1] = {0};
198 #if (defined(__CHKCMD) && defined(__BUILTIN) && !defined(WIN32))
209 ERROR0("The runner is already initialized");
213 runner = xbt_new0(s_runner_t, 1);
216 runner->builtin = NULL;
218 if(!(runner->units = units_new(runner, fstreams)))
225 runner->timeout = timeout;
226 runner->timeouted = 0;
227 runner->interrupted = 0;
228 runner->number_of_ended_units = 0;
229 runner->number_of_runned_units = 0;
232 runner->total_of_tests = 0;
233 runner->total_of_successeded_tests = 0;
234 runner->total_of_failed_tests = 0;
235 runner->total_of_interrupted_tests = 0;
237 runner->total_of_units = 0;
238 runner->total_of_successeded_units = 0;
239 runner->total_of_failed_units = 0;
240 runner->total_of_interrupted_units = 0;
242 runner->total_of_suites = 0;
243 runner->total_of_successeded_suites = 0;
244 runner->total_of_failed_suites = 0;
245 runner->total_of_interrupted_suites = 0;
247 /* initialize the vector of variables */
248 runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);
250 /* add the environment variables in the vector */
251 for(i = 0; environ[i] != NULL; i++)
253 val = strchr(environ[i], '=');
260 strncpy(buffer, environ[i], (val - environ[i] -1));
262 if(!strcmp("TESH_PPID", buffer))
265 variable = variable_new(buffer, val);
267 xbt_dynar_push(runner->variables, &variable);
270 if(!strcmp("PATH", buffer))
275 /* get the list of paths */
277 runner->path = explode(':', val);
279 /* remove spaces and backslahes at the end of the path */
280 for (k = 0; runner->path[k] != NULL; k++)
286 for(j = len - 1; p[j] == '/' || p[j] == ' '; j--)
293 memset(buffer, 0, PATH_MAX + 1);
299 char* tesh_dir = getcwd(NULL, 0);
301 sprintf(buffer,"%d",getpid());
304 setenv("TESH_PPID", buffer, 0);
305 setenv("TESH_DIR", tesh_dir, 0);
307 SetEnvironmentVariable("TESH_PPID", buffer);
308 SetEnvironmentVariable("TESH_DIR", tesh_dir);
311 variable = variable_new("TESH_PPID", buffer);
314 xbt_dynar_push(runner->variables, &variable);
316 variable = variable_new("TESH_DIR", tesh_dir);
319 xbt_dynar_push(runner->variables, &variable);
324 variable = variable_new("EXIT_SUCCESS", "0");
327 xbt_dynar_push(runner->variables, &variable);
329 variable = variable_new("EXIT_FAILURE", "1");
332 xbt_dynar_push(runner->variables, &variable);
334 variable = variable_new("TRUE", "0");
337 xbt_dynar_push(runner->variables, &variable);
339 variable = variable_new("FALSE", "1");
342 xbt_dynar_push(runner->variables, &variable);
346 /* add the errors variables */
347 while((cstr = error_get_at(i++, &code)))
349 sprintf(buffer,"%d",code);
350 variable = variable_new(cstr, buffer);
352 xbt_dynar_push(runner->variables, &variable);
355 /* if the user want check the syntax, check it */
356 /*if(check_syntax_flag)
360 #if (!defined(WIN32) && defined(__CHKCMD))
361 #if defined(__BUILTIN)
365 /* compute the full path the builtin.def file */
366 sprintf(buffer,"%s/builtin.def",getenv("TESH_DIR"));
368 if(!(s = fopen(buffer, "r")))
370 ERROR1("File `(%s)' not found", buffer);
377 if(!(s = fopen("builtin.def", "r")))
379 ERROR0("File `(builtin.def)' not found");
390 while(readline(s, &line, &len) != -1)
396 while(line[i] != '\0')
398 if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
419 runner->builtin = xbt_new0(char*, n + 1); /* (char**) calloc(n + 1, sizeof(char*));*/
423 while(readline(s, &line, &len) != -1)
428 while(line[i] != '\0')
430 if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
443 l[strlen(l) - 1] = '\0';
445 (runner->builtin)[n++] = l;
453 WARN0("The file `(builtin.def)' is empty");
454 free(runner->builtin);
455 runner->builtin = NULL;
467 runner->builtin = xbt_new0(char*, __BUILTIN_MAX + 1); /* (char**) calloc(__BUILTIN_MAX + 1, sizeof(char*));*/
469 for(i = 0; i < __BUILTIN_MAX; i++)
470 runner->builtin[i] = strdup(builtin[i]);
474 return exit_code ? -1 : 0;
483 units_free((void**)(&(runner->units)));
485 if(runner->variables)
486 xbt_dynar_free(&runner->variables);
489 CloseHandle(timer_handle);
493 xbt_os_thread_join(runner->thread, NULL);
497 for (i = 0; runner->path[i] != NULL; i++)
498 free(runner->path[i]);
505 for (i = 0; runner->builtin[i] != NULL; i++)
506 free(runner->builtin[i]);
508 free(runner->builtin);
520 /* allocate the mutex used by the units to asynchronously access
521 * to the properties of the runner.
523 xbt_os_mutex_t mutex = xbt_os_mutex_init();
525 /* run all the units */
526 units_run_all(runner->units, mutex);
531 /* if the runner is timeouted or receive a interruption request
532 * , interrupt all the active units.
534 if(runner->timeouted || interrupted)
537 /* joins all the units */
538 units_join_all(runner->units);
540 /* release the mutex resource */
541 xbt_os_mutex_destroy(mutex);
548 if(runner->timeout > 0)
549 runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);
551 /* signal that the runner is waiting */
554 /* wait for the end of all the units */
555 xbt_os_sem_acquire(units_sem);
563 * interrupt all the active units.
564 * this function is called when the lead time of the execution is reached
565 * or when a failed unit requests an interruption of the execution.
568 runner_interrupt(void)
570 units_interrupt_all(runner->units);
574 runner_summarize(void)
580 struct rusage r_usage;
584 FILETIME kernel_time;
589 printf("\n TEst SHell utility - mini shell specialized in running test units.\n");
590 printf(" =============================================================================\n");
592 units_summuarize(runner->units);
594 printf(" =====================================================================%s\n",
595 runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");
597 printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",
598 (runner->total_of_suites ? (1-((double)runner->total_of_failed_suites + (double)runner->total_of_interrupted_suites)/(double)runner->total_of_suites)*100.0 : 100.0),
599 runner->total_of_suites, runner->total_of_successeded_suites);
601 if(runner->total_of_failed_suites > 0)
602 printf(", %d failed", runner->total_of_failed_suites);
604 if(runner->total_of_interrupted_suites > 0)
605 printf(", %d interrupted)", runner->total_of_interrupted_suites);
609 printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok",
610 (runner->total_of_units ? (1-((double)runner->total_of_failed_units + (double)runner->total_of_interrupted_units)/(double)runner->total_of_units)*100.0 : 100.0),
611 runner->total_of_units, runner->total_of_successeded_units);
613 if(runner->total_of_failed_units > 0)
614 printf(", %d failed", runner->total_of_failed_units);
616 if(runner->total_of_interrupted_units > 0)
617 printf(", %d interrupted)", runner->total_of_interrupted_units);
621 printf(" Test(s): %.0f%% ok (%d test(s): %d ok",
622 (runner->total_of_tests ? (1-((double)runner->total_of_failed_tests + (double)runner->total_of_interrupted_tests)/(double)runner->total_of_tests)*100.0 : 100.0),
623 runner->total_of_tests, runner->total_of_successeded_tests);
625 if(runner->total_of_failed_tests > 0)
626 printf(", %d failed", runner->total_of_failed_tests);
628 if(runner->total_of_interrupted_tests > 0)
629 printf(", %d interrupted)", runner->total_of_interrupted_tests);
634 if(!getrusage(RUSAGE_SELF, &r_usage))
637 printf(" Total tesh user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);
638 printf(" Total tesh system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
640 if(!getrusage(RUSAGE_CHILDREN, &r_usage))
642 printf(" Total children user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec);
643 printf(" Total children system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec);
649 if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))
651 FileTimeToSystemTime(&user_time, &si);
653 printf(" Total tesh user time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
655 FileTimeToSystemTime(&kernel_time, &si);
657 printf(" Total tesh kernel time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
667 ERROR0("Syntax NOK");
674 runner_is_timedout(void)
676 return runner->timeouted;