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>
31 #define _RUNNER_HASHCODE 0xFEFEAAAA
33 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
35 #if (!defined(__BUILTIN) && defined(__CHKCMD))
36 static const char* builtin[] =
83 #define __BUILTIN_MAX ((size_t)42)
91 /* the unique tesh runner */
95 /* wait for the tesh runner terminaison */
100 runner_start_routine(void* p);
103 /* check the syntax of the tesh files if
104 * the check_syntax_flag is specified. Returns
105 * 0 if the syntax is clean.
108 check_syntax(void);*/
117 runner_start_routine(void* p)
122 li.QuadPart=- runner->timeout * 10000000; /* 10000000 = 10 000 000 * 100 nanoseconds = 1 second */
124 /* create the waitable timer */
125 timer_handle = CreateWaitableTimer(NULL, TRUE, NULL);
127 /* set a timer to wait for timeout seconds */
128 SetWaitableTimer(timer_handle, &li, 0, NULL, NULL, 0);
130 /* wait for the timer */
131 WaitForSingleObject(timer_handle, INFINITE);
135 exit_code = ELEADTIME;
137 runner->timeouted = 1;
138 xbt_os_sem_release(units_sem);
146 runner_start_routine(void* p)
149 int timeout = runner->timeout;
152 while(timeout-- && runner->waiting)
160 }while(EINTR == errno);
165 /* TODO process the error */
171 exit_code = ELEADTIME;
173 runner->timeouted = 1;
174 xbt_os_sem_release(units_sem);
184 runner_init(/*int check_syntax_flag, */int timeout, fstreams_t fstreams)
189 char buffer[PATH_MAX + 1] = {0};
194 #if (defined(__CHKCMD) && defined(__BUILTIN))
205 ERROR0("The runner is already initialized");
209 runner = xbt_new0(s_runner_t, 1);
212 runner->builtin = NULL;
214 if(!(runner->units = units_new(runner, fstreams)))
221 runner->timeout = timeout;
222 runner->timeouted = 0;
223 runner->interrupted = 0;
224 runner->number_of_ended_units = 0;
225 runner->number_of_runned_units = 0;
228 runner->total_of_tests = 0;
229 runner->total_of_successeded_tests = 0;
230 runner->total_of_failed_tests = 0;
231 runner->total_of_interrupted_tests = 0;
233 runner->total_of_units = 0;
234 runner->total_of_successeded_units = 0;
235 runner->total_of_failed_units = 0;
236 runner->total_of_interrupted_units = 0;
238 runner->total_of_suites = 0;
239 runner->total_of_successeded_suites = 0;
240 runner->total_of_failed_suites = 0;
241 runner->total_of_interrupted_suites = 0;
243 /* initialize the vector of variables */
244 runner->variables = xbt_dynar_new(sizeof(variable_t), (void_f_pvoid_t)variable_free);
246 /* add the environment variables in the vector */
247 for(i = 0; environ[i] != NULL; i++)
250 val = strchr(environ[i], '=');
259 strncpy(buffer, environ[i], (val - environ[i] -1));
261 if(!strcmp("TESH_PPID", buffer))
264 variable = variable_new(buffer, val);
266 xbt_dynar_push(runner->variables, &variable);
269 if(!strcmp("PATH", buffer))
274 /* get the list of paths */
275 runner->path = explode(':', val);
277 /* remove spaces and backslahes at the end of the path */
278 for (k = 0; runner->path[k] != NULL; k++)
284 for(j = len - 1; p[j] == '/' || p[j] == ' '; j--)
290 memset(buffer, 0, PATH_MAX + 1);
296 char* tesh_dir = getcwd(NULL, 0);
298 sprintf(buffer,"%d",getpid());
301 setenv("TESH_PPID", buffer, 0);
302 setenv("TESH_DIR", tesh_dir, 0);
304 SetEnvironmentVariable("TESH_PPID", buffer);
305 SetEnvironmentVariable("TESH_DIR", tesh_dir);
308 variable = variable_new("TESH_PPID", buffer);
311 xbt_dynar_push(runner->variables, &variable);
316 variable = variable_new("EXIT_SUCCESS", "0");
319 xbt_dynar_push(runner->variables, &variable);
321 variable = variable_new("EXIT_FAILURE", "1");
324 xbt_dynar_push(runner->variables, &variable);
326 variable = variable_new("TRUE", "0");
329 xbt_dynar_push(runner->variables, &variable);
331 variable = variable_new("FALSE", "1");
334 xbt_dynar_push(runner->variables, &variable);
339 /* add the errors variables */
340 while((cstr = error_get_at(i++, &code)))
342 sprintf(buffer,"%d",code);
343 variable = variable_new(cstr, buffer);
345 xbt_dynar_push(runner->variables, &variable);
348 /* if the user want check the syntax, check it */
349 /*if(check_syntax_flag)
354 #if defined(__CHKCMD)
355 #if defined(__BUILTIN)
358 /* compute the full path the builtin.def file */
360 sprintf(buffer,"%s/builtin.def",getenv("TESH_DIR"));
362 GetEnvironmentVariable("TESH_DIR",buffer,PATH_MAX + 1);
365 s = fopen(buffer, "r");
370 s = fopen("builtin.def", "r");
379 while(readline(s, &line, &len) != -1)
385 while(line[i] != '\0')
387 if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
410 runner->builtin = xbt_new0(char*, n + 1); /* (char**) calloc(n + 1, sizeof(char*));*/
414 while(readline(s, &line, &len) != -1)
419 while(line[i] != '\0')
421 if (line[i] != ' ' && line[i] != '\t' && line[i]!='\n' && line[i]!='\r')
434 l[strlen(l) - 1] = '\0';
436 (runner->builtin)[n++] = l;
444 WARN0("The file `(builtin.def)' is empty");
445 free(runner->builtin);
446 runner->builtin = NULL;
458 ERROR0("File `(builtin.def)' not found");
463 runner->builtin = xbt_new0(char*, __BUILTIN_MAX + 1); /* (char**) calloc(__BUILTIN_MAX + 1, sizeof(char*));*/
465 for(i = 0; i < __BUILTIN_MAX; i++)
466 runner->builtin[i] = strdup(builtin[i]);
470 return exit_code ? -1 : 0;
479 units_free((void**)(&(runner->units)));
481 if(runner->variables)
482 xbt_dynar_free(&runner->variables);
485 CloseHandle(timer_handle);
489 xbt_os_thread_join(runner->thread, NULL);
493 for (i = 0; runner->path[i] != NULL; i++)
494 free(runner->path[i]);
501 for (i = 0; runner->builtin[i] != NULL; i++)
502 free(runner->builtin[i]);
504 free(runner->builtin);
516 /* allocate the mutex used by the units to asynchronously access
517 * to the properties of the runner.
519 xbt_os_mutex_t mutex = xbt_os_mutex_init();
521 /* run all the units */
522 units_run_all(runner->units, mutex);
527 /* if the runner is timeouted or receive a interruption request
528 * , interrupt all the active units.
530 if(runner->timeouted || interrupted)
533 /* joins all the units */
534 units_join_all(runner->units);
536 /* release the mutex resource */
537 xbt_os_mutex_destroy(mutex);
544 if(runner->timeout > 0)
545 runner->thread = xbt_os_thread_create("", runner_start_routine, NULL);
547 /* signal that the runner is waiting */
550 /* wait for the end of all the units */
551 xbt_os_sem_acquire(units_sem);
559 * interrupt all the active units.
560 * this function is called when the lead time of the execution is reached
561 * or when a failed unit requests an interruption of the execution.
564 runner_interrupt(void)
566 units_interrupt_all(runner->units);
570 runner_summarize(void)
576 struct rusage r_usage;
580 FILETIME kernel_time;
585 printf("\n TEst SHell utility - mini shell specialized in running test units.\n");
586 printf(" =============================================================================\n");
588 units_summuarize(runner->units);
590 printf(" =====================================================================%s\n",
591 runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK");
593 printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok",
594 (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),
595 runner->total_of_suites, runner->total_of_successeded_suites);
597 if(runner->total_of_failed_suites > 0)
598 printf(", %d failed", runner->total_of_failed_suites);
600 if(runner->total_of_interrupted_suites > 0)
601 printf(", %d interrupted)", runner->total_of_interrupted_suites);
605 printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok",
606 (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),
607 runner->total_of_units, runner->total_of_successeded_units);
609 if(runner->total_of_failed_units > 0)
610 printf(", %d failed", runner->total_of_failed_units);
612 if(runner->total_of_interrupted_units > 0)
613 printf(", %d interrupted)", runner->total_of_interrupted_units);
617 printf(" Test(s): %.0f%% ok (%d test(s): %d ok",
618 (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),
619 runner->total_of_tests, runner->total_of_successeded_tests);
621 if(runner->total_of_failed_tests > 0)
622 printf(", %d failed", runner->total_of_failed_tests);
624 if(runner->total_of_interrupted_tests > 0)
625 printf(", %d interrupted)", runner->total_of_interrupted_tests);
630 if(!getrusage(RUSAGE_SELF, &r_usage))
633 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);
634 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);
636 if(!getrusage(RUSAGE_CHILDREN, &r_usage))
638 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);
639 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);
645 if(GetProcessTimes(GetCurrentProcess(), &start_time, &exit_time, &kernel_time, &user_time))
647 FileTimeToSystemTime(&user_time, &si);
649 printf(" Total tesh user time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
651 FileTimeToSystemTime(&kernel_time, &si);
653 printf(" Total tesh kernel time used: %uhour(s) %uminute(s) %usecond(s) %millisecond(s)\n", si.wHour, si.wMinute, si.wSecond, si.wMilliseconds );
663 ERROR0("Syntax NOK");
670 runner_is_timedout(void)
672 return runner->timeouted;