9 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
12 /* the unit thread start routine */
17 unit_new(runner_t runner, suite_t owner, fstream_t fstream)
19 unit_t unit = xbt_new0(s_unit_t, 1);
21 /* set the owner of the unit */
22 unit->runner = runner;
24 unit->fstream = fstream;
28 unit->commands = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)command_free);
32 unit->number_of_started_commands = 0;
33 unit->number_of_interrupted_commands = 0;
34 unit->number_of_failed_commands = 0;
35 unit->number_of_successeded_commands = 0;
36 unit->number_of_terminated_commands = 0;
37 unit->interrupted = 0;
39 unit->successeded = 0;
42 unit->parsing_include_file = 0;
47 unit->suites = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)suite_free);
50 unit->running_suite = 0;
57 unit_add_suite(unit_t unit, suite_t suite)
59 vector_push_back(unit->suites, suite);
63 unit_free(void** unitptr)
65 unit_t* __unitptr = (unit_t*)unitptr;
67 vector_free(&((*__unitptr)->commands));
69 vector_free(&((*__unitptr)->suites));
71 /* if the unit is interrupted during its run, the semaphore is NULL */
73 xbt_os_sem_destroy((*__unitptr)->sem);
76 free((*__unitptr)->suites);
89 xbt_os_thread_t thread;
94 unit_t unit = (unit_t)p;
96 xbt_os_mutex_acquire(unit->mutex);
97 unit->runner->number_of_runned_units++;
98 xbt_os_mutex_release(unit->mutex);
100 /* try to acquire the jobs semaphore to start */
101 xbt_os_sem_acquire(jobs_sem);
103 mutex = xbt_os_mutex_init();
104 context = context_new();
107 INFO1("checking unit %s...",unit->fstream->name);
110 unit_parse(unit, context, mutex, unit->fstream->name, unit->fstream->stream);
112 /* if the unit is not interrupted and not failed the unit, all the file is parsed
113 * so all the command are launched
115 if(!unit->interrupted)
119 /* all the commands have terminate before the end of the parsing of the tesh file
120 * so the unit release the semaphore itself
122 if(!unit->released && (unit->number_of_started_commands == (unit->number_of_failed_commands + unit->number_of_interrupted_commands + unit->number_of_successeded_commands)))
123 xbt_os_sem_release(unit->sem);
127 /* wait the end of all the commands or a command failure or an interruption */
130 xbt_os_sem_acquire(unit->sem);
132 if(unit->interrupted)
136 /* interrupt all the running commands of the unit */
137 for(i = 0; i < unit->number_of_commands; i++)
139 /*command = unit->commands[i];*/
140 command = vector_get_at(unit->commands, i);
142 if(command->status == cs_in_progress)
143 /*command_interrupt(unit->commands[i]);*/
144 command_interrupt(command);
149 /* wait the end of the threads */
150 for(i = 0; i < unit->number_of_commands; i++)
152 /*thread = unit->commands[i]->thread;*/
154 command_t command = vector_get_at(unit->commands, i);
155 thread = command->thread;
158 xbt_os_thread_join(thread,NULL);
161 context_free(&context);
163 xbt_os_mutex_destroy(mutex);
165 xbt_os_mutex_acquire(unit->mutex);
167 /* increment the number of ended units */
168 unit->runner->number_of_ended_units++;
170 /* it's the last unit, release the runner */
171 if(/*!unit->interrupted &&*/ (unit->runner->number_of_runned_units == unit->runner->number_of_ended_units))
173 if(unit->number_of_successeded_commands == unit->number_of_commands)
174 unit->successeded = 1;
176 /* first release the mutex */
177 xbt_os_mutex_release(unit->mutex);
178 xbt_os_sem_release(units_sem);
181 xbt_os_mutex_release(unit->mutex);
183 /* release the jobs semaphore, then the next unit can start */
184 xbt_os_sem_release(jobs_sem);
191 unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name, FILE* stream)
200 /* Count the line length while checking wheather it's blank */
203 /* Deal with \ at the end of the line, and call handle_line on result */
206 buff=xbt_strbuff_new();
208 while(!unit->interrupted && getline(&line, &len, stream) != -1)
216 while(line[linelen] != '\0')
218 if (line[linelen] != ' ' && line[linelen] != '\t' && line[linelen]!='\n' && line[linelen]!='\r')
226 if(!context->command_line && (context->input->used || context->output->used))
228 ERROR1("[%d] Error: no command found in this chunk of lines.",buffbegin);
230 if(unit->parsing_include_file)
231 ERROR1("Unit `%s': NOK (syntax error)", unit->fstream->name);
233 ERROR2("Unit `%s' inclued in `%s' : NOK (syntax error)", file_name, unit->fstream->name);
236 unit_handle_failure(unit);
240 if(context->command_line)
244 command_t command = command_new(unit, context, mutex);
245 command_run(command);
248 context_reset(context);
256 if(linelen>1 && line[linelen-2]=='\\')
258 if (linelen>2 && line[linelen-3] == '\\')
260 /* Damn. Escaped \ */
261 line[linelen-2] = '\n';
262 line[linelen-1] = '\0';
267 line[linelen-2] = '\0';
271 buffbegin = line_num;
275 if(buff->used || to_be_continued)
277 xbt_strbuff_append(buff,line);
279 if (!to_be_continued)
281 snprintf(file_pos,256,"%s:%d",file_name,buffbegin);
282 unit_handle_line(unit, context, mutex, file_pos, buff->data);
283 xbt_strbuff_empty(buff);
288 snprintf(file_pos,256,"%s:%d",file_name,line_num);
289 unit_handle_line(unit, context, mutex, file_pos, line);
293 /* Check that last command of the file ran well */
294 if(context->command_line)
298 command_t command = command_new(unit, context, mutex);
299 command_run(command);
302 context_reset(context);
309 xbt_strbuff_free(buff);
313 unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char * filepos, char *line)
316 xbt_str_rtrim(line+2,"\n");
326 context->async = (line[0] == '&');
328 /* further trim useless chars which are significant for in/output */
329 xbt_str_rtrim(line+2," \t");
331 /* Deal with CD commands here, not in rctx */
332 if (!strncmp("cd ",line+2,3))
336 if (context->command_line)
340 command_t command = command_new(unit, context, mutex);
341 command_run(command);
344 context_reset(context);
347 /* search begining */
348 while (*(dir++) == ' ');
352 VERB1("Saw cd '%s'",dir);
356 unit->number_of_successeded_commands++;
362 ERROR2("Chdir to %s failed: %s",dir,strerror(errno));
363 ERROR1("Test suite `%s': NOK (system error)", unit->fstream->name);
365 unit_handle_failure(unit);
370 } /* else, pushline */
373 unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/);
380 unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/);
385 INFO2("[%s] %s",filepos,line+2);
390 CRITICAL2("[%s] %s",filepos,line+2);
394 ERROR2("[%s] Syntax error: %s",filepos, line);
395 ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name);
397 unit_handle_failure(unit);
403 unit_pushline(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* filepos, char kind, char *line)
410 if(context->command_line)
414 if(context->output->used || context->input->used)
416 ERROR2("[%s] More than one command in this chunk of lines (previous: %s).\nDunno which input/output belongs to which command.",filepos,context->command_line);
417 ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name);
419 unit_handle_failure(unit);
425 command = command_new(unit, context, mutex);
426 command_run(command);
429 context_reset(context);
431 VERB1("[%s] More than one command in this chunk of lines",filepos);
434 context->command_line = strdup(line);
437 context->line = strdup(filepos);
438 /*INFO2("[%s] %s",filepos,context->command_line);*/
443 xbt_strbuff_append(context->input,line);
444 xbt_strbuff_append(context->input,"\n");
448 xbt_strbuff_append(context->output,line);
449 xbt_strbuff_append(context->output,"\n");
454 if(context->command_line)
458 command_t command = command_new(unit, context, mutex);
459 command_run(command);
462 context_reset(context);
465 if(!strncmp(line,"timeout no",strlen("timeout no")))
467 VERB1("[%s] (disable timeout)", filepos);
468 context->timeout = INDEFINITE;
470 else if(!strncmp(line,"timeout ",strlen("timeout ")))
473 char* p = line + strlen("timeout ");
480 ERROR2("Invalid timeout value `%s' at %s ", line + strlen("timeout "), filepos);
481 unit_handle_failure(unit);
487 context->timeout = atoi(line + strlen("timeout"));
488 VERB2("[%s] (new timeout value: %d)",filepos,context->timeout);
491 else if (!strncmp(line,"expect signal ",strlen("expect signal ")))
493 context->signal = strdup(line + strlen("expect signal "));
496 if(!strstr(context->signal,"SIGSEGVSIGTRAPSIGBUSSIGFPESIGILL"))
499 /*ERROR2("Signal `%s' not supported at %s", line + strlen("expect signal "), filepos);*/
500 unit_handle_failure(unit);
504 xbt_str_trim(context->signal," \n");
505 VERB2("[%s] (next command must raise signal %s)", filepos, context->signal);
508 else if (!strncmp(line,"expect return ",strlen("expect return ")))
512 char* p = line + strlen("expect return ");
520 ERROR2("Invalid exit code value `%s' at %s ", line + strlen("expect return "), filepos);
521 unit_handle_failure(unit);
527 context->exit_code = atoi(line+strlen("expect return "));
528 VERB2("[%s] (next command must return code %d)",filepos, context->exit_code);
531 else if (!strncmp(line,"output ignore",strlen("output ignore")))
533 context->output_handling = oh_ignore;
534 VERB1("[%s] (ignore output of next command)", filepos);
537 else if (!strncmp(line,"output display",strlen("output display")))
539 context->output_handling = oh_display;
540 VERB1("[%s] (ignore output of next command)", filepos);
543 else if(!strncmp(line,"include", strlen("include")))
545 unit_handle_include(unit, context, mutex, line + strlen("include "));
548 else if(!strncmp(line,"suite", strlen("suite")))
550 unit_handle_suite(unit, context, mutex, line + strlen("suite "));
554 ERROR2("%s: Malformed metacommand: %s",filepos,line);
555 ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name);
557 unit_handle_failure(unit);
567 unit_handle_failure(unit_t unit)
569 if(!want_keep_going_unit)
571 if(!unit->interrupted)
573 /* the unit interrupted (exit for the loop) */
574 unit->interrupted = 1;
576 /* release the unit */
577 xbt_os_sem_release(unit->sem);
580 /* if the --keep-going option is not specified */
585 /* request an global interruption by the runner */
588 /* release the runner */
589 xbt_os_sem_release(units_sem);
596 unit_run(unit_t unit, xbt_os_mutex_t mutex)
602 unit->sem = xbt_os_sem_init(0);
605 unit->thread = xbt_os_thread_create("", unit_start, unit);
608 /* the unit is interrupted by the runner before its starting
609 * in this case the unit semaphore is NULL take care of that
610 * in the function unit_free()
612 unit->interrupted = 1;
618 unit_interrupt(unit_t unit)
620 /* interrupt the loop */
621 unit->interrupted = 1;
622 xbt_os_sem_release(unit->sem);
626 unit_verbose(unit_t unit)
631 printf("\nUnit : %s (%s)\n", unit->fstream->name, unit->fstream->directory);
632 printf("Status informations :");
634 if(unit->parsed && unit->number_of_successeded_commands == unit->number_of_started_commands)
635 printf(" - (success)");
638 if(unit->interrupted)
639 printf(" - (interruped)");
641 printf(" - (failed)");
646 printf(" number of commands : %d\n", unit->number_of_commands);
647 printf(" number of runned commands : %d\n", unit->number_of_started_commands);
648 printf(" number of successeded commands : %d\n", unit->number_of_successeded_commands);
649 printf(" number of failed commands : %d\n", unit->number_of_failed_commands);
650 printf(" number of interrupted commands : %d\n", unit->number_of_interrupted_commands);
652 test_count = unit->number_of_commands;
655 for(i = 0; i < test_count; i++)
657 command = vector_get_at(unit->commands, i);
659 /*command_display_status(unit->commands[i]);*/
660 command_display_status(command);
667 unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name)
670 char* prev_directory = NULL;
671 fstream_t fstream = NULL;
672 struct stat buffer = {0};
675 if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
677 INFO1("the file stream %s is in the current directory", file_name);
679 fstream = fstream_new(getcwd(NULL, 0), file_name);
680 fstream_open(fstream);
682 /* the file to include is not in the current directory, check if it is in a include directory */
685 prev_directory = getcwd(NULL, 0);
687 vector_rewind(includes);
689 while((include = vector_get(includes)))
691 chdir(include->name);
693 if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode))
695 fstream = fstream_new(include->name, file_name);
696 fstream_open(fstream);
701 vector_move_next(includes);
704 chdir(prev_directory);
705 free(prev_directory);
710 /* the file to include is not found handle the failure */
713 exit_code = EINCLUDENOTFOUND;
714 ERROR1("Include file %s not found",file_name);
715 unit_handle_failure(unit);
719 /* parse the include file */
721 /*unit_t __unit = unit_new(unit->runner, NULL, fstream);*/
722 unit->parsing_include_file = 1;
724 /* add the unit to the list of the runned units */
726 /*xbt_os_mutex_acquire(unit->mutex);
727 vector_push_back(__unit->runner->units->items, __unit);
728 xbt_os_mutex_release(unit->mutex);*/
732 INFO2("checking unit %s including in %s...",fstream->name, unit->fstream->name);
734 unit_parse(unit, context_new(), mutex, fstream->name, fstream->stream);
736 fstream_free((void**)&fstream);
737 unit->parsing_include_file = 0;
742 unit_handle_suite(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* description)
744 suite_t suite = suite_new(unit, description);
745 unit_add_suite(unit, suite);
746 unit->running_suite = 1;
750 unit_reset(unit_t unit)
752 fseek(unit->fstream->stream,0L, SEEK_SET);
754 unit->number_of_commands = 0;