1 : /*
2 : * This file is part of MIN Test Framework. Copyright © 2008 Nokia Corporation
3 : * and/or its subsidiary(-ies).
4 : * Contact: Robert Galkowski
5 : * Contact e-mail: DG.MIN-Support@nokia.com
6 : *
7 : * This program is free software: you can redistribute it and/or modify it
8 : * under the terms of the GNU General Public License as published by the Free
9 : * Software Foundation, version 2 of the License.
10 : *
11 : * This program is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 : * more details. You should have received a copy of the GNU General Public
15 : * License along with this program. If not, see
16 : * <http://www.gnu.org/licenses/>.
17 : */
18 :
19 :
20 : /**
21 : * @file tec.c
22 : * @version 0.1
23 : * @brief This file contains implementation of test execution
24 : * controller functionality
25 : */
26 :
27 : /* ----------------------------------------------------------------------------
28 : * INCLUDE FILES
29 : */
30 : #include <stdio.h>
31 : #include <signal.h>
32 : #include <time.h>
33 : #include <sys/wait.h>
34 : #include <dirent.h>
35 : #include <sys/stat.h>
36 : #include <sys/types.h>
37 : #include <regex.h>
38 :
39 : #include <min_parser.h>
40 : #include <tec.h>
41 : #include <min_common.h>
42 : #include <consoleui.h>
43 : #include <data_api.h>
44 : #include <tec_events.h>
45 : #include <min_logger.h>
46 : #include <min_engine_api.h>
47 : #ifndef MIN_EXTIF
48 : #include <tec_tcp_handling.h>
49 : #endif
50 : /* ----------------------------------------------------------------------------
51 : * GLOBAL VARIABLES
52 : */
53 : pthread_mutex_t tec_mutex_ = PTHREAD_MUTEX_INITIALIZER;
54 : char **envp;
55 : #ifdef MIN_UNIT_TEST
56 : int unit_test_result;
57 : #endif /*MINMIN_UNIT_TEST */
58 : struct logger_settings_t logger_settings;
59 : eapiIn_t in_str;
60 : eapiIn_t *in = &in_str;
61 : DLList *available_modules = INITPTR; /*list of available test modules */
62 : DLList *filters = INITPTR;
63 : int min_return_value = 0;
64 : /* ----------------------------------------------------------------------------
65 : * EXTERNAL DATA STRUCTURES
66 : */
67 : /* None */
68 :
69 : /* ---------------------------------------------------------------------------
70 : * EXTERNAL FUNCTION PROTOTYPES
71 : */
72 : extern int ec_msg_ms_handler (MsgBuffer * message);
73 : extern int ec_msg_sndrcv_handler (MsgBuffer * message);
74 : extern int event_system_up (void);
75 : extern int event_system_cleanup (void);
76 :
77 : /* ----------------------------------------------------------------------------
78 : * CONSTANTS
79 : */
80 :
81 : /* ----------------------------------------------------------------------------
82 : * MACROS
83 : */
84 :
85 : #ifndef MIN_CONF_DIR
86 : # define MIN_CONF_DIR "/etc"
87 : #endif
88 :
89 : #ifndef MIN_BIN_DIR
90 : # define MIN_BIN_DIR "/usr/bin"
91 : #endif
92 :
93 :
94 : /* ----------------------------------------------------------------------------
95 : * LOCAL CONSTANTS AND MACROS
96 : */
97 :
98 : /* ----------------------------------------------------------------------------
99 : * MODULE DATA STRUCTURES
100 : */
101 : typedef struct {
102 : Text *filter_;
103 : int regexp_;
104 : } title_filter;
105 :
106 : /* ----------------------------------------------------------------------------
107 : * LOCAL FUNCTION PROTOTYPES
108 : */
109 : /* ------------------------------------------------------------------------- */
110 : /** Waits for process to be ended - collects the zombie.
111 : */
112 : LOCAL void wait_for_pid (void *pid);
113 : /* ------------------------------------------------------------------------- */
114 : /** Signal handler to signal SIGSEGV
115 : * FATAL. Segmentation violation
116 : * @param signum signal number
117 : */
118 : LOCAL void handle_sigsegv (int signum);
119 : /* ------------------------------------------------------------------------- */
120 : /** Signal handler to signal SIGQUIT
121 : * FATAL. Process should dump core on this signal.
122 : * @param signum signal number
123 : */
124 : /* ------------------------------------------------------------------------- */
125 : LOCAL void handle_sigquit (int signum);
126 : /** Signal handler to signal SIGBUS
127 : * FATAL. Bus error.
128 : * @param signum signal number
129 : */
130 : /* ------------------------------------------------------------------------- */
131 : LOCAL void handle_sigbus (int signum);
132 : /** Signal handler to signal SIGTERM
133 : * Signal generated by (kill <processnumber>)
134 : * @param signum signal number
135 : */
136 : /* ------------------------------------------------------------------------- */
137 : LOCAL void handle_sigterm (int signum);
138 : /** Signal handler to signal SIGINT
139 : * Signal generated by CTRL-C
140 : * @param signum signal number
141 : */
142 : /* ------------------------------------------------------------------------- */
143 : LOCAL void handle_sigint (int signum);
144 : /** Signal handler for SIGCHLD
145 : * @param signum signal number
146 : */
147 : /* LOCAL void handle_sigchld (int signum); not used */
148 : /** Function that wraps test module controller process starting.
149 : * In case of failure to start
150 : * a module, information will be logged.
151 : * @param work_module_item item from available modules list
152 : * @return pid of newly created process, or -1 in case of failure
153 : */
154 : LOCAL pid_t ec_start_tmc (DLListIterator work_module_item);
155 : /** Parses the module configuration section(s) from the min configuraion file
156 : * @param inifile the min configuration file
157 : * @return 0, always
158 : */
159 : LOCAL int ec_read_module_section (MinParser * inifile);
160 : /* ------------------------------------------------------------------------- */
161 : /** Looks for files in directory /etc/min.d and tries to find module
162 : * configurations from them
163 : * @return 1 if the directory /etc/min.d does not exists or an error occurs,
164 : * 0 otherwise
165 : */
166 : LOCAL int ec_read_module_confdir (void);
167 :
168 : /* -------------------------------------------------------------------------
169 : * FORWARD DECLARATIONS
170 : */
171 : /* None */
172 :
173 : /* ==================== LOCAL FUNCTIONS ==================================== */
174 : /* ------------------------------------------------------------------------- */
175 : LOCAL void wait_for_pid (void *arg)
176 0 : {
177 : //int* pid = (int*)arg;
178 0 : pthread_exit (0);
179 : }
180 :
181 : /* ------------------------------------------------------------------------- */
182 : /*temp code for summary generation*/
183 : void log_summary ()
184 0 : {
185 0 : DLListIterator work_result_item = INITPTR;
186 0 : DLListIterator work_case_item = INITPTR;
187 0 : DLListIterator work_module_item = INITPTR;
188 :
189 0 : char *case_title = NEW2 (char, MaxTestCaseName);
190 0 : char *module_name = NEW2 (char, MaxFileName);
191 0 : min_log_open ("SUMMARY", 1);
192 :
193 0 : MIN_DEBUG (">>>>>>>>>>>>>>>SUMMARY<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
194 :
195 0 : work_module_item = dl_list_head (available_modules);
196 0 : while (work_module_item != DLListNULLIterator) {
197 0 : tm_get_module_filename (work_module_item, module_name);
198 0 : MIN_DEBUG ("module: %s", module_name);
199 0 : work_case_item =
200 : dl_list_head (tm_get_tclist (work_module_item));
201 0 : while (work_case_item != DLListNULLIterator) {
202 0 : tc_get_title (work_case_item, case_title);
203 0 : MIN_DEBUG ("case: %s", case_title);
204 0 : work_result_item =
205 : dl_list_head (tc_get_tr_list (work_case_item));
206 0 : while (work_result_item != DLListNULLIterator) {
207 0 : MIN_DEBUG ("result = %d",
208 : tr_get_result_type
209 : (work_result_item));
210 0 : work_result_item =
211 : dl_list_next (work_result_item);
212 : }
213 0 : work_case_item = dl_list_next (work_case_item);
214 : }
215 0 : work_module_item = dl_list_next (work_module_item);
216 : }
217 0 : MIN_DEBUG (">>>>>>>>>>>>>>>END OF SUMMARY<<<<<<<<<<<<<<<<<<<<<");
218 0 : DELETE (module_name);
219 0 : DELETE (case_title);
220 0 : min_log_close ();
221 :
222 0 : }
223 :
224 :
225 : /**Function used to select test case for execution - passed test case is
226 : * copied, and then copied case is added to "selected" list. As this function
227 : * modifies "selected" list, code that calls it should first lock "tec_mutex_",
228 : * and unlock it after executing the function.
229 : * @param work_case_item DLList item containing selected case
230 : * @param group_id id of group to which case belongs
231 : * @return item from "selected cases" list
232 : */
233 : DLListIterator ec_select_case (DLListIterator work_case_item, int group_id)
234 106 : {
235 :
236 :
237 106 : test_case_s *dest_case = INITPTR;
238 106 : test_result_s *test_result = INITPTR;
239 106 : DLListIterator selected_case = DLListNULLIterator;
240 : filename_t config;
241 : title_string_t title;
242 106 : DLListIterator work_result_item = DLListNULLIterator;
243 :
244 106 : tc_get_cfg_filename (work_case_item, config);
245 106 : tc_get_title (work_case_item, title);
246 :
247 106 : dest_case =
248 : tc_create (tc_get_test_module_ptr (work_case_item), config,
249 : title);
250 :
251 106 : selected_case = tc_add (selected_cases, dest_case);
252 :
253 106 : tc_set_group_id (selected_case, group_id);
254 106 : tc_set_id (selected_case, tc_get_id (work_case_item));
255 106 : tc_set_priority (work_case_item, tc_get_priority (work_case_item));
256 106 : dest_case->tc_ext_id_ = tc_get_ext_id (work_case_item);
257 :
258 106 : test_result = tr_create_data_item (selected_case);
259 106 : work_result_item =
260 : tr_add (tc_get_tr_list (selected_case), test_result);
261 :
262 106 : return selected_case;
263 : }
264 :
265 : /*---------------------------------------------------------------------------*/
266 :
267 : /** Function used to create shared memory segment and write settings to it,
268 : * so that they can be used by other processes (TMCs). Currently sent settings
269 : * are: logger's settings placed in apropriate structure, and search paths
270 : * (if there are any search paths defined), concatenated into one
271 : * NULL-terminated string, separated by ":" character. If program fails to
272 : * createshared memory segment, it will exit the application.
273 : */
274 : LOCAL void ec_settings_send ()
275 119 : {
276 :
277 119 : int shared_segm_id = 0;
278 119 : void *sh_mem_handle = NULL;
279 119 : int paths_size = 0;
280 119 : char *work_path = INITPTR;
281 119 : DLListIterator work_path_item = DLListNULLIterator;
282 119 : char *concat_paths = INITPTR;
283 : void *temp_ptr;
284 119 : work_path_item = dl_list_head (ec_settings.search_dirs);
285 :
286 476 : while (work_path_item != DLListNULLIterator) {
287 :
288 238 : work_path = (char *)dl_list_data (work_path_item);
289 238 : paths_size = paths_size + strlen (work_path) + 1;
290 238 : work_path_item = dl_list_next (work_path_item);
291 :
292 : }
293 :
294 119 : if (paths_size > 0) {
295 119 : concat_paths = NEW2 (char, paths_size);
296 119 : *concat_paths = '\0';
297 119 : work_path_item = dl_list_head (ec_settings.search_dirs);
298 476 : while (work_path_item != DLListNULLIterator) {
299 238 : work_path = (char *)dl_list_data (work_path_item);
300 238 : strcat (concat_paths, work_path);
301 238 : work_path_item = dl_list_next (work_path_item);
302 238 : if (work_path_item != DLListNULLIterator)
303 119 : strcat (concat_paths, ":");
304 : }
305 : }
306 : /*create shared memory segment */
307 119 : shared_segm_id =
308 : sm_create ('a', sizeof (struct logger_settings_t) + paths_size);
309 : /*
310 : ** Try to clean up
311 : */
312 :
313 119 : if (shared_segm_id < 0) {
314 1 : MIN_WARN ("failed to create shared memory segment "
315 : " - trying to clean up");
316 1 : system ("/usr/bin/min-clean.sh");
317 : }
318 :
319 :
320 119 : shared_segm_id =
321 : sm_create ('a', sizeof (struct logger_settings_t) + paths_size);
322 119 : if (shared_segm_id < 0) {
323 1 : MIN_FATAL ("Failed to create shared memory segment: %s",
324 : strerror (errno));
325 1 : min_log_close ();
326 : #ifdef MIN_UNIT_TEST
327 1 : exit (0);
328 : #endif
329 0 : exit (-1);
330 : }
331 :
332 118 : ec_settings.sh_mem_id_ = shared_segm_id;
333 118 : sh_mem_handle = sm_attach (shared_segm_id);
334 118 : sm_write (sh_mem_handle,
335 : (void *)(&logger_settings),
336 : sizeof (struct logger_settings_t));
337 118 : temp_ptr = sh_mem_handle + sizeof (struct logger_settings_t);
338 118 : if (paths_size > 0) {
339 118 : sm_write (temp_ptr, (void *)concat_paths, paths_size);
340 118 : DELETE (concat_paths);
341 : }
342 :
343 118 : sm_detach (sh_mem_handle);
344 118 : }
345 :
346 : /* ------------------------------------------------------------------------- */
347 : /** Function used check test case title agains filters
348 : * @param test case title string
349 : * @return 0 if the test case matches filter, 1 if not
350 : */
351 : LOCAL int
352 : ec_filter_it(char *title)
353 623 : {
354 : DLListIterator it;
355 : title_filter *filt;
356 : regex_t re;
357 : int val;
358 :
359 623 : if (filters == INITPTR)
360 593 : return 0;
361 :
362 : /*
363 : ** We have filters specified, see if the case should be filtered
364 : */
365 30 : for (it = dl_list_head(filters);
366 86 : it != DLListNULLIterator;
367 26 : it = dl_list_next(it)) {
368 30 : filt = dl_list_data (it);
369 30 : if (filt->regexp_ == 0 && !strcmp (title,
370 : tx_share_buf
371 : (filt->filter_)))
372 2 : return 0;
373 28 : if (filt->regexp_) {
374 10 : val = regcomp (&re, tx_share_buf (filt->filter_),
375 : REG_EXTENDED);
376 10 : if (val) {
377 0 : regfree (&re);
378 0 : continue; /* regcomp failed */
379 : }
380 10 : val = regexec (&re, title, 0, NULL, 0);
381 10 : regfree (&re);
382 10 : if (val == 0)
383 2 : return 0; /* Match */
384 : }
385 : }
386 :
387 26 : return 1;
388 : }
389 :
390 :
391 : /*---------------------------------------------------------------------------*/
392 : /** Function used to read logger settings. It was moved to separate function to
393 : * keep functions shorter. It uses section andf item parser functionalities to
394 : * write data to logger settings struct.
395 : * @param section fetched from config file
396 : */
397 : LOCAL void ec_get_logger_settings (MinSectionParser * settings)
398 238 : {
399 238 : MinItemParser *linebreaker = INITPTR; /* used if it is necessary
400 : to breakdown line into
401 : parts */
402 238 : char *opt_val = NULL; /* used to hold option value if
403 : * it is single */
404 238 : int fresult = 0;
405 :
406 238 : fresult = mmp_get_line (settings,
407 : "CreateLogDirectories=", &opt_val, ESNoTag);
408 238 : if (fresult == 0) {
409 119 : logger_settings.is_defined_.create_log_dir_ = ESTrue;
410 119 : if (strcasecmp (opt_val, "YES") == 0) {
411 119 : logger_settings.create_log_dir_ = ESTrue;
412 0 : } else if (strcasecmp (opt_val, "NO") == 0) {
413 0 : logger_settings.create_log_dir_ = ESFalse;
414 : } else {
415 0 : MIN_WARN ("Error in config file (CreateLogDirectories) !");
416 0 : logger_settings.is_defined_.create_log_dir_ = ESFalse;
417 : }
418 119 : DELETE (opt_val);
419 : }
420 :
421 238 : fresult = mmp_get_line (settings,
422 : "EmulatorBasePath=", &opt_val, ESNoTag);
423 238 : if (fresult == 0) {
424 238 : sprintf (logger_settings.emulator_path_, "%s", opt_val);
425 238 : logger_settings.is_defined_.path_ = ESTrue;
426 238 : DELETE (opt_val);
427 : }
428 :
429 238 : linebreaker = mmp_get_item_line (settings,
430 : "EmulatorFormat=", ESNoTag);
431 :
432 238 : if (linebreaker != INITPTR) {
433 238 : fresult = mip_get_string (linebreaker, "", &opt_val);
434 714 : while (fresult == 0) {
435 238 : if (strcasecmp (opt_val, "HTML") == 0) {
436 0 : logger_settings.emulator_format_ =
437 : logger_settings.emulator_format_ | ESHtml;
438 0 : logger_settings.is_defined_.format_ = ESTrue;
439 : }
440 238 : if (strcasecmp (opt_val, "TXT") == 0) {
441 238 : logger_settings.emulator_format_ =
442 : logger_settings.emulator_format_ | ESTxt;
443 238 : logger_settings.is_defined_.format_ = ESTrue;
444 : }
445 238 : if (strcasecmp (opt_val, "DATA") == 0) {
446 0 : logger_settings.emulator_format_ =
447 : logger_settings.emulator_format_ | ESData;
448 0 : logger_settings.is_defined_.format_ = ESTrue;
449 : }
450 238 : DELETE (opt_val);
451 238 : fresult = mip_get_next_string (linebreaker, &opt_val);
452 : }
453 : }
454 :
455 238 : mip_destroy (&linebreaker);
456 238 : linebreaker = mmp_get_item_line (settings,
457 : "EmulatorOutput=", ESNoTag);
458 :
459 238 : if (linebreaker != INITPTR) {
460 238 : fresult = mip_get_string (linebreaker, "", &opt_val);
461 714 : while (fresult == 0) {
462 238 : if (strcasecmp (opt_val, "NULL") == 0) {
463 0 : logger_settings.emulator_output_ =
464 : logger_settings.emulator_output_ | ESNull;
465 0 : logger_settings.is_defined_.output_ = ESTrue;
466 : }
467 238 : if (strcasecmp (opt_val, "FILE") == 0) {
468 119 : logger_settings.emulator_output_ =
469 : logger_settings.emulator_output_ | ESFile;
470 119 : logger_settings.is_defined_.output_ = ESTrue;
471 : }
472 238 : if (strcasecmp (opt_val, "SYSLOG") == 0) {
473 119 : logger_settings.emulator_output_ =
474 : logger_settings.
475 : emulator_output_ | ESSyslog;
476 119 : logger_settings.is_defined_.output_ = ESTrue;
477 : }
478 :
479 238 : DELETE (opt_val);
480 238 : fresult = mip_get_next_string (linebreaker, &opt_val);
481 : }
482 :
483 : }
484 :
485 238 : mip_destroy (&linebreaker);
486 :
487 238 : fresult = mmp_get_line (settings,
488 : "ThreadIdToLogFile=", &opt_val, ESNoTag);
489 238 : if (fresult == 0) {
490 238 : logger_settings.is_defined_.pidid_ = ESTrue;
491 238 : if (strcasecmp (opt_val, "YES") == 0) {
492 0 : logger_settings.pidid_ = ESTrue;
493 238 : } else if (strcasecmp (opt_val, "NO") == 0) {
494 238 : logger_settings.pidid_ = ESFalse;
495 : } else {
496 0 : MIN_WARN ("Error in config file (ThreadIdToLogFile) !");
497 0 : logger_settings.is_defined_.pidid_ = ESFalse;
498 : }
499 238 : DELETE (opt_val);
500 : }
501 :
502 238 : fresult = mmp_get_line (settings,
503 : "WithTimeStamp=", &opt_val, ESNoTag);
504 238 : if (fresult == 0) {
505 119 : logger_settings.is_defined_.time_stamp_ = ESTrue;
506 119 : if (strcasecmp (opt_val, "YES") == 0) {
507 119 : logger_settings.time_stamp_ = ESTrue;
508 0 : } else if (strcasecmp (opt_val, "NO") == 0) {
509 0 : logger_settings.time_stamp_ = ESFalse;
510 : } else {
511 0 : MIN_WARN ("Error in config file (WithTimeStamp) !");
512 0 : logger_settings.is_defined_.time_stamp_ = ESFalse;
513 : }
514 119 : DELETE (opt_val);
515 : }
516 :
517 238 : fresult = mmp_get_line (settings,
518 : "WithLineBreak=", &opt_val, ESNoTag);
519 238 : if (fresult == 0) {
520 119 : logger_settings.is_defined_.line_break_ = ESTrue;
521 119 : if (strcasecmp (opt_val, "YES") == 0) {
522 0 : logger_settings.line_break_ = ESTrue;
523 119 : } else if (strcasecmp (opt_val, "NO") == 0) {
524 119 : logger_settings.line_break_ = ESFalse;
525 : } else {
526 0 : MIN_WARN ("Error in config file (WithLineBreak) !");
527 0 : logger_settings.is_defined_.line_break_ = ESFalse;
528 : }
529 :
530 119 : DELETE (opt_val);
531 : }
532 :
533 238 : fresult = mmp_get_line (settings,
534 : "WithEventRanking=", &opt_val, ESNoTag);
535 238 : if (fresult == 0) {
536 119 : logger_settings.is_defined_.event_ranking_ = ESTrue;
537 119 : if (strcasecmp (opt_val, "YES") == 0) {
538 119 : logger_settings.event_ranking_ = ESTrue;
539 0 : } else if (strcasecmp (opt_val, "NO") == 0) {
540 0 : logger_settings.event_ranking_ = ESFalse;
541 : } else {
542 0 : MIN_WARN ("Error in config file (WithEventRanking) !");
543 0 : logger_settings.is_defined_.event_ranking_ = ESFalse;
544 : }
545 :
546 119 : DELETE (opt_val);
547 : }
548 :
549 238 : fresult = mmp_get_line (settings,
550 : "FileCreationMode=", &opt_val, ESNoTag);
551 238 : if (fresult == 0) {
552 119 : logger_settings.is_defined_.overwrite_ = ESTrue;
553 119 : if (strcasecmp (opt_val, "APPEND") == 0) {
554 119 : logger_settings.overwrite_ = ESFalse;
555 0 : } else if (strcasecmp (opt_val, "OVERWRITE") == 0) {
556 0 : logger_settings.overwrite_ = ESTrue;
557 : } else {
558 0 : logger_settings.is_defined_.overwrite_ = ESFalse;
559 0 : MIN_WARN ("Error in config file (FileCreationMode) !");
560 : }
561 :
562 119 : DELETE (opt_val);
563 : }
564 :
565 238 : fresult = mmp_get_line (settings,
566 : "LogLevel=", &opt_val, ESNoTag);
567 238 : if (fresult == 0) {
568 0 : if (strcasecmp (opt_val, "fatal") == 0) {
569 0 : logger_settings.loglevel_ = ESFatal;
570 0 : logger_settings.is_defined_.loglevel_ = ESTrue;
571 0 : } else if (strcasecmp (opt_val, "error")==0) {
572 0 : logger_settings.loglevel_ = ESError;
573 0 : logger_settings.is_defined_.loglevel_ = ESTrue;
574 0 : } else if (strcasecmp (opt_val, "warn")==0) {
575 0 : logger_settings.loglevel_ = ESWarning;
576 0 : logger_settings.is_defined_.loglevel_ = ESTrue;
577 0 : } else if (strcasecmp (opt_val, "info")==0) {
578 0 : logger_settings.loglevel_ = ESInfo;
579 0 : logger_settings.is_defined_.loglevel_ = ESTrue;
580 0 : } else if (strcasecmp (opt_val, "notice")==0) {
581 0 : logger_settings.loglevel_ = ESNotice;
582 0 : logger_settings.is_defined_.loglevel_ = ESTrue;
583 0 : } else if (strcasecmp (opt_val, "debug")==0) {
584 0 : logger_settings.loglevel_ = ESDebug;
585 0 : logger_settings.is_defined_.loglevel_ = ESTrue;
586 0 : } else if (strcasecmp (opt_val, "trace")==0) {
587 0 : logger_settings.loglevel_ = ESTrace;
588 0 : logger_settings.is_defined_.loglevel_ = ESTrue;
589 : } else {
590 0 : MIN_WARN ("Error in config file (LogLevel) !");
591 : }
592 0 : DELETE (opt_val);
593 : }
594 238 : }
595 :
596 : /**Function used for temporary module instantiation and test case execution,
597 : * used when there is a need to execute two test cases from the same module
598 : * in parallel.
599 : * @param work_case_item DLListItem containing test case to be executed
600 : */
601 : LOCAL int ec_start_module_temp (DLListIterator work_case_item)
602 7 : {
603 : /* this will be the module that will be used as a source of data for
604 : * instantiating temporary module */
605 7 : DLListIterator source_module_item = DLListNULLIterator;
606 : /* this will contain handle to temporaryily instantiated module */
607 7 : DLListIterator temporary_module_item = DLListNULLIterator;
608 : /* we will need also the copy of case to be executed */
609 7 : DLList *work_cases_list = dl_list_create ();
610 7 : DLList *cfgs_work_list = dl_list_create ();
611 7 : pid_t temp_mod_pid = 0;
612 : filename_t library_name;
613 7 : test_module_info_s *temporary_module = INITPTR;
614 :
615 7 : source_module_item = tc_get_test_module_ptr (work_case_item);
616 :
617 7 : tm_get_module_filename (source_module_item, library_name);
618 :
619 7 : temporary_module =
620 : tm_create (library_name,
621 : tm_get_cfg_filenames (source_module_item),
622 : tm_get_module_id (source_module_item));
623 7 : temporary_module_item =
624 : tm_add (instantiated_modules, temporary_module);
625 7 : tm_set_cfg_filenames (temporary_module_item, cfgs_work_list);
626 7 : temp_mod_pid = ec_start_tmc (temporary_module_item);
627 2 : if (temp_mod_pid == -1) {
628 0 : MIN_WARN ("Failed to create module");
629 0 : return -1;
630 :
631 : }
632 2 : tm_set_status (temporary_module_item, TEST_MODULE_INITIALIZED_TEMP);
633 2 : tm_set_tclist (temporary_module_item, work_cases_list);
634 2 : tm_set_pid (temporary_module_item, temp_mod_pid);
635 :
636 2 : tc_add (work_cases_list, dl_list_data (work_case_item));
637 2 : tc_set_test_module_ptr (work_case_item, temporary_module_item);
638 :
639 2 : return 1;
640 : }
641 :
642 : /*--------------------------------------------------------------------*/
643 :
644 : /** Function used to initialize logger_settings structure
645 : */
646 : LOCAL void ec_init_logger_settings ()
647 119 : {
648 119 : logger_settings.create_log_dir_ = ESFalse;
649 119 : logger_settings.unicode_ = ESFalse;
650 119 : logger_settings.time_stamp_ = ESFalse;
651 119 : logger_settings.pidid_ = ESFalse;
652 119 : logger_settings.overwrite_ = ESFalse;
653 119 : logger_settings.line_break_ = ESFalse;
654 119 : logger_settings.event_ranking_ = ESFalse;
655 119 : *logger_settings.emulator_path_ = '\0';
656 119 : logger_settings.emulator_output_ = ESNull;
657 119 : logger_settings.emulator_format_ = 0;
658 119 : logger_settings.is_defined_.create_log_dir_ = ESFalse;
659 119 : logger_settings.is_defined_.unicode_ = ESFalse;
660 119 : logger_settings.is_defined_.time_stamp_ = ESFalse;
661 119 : logger_settings.is_defined_.pidid_ = ESFalse;
662 119 : logger_settings.is_defined_.path_ = ESFalse;
663 119 : logger_settings.is_defined_.overwrite_ = ESFalse;
664 119 : logger_settings.is_defined_.output_ = ESFalse;
665 119 : logger_settings.is_defined_.line_break_ = ESFalse;
666 119 : logger_settings.is_defined_.hw_path_ = ESFalse;
667 119 : logger_settings.is_defined_.hw_output_ = ESFalse;
668 119 : logger_settings.is_defined_.hw_format_ = ESFalse;
669 119 : logger_settings.is_defined_.format_ = ESFalse;
670 119 : logger_settings.is_defined_.event_ranking_ = ESFalse;
671 119 : }
672 :
673 : /*-----------------------------------------------------------------------*/
674 :
675 : /** Function called to execute one test case. Prequisite: before calling this
676 : * function, case should be put in "selected_cases" list, and that's from
677 : * where argument should be taken.
678 : * @param work_case_item pointer to item from "selected_cases" containing
679 : * test case to be executed.
680 : * @return result of operation (TBD)
681 : */
682 : int ec_exec_case (DLListIterator work_case_item)
683 105 : {
684 :
685 105 : DLList *work_result_list = tc_get_tr_list (work_case_item);
686 : DLListIterator test_result_item;
687 : int work_module_status;
688 105 : test_case_s *work_case = INITPTR;
689 : MsgBuffer message;
690 105 : int res = -1;
691 : DLListIterator work_module_item =
692 105 : tc_get_test_module_ptr (work_case_item);
693 :
694 105 : if (work_module_item == INITPTR) {
695 0 : MIN_DEBUG (" exec case %x", work_case_item);
696 0 : MIN_WARN ("Faulty test case data");
697 0 : goto EXIT;
698 :
699 : }
700 :
701 105 : work_case = dl_list_data (work_case_item);
702 :
703 105 : if (work_case == DLListNULLIterator) {
704 :
705 0 : MIN_WARN ("Faulty test case data (2)");
706 0 : goto EXIT;
707 :
708 : }
709 105 : work_module_status = tm_get_status (work_module_item);
710 :
711 105 : switch (work_module_status) {
712 :
713 : case TEST_MODULE_READY:
714 98 : tm_set_status (work_module_item, TEST_MODULE_BUSY);
715 98 : tc_set_status (work_case_item, TEST_CASE_ONGOING);
716 98 : test_result_item = dl_list_head (work_result_list);
717 : /* it is enough to get "head of the list, since item in
718 : * selected list is just a copy of test case containing one
719 : * result in the list */
720 98 : tr_set_start_time (test_result_item, time (NULL));
721 98 : tr_set_priontouts_list (test_result_item, dl_list_create ());
722 98 : message.type_ = MSG_EXE;
723 98 : message.sender_ = ec_settings.engine_pid_;
724 98 : message.receiver_ = tm_get_pid (work_module_item);
725 98 : message.param_ = tc_get_id (work_case_item);
726 98 : STRCPY (message.desc_, "\0", MaxDescSize);
727 98 : tc_get_cfg_filename (work_case_item, message.message_);
728 98 : res = mq_send_message (mq_id, &message);
729 98 : break;
730 :
731 : case TEST_MODULE_BUSY:
732 7 : ec_start_module_temp (work_case_item);
733 2 : res = 0;
734 2 : break;
735 :
736 : default:
737 0 : MIN_WARN ("module status fault");
738 0 : res = -1;
739 :
740 : }
741 100 : EXIT:
742 100 : return res;
743 : }
744 :
745 :
746 :
747 :
748 : /**Function used to check if there is a test case with given group id
749 : * in "selected_cases" list waiting to be executed and runs it if it is the
750 : * case.
751 : * @param group_id - id og group of test cases in question.
752 : */
753 : LOCAL void ec_check_next_in_group (int group_id)
754 67 : {
755 :
756 67 : DLListIterator work_case_item = DLListNULLIterator;
757 :
758 67 : pthread_mutex_lock (&tec_mutex_);
759 :
760 67 : work_case_item = dl_list_head (selected_cases);
761 :
762 744 : while (work_case_item != DLListNULLIterator) {
763 :
764 669 : if ((tc_get_group_id (work_case_item) == group_id) &&
765 : (tc_get_status (work_case_item) == TEST_CASE_IDLE))
766 59 : break;
767 :
768 610 : work_case_item = dl_list_next (work_case_item);
769 : }
770 :
771 67 : pthread_mutex_unlock (&tec_mutex_);
772 :
773 67 : if (work_case_item != DLListNULLIterator) {
774 59 : ec_exec_case (work_case_item);
775 : }
776 :
777 : return;
778 : }
779 :
780 : /**Function for removal of temporary instantiated module.
781 : * @param work_module_item pointer to dllistitem containing module in question.
782 : */
783 : LOCAL int ec_remove_module_temp (DLListIterator work_module_item)
784 1 : {
785 :
786 : pthread_t threadid;
787 1 : long address = tm_get_pid (work_module_item);
788 : test_module_info_s *work_module =
789 1 : (test_module_info_s *) dl_list_data (work_module_item);
790 :
791 1 : mq_send_message2 (mq_id, address, MSG_END, 0, "Shut down !");
792 : #ifndef MIN_UNIT_TEST
793 : /*waitpid ( address, NULL, 0); */
794 0 : pthread_create (&threadid, NULL, (void *)&wait_for_pid,
795 : (void *)&address);
796 : #endif
797 1 : tm_delete (work_module);
798 1 : tm_remove (work_module_item);
799 :
800 1 : return 0;
801 : }
802 :
803 : /**Function used to start test case from temporarily instantianted module -
804 : * process is slightly different than starting test case from ordinary module.
805 : * "Temp" module has only one test case in list, so only that has to be passed
806 : * to this function is module item.
807 : * @param work_module_item pointer to dllistitem containg "current" module.
808 : */
809 : LOCAL int ec_exec_case_temp (DLListIterator work_module_item)
810 2 : {
811 : MsgBuffer message;
812 : DLListIterator work_result_item;
813 : DLListIterator work_case_item =
814 2 : dl_list_head (tm_get_tclist (work_module_item));
815 2 : test_case_s *work_case = dl_list_data (work_case_item);
816 :
817 : /*let's look for test case in "selected list" */
818 2 : pthread_mutex_lock (&tec_mutex_);
819 :
820 2 : work_case_item = dl_list_head (selected_cases);
821 :
822 6 : while (work_case_item != DLListNULLIterator) {
823 :
824 4 : if (dl_list_data (work_case_item) == work_case)
825 2 : break;
826 2 : work_case_item = dl_list_next (work_case_item);
827 :
828 : }
829 :
830 2 : pthread_mutex_unlock (&tec_mutex_);
831 :
832 2 : if (work_case_item == DLListNULLIterator) {
833 0 : MIN_WARN ("Test case not found in selected list");
834 0 : return -1;
835 : }
836 :
837 2 : tm_set_status (work_module_item, TEST_MODULE_BUSY_TEMP);
838 2 : tc_set_status (work_case_item, TEST_CASE_ONGOING);
839 2 : work_result_item = dl_list_head (tc_get_tr_list (work_case_item));
840 2 : tr_set_start_time (work_result_item, time (NULL));
841 2 : tr_set_priontouts_list (work_result_item, dl_list_create ());
842 :
843 : /*create and send message */
844 2 : message.type_ = MSG_EXE;
845 2 : message.sender_ = ec_settings.engine_pid_;
846 2 : message.receiver_ = tm_get_pid (work_module_item);
847 2 : message.param_ = tc_get_id (work_case_item);
848 2 : STRCPY (message.desc_, "\0", MaxDescSize);
849 2 : tc_get_cfg_filename (work_case_item, message.message_);
850 2 : mq_send_message (mq_id, &message);
851 :
852 2 : return 0;
853 : }
854 :
855 : /**Function for handling test results obtained from "temp" module
856 : * @param temp_module_item DLListIterator containing module to be worked on
857 : * @param message pointer to received message buffer
858 : */
859 : LOCAL int ec_handle_temp_results (DLListIterator temp_module_item,
860 : MsgBuffer * message)
861 0 : {
862 : /* This module has only one test case */
863 : DLListIterator work_case_item =
864 0 : dl_list_head (tm_get_tclist (temp_module_item));
865 0 : int group_id = tc_get_group_id (work_case_item);
866 : DLListIterator orig_case;
867 0 : DLListIterator work_module_item = DLListNULLIterator;
868 : DLListIterator temp_result;
869 0 : DLListIterator work_result_item = DLListNULLIterator;
870 0 : test_result_s *work_result = INITPTR;
871 : filename_t name;
872 : filename_t name2;
873 : filename_t work_conf;
874 : filename_t orig_conf;
875 : int id, id2;
876 0 : int result = 0;
877 0 : int it = 1; /*general purpose loop iterator */
878 :
879 0 : int cont_flag = 1;
880 : #ifndef MIN_EXTIF
881 : test_case_s *work_case;
882 : #endif
883 0 : work_module_item = dl_list_head (instantiated_modules);
884 0 : tm_get_module_filename (temp_module_item, name);
885 :
886 : /* first we will search for module that was the source for "temp",
887 : * using filename */
888 0 : while (work_module_item != DLListNULLIterator) {
889 0 : tm_get_module_filename (work_module_item, name2);
890 0 : it = strcmp (name, name2);
891 :
892 0 : if (it == 0) {
893 0 : tc_get_cfg_filename (work_case_item, work_conf);
894 0 : orig_case =
895 : dl_list_head (tm_get_tclist (work_module_item));
896 0 : if (orig_case == DLListNULLIterator)
897 0 : break;
898 0 : while (orig_case != DLListNULLIterator) {
899 0 : tc_get_cfg_filename (orig_case, orig_conf);
900 0 : if (strstr (work_conf, orig_conf) != NULL) {
901 0 : cont_flag = 0;
902 0 : break;
903 : } else
904 0 : orig_case = dl_list_next (orig_case);
905 : }
906 : }
907 :
908 0 : if (cont_flag == 1)
909 0 : work_module_item = dl_list_next (work_module_item);
910 : else
911 0 : break;
912 : }
913 :
914 0 : if (work_module_item == DLListNULLIterator) {
915 0 : MIN_WARN ("MODULE Data fault");
916 0 : return -1;
917 : }
918 :
919 : /*now we will search for original test case, using id and config
920 : filename */
921 0 : id = tc_get_id (work_case_item);
922 0 : tc_get_cfg_filename (work_case_item, work_conf);
923 0 : orig_case = dl_list_head (tm_get_tclist (work_module_item));
924 :
925 0 : while (orig_case != DLListNULLIterator) {
926 0 : tc_get_cfg_filename (orig_case, orig_conf);
927 0 : id2 = tc_get_id (orig_case);
928 0 : if ((id == id2) && (strcmp (work_conf, orig_conf) == 0))
929 : break;
930 : else
931 0 : orig_case = dl_list_next (orig_case);
932 : }
933 :
934 0 : if (orig_case == DLListNULLIterator) {
935 0 : MIN_WARN ("CASE Data fault");
936 0 : return -1;
937 : }
938 :
939 0 : work_result = tr_create_data_item (orig_case);
940 0 : work_result_item = tr_add (tc_get_tr_list (orig_case), work_result);
941 : /* since module was started to run just one case once, it will have
942 : * only one test result, from which we will now copy data to
943 : * original test case
944 : */
945 0 : temp_result = dl_list_head (tc_get_tr_list (work_case_item));
946 0 : tr_set_result_description (work_result_item, message->message_);
947 0 : tr_set_start_time (work_result_item, tr_get_start_time (temp_result));
948 0 : tr_set_result_description (work_result_item, message->message_);
949 0 : tr_set_end_time (work_result_item, time (NULL));
950 :
951 0 : switch (message->param_) {
952 : case TP_CRASHED:
953 0 : min_return_value ++;
954 0 : tr_set_result_type (work_result_item, TEST_RESULT_CRASHED);
955 0 : break;
956 :
957 : case TP_TIMEOUTED:
958 0 : min_return_value ++;
959 0 : tr_set_result_type (work_result_item, TEST_RESULT_TIMEOUT);
960 0 : break;
961 :
962 : case TP_PASSED:
963 0 : tr_set_result_type (work_result_item, TEST_RESULT_PASSED);
964 0 : break;
965 :
966 : case TP_FAILED:
967 0 : min_return_value ++;
968 0 : tr_set_result_type (work_result_item, TEST_RESULT_FAILED);
969 0 : break;
970 :
971 : case TP_NC:
972 0 : min_return_value ++;
973 0 : tr_set_result_type (work_result_item, TEST_RESULT_NOT_RUN);
974 0 : break;
975 :
976 : case TP_LEAVE:
977 0 : min_return_value ++;
978 0 : tr_set_result_type (work_result_item, TEST_RESULT_FAILED);
979 0 : break;
980 :
981 : default:
982 :
983 0 : MIN_WARN ("Faulty data received");
984 0 : return (-1);
985 :
986 : }
987 :
988 0 : tr_set_priontouts_list (work_result_item,
989 : tr_get_priontouts_list (temp_result));
990 0 : ((test_result_s *) dl_list_data (temp_result))->printouts_list_ =
991 : INITPTR;
992 :
993 :
994 0 : MINAPI_PLUGIN_CALL (case_result,
995 : case_result (tc_get_run_id (work_case_item),
996 : message->param_,
997 : message->message_,
998 : tr_get_start_time (work_result_item),
999 : tr_get_end_time (work_result_item)));
1000 :
1001 0 : pthread_mutex_lock (&tec_mutex_);
1002 :
1003 0 : work_case_item = dl_list_head (selected_cases);
1004 0 : while (work_case_item != DLListNULLIterator) {
1005 0 : if (tc_get_test_module_ptr (work_case_item) ==
1006 : temp_module_item)
1007 0 : break;
1008 0 : work_case_item = dl_list_next (work_case_item);
1009 : }
1010 0 : pthread_mutex_unlock (&tec_mutex_);
1011 :
1012 0 : if (work_case_item == DLListNULLIterator) {
1013 0 : MIN_WARN ("could not find case in list");
1014 0 : return -1;
1015 : }
1016 0 : work_module_item =
1017 : tm_get_ptr_by_pid (instantiated_modules, message->sender_);
1018 0 : tc_set_status (work_case_item, TEST_CASE_TERMINATED);
1019 : #ifndef MIN_EXTIF
1020 0 : work_case = (test_case_s *)dl_list_data (work_case_item);
1021 0 : if (work_case->ip_slave_case_) {
1022 0 : MIN_DEBUG ("ip slave case");
1023 0 : tcp_master_report (work_case->tc_run_id_, 1, message->param_,
1024 : message->desc_);
1025 :
1026 : }
1027 : #endif
1028 :
1029 0 : pthread_mutex_lock (&tec_mutex_);
1030 0 : pthread_mutex_unlock (&tec_mutex_);
1031 :
1032 0 : ec_remove_module_temp (work_module_item);
1033 0 : ec_check_next_in_group (group_id);
1034 0 : result = 1;
1035 :
1036 0 : return result;
1037 : }
1038 :
1039 : /** Function handling MSG_OK. As it is first message sent by module,
1040 : * function set's module status to TC_SENDING, initilaizes test cases list
1041 : * for module and sends message MSG_GTC
1042 : * @param message pointer to MsgBuffer structure containing message
1043 : * @return result of message handling, 0 if message handling was succesful,
1044 : * -1 otherwise
1045 : */
1046 : LOCAL int ec_msg_ok_handler (MsgBuffer * message)
1047 183 : {
1048 183 : int result = -1;
1049 183 : long sender = message->sender_;
1050 : int work_module_status;
1051 : int retry_count;
1052 : DLListIterator work_module =
1053 183 : tm_get_ptr_by_pid (instantiated_modules, sender);
1054 : MsgBuffer message_gtc;
1055 :
1056 : /*Possible error handling will be inserted here */
1057 183 : retry_count = 0;
1058 386 : while (work_module == DLListNULLIterator) {
1059 :
1060 22 : MIN_WARN ("Could not fetch module data, pid = %d", sender);
1061 : /*
1062 : ** Synchronization issue try again a few times
1063 : */
1064 22 : usleep (100000);
1065 22 : work_module =
1066 : tm_get_ptr_by_pid (instantiated_modules, sender);
1067 22 : retry_count++;
1068 22 : if (retry_count > 10)
1069 2 : return result;
1070 : }
1071 :
1072 181 : work_module_status = tm_get_status (work_module);
1073 :
1074 181 : switch (work_module_status) {
1075 : case TEST_MODULE_INITIALIZED:
1076 178 : tm_set_status (work_module, TEST_MODULE_TC_SENDING);
1077 178 : result = 0;
1078 178 : message_gtc.type_ = MSG_GTC;
1079 178 : message_gtc.sender_ = ec_settings.engine_pid_;
1080 178 : message_gtc.receiver_ = message->sender_;
1081 178 : message_gtc.param_ = 0;
1082 178 : message_gtc.special_ = ESTrue; /*TCDs should be sent */
1083 178 : mq_send_message (mq_id, &message_gtc);
1084 178 : break;
1085 :
1086 : case TEST_MODULE_INITIALIZED_TEMP:
1087 :
1088 3 : result = 0;
1089 3 : message_gtc.type_ = MSG_GTC;
1090 3 : message_gtc.sender_ = ec_settings.engine_pid_;
1091 3 : message_gtc.receiver_ = message->sender_;
1092 3 : message_gtc.param_ = 0;
1093 3 : message_gtc.special_ = ESFalse; /*don't care about
1094 : TCDs */
1095 3 : mq_send_message (mq_id, &message_gtc);
1096 3 : break;
1097 :
1098 : default:
1099 :
1100 0 : MIN_WARN ("Unexpected message sequence");
1101 0 : result = -1;
1102 : break;
1103 :
1104 : }
1105 :
1106 : #ifdef MIN_UNIT_TEST
1107 2 : unit_test_result = result;
1108 : #endif /*MIN_UNIT_TEST */
1109 :
1110 181 : return result;
1111 : }
1112 :
1113 : /**Function handling MSG_KO message, which means that some trouble occured on
1114 : * tmc's side. Hadling depends on state of module: if it's
1115 : * TEST_MODULE_INITIALIZED, it means that test case extraction is impossible.
1116 : * Module will be removed from "instantiated" list and terminated.Problems
1117 : * will be logged.
1118 : * @param message - pointer to MsgBuffer containing message
1119 : */
1120 : LOCAL int ec_msg_ko_handler (MsgBuffer * message)
1121 1 : {
1122 1 : int result = -1;
1123 1 : int status = 0;
1124 1 : DLListIterator work_module_item = DLListNULLIterator;
1125 : /*work module fetched from list of instantiated modules */
1126 :
1127 1 : work_module_item =
1128 : tm_get_ptr_by_pid (instantiated_modules, message->sender_);
1129 :
1130 1 : if (work_module_item == DLListNULLIterator) {
1131 :
1132 0 : MIN_WARN ("Could not fetch module data");
1133 0 : return result;
1134 : }
1135 :
1136 1 : status = tm_get_status (work_module_item);
1137 1 : switch (status) {
1138 : case TEST_MODULE_INITIALIZED:
1139 1 : mq_send_message2 (mq_id, message->sender_, MSG_END, 0,
1140 : "Useless module");
1141 1 : waitpid (message->sender_, NULL, 0);
1142 1 : dl_list_remove_it (work_module_item);
1143 1 : MIN_WARN ("Could not fetch test cases");
1144 1 : result = 0;
1145 1 : break;
1146 :
1147 : default:
1148 :
1149 0 : result = -1;
1150 0 : MIN_WARN ("Unexpected message sequence");
1151 : break;
1152 :
1153 : }
1154 :
1155 1 : return result;
1156 : }
1157 :
1158 : /**Function handling MSG_RET with test case results
1159 : * @param message - pointer to MsgBuffer containing message
1160 : */
1161 : LOCAL int ec_msg_ret_handler (MsgBuffer * message)
1162 74 : {
1163 :
1164 74 : DLListIterator work_case_item = INITPTR;
1165 74 : DLListIterator dest_case_item = INITPTR;
1166 74 : DLListIterator work_module_item = INITPTR;
1167 74 : test_case_s *work_case = INITPTR;
1168 74 : DLList *work_result_list = INITPTR;
1169 74 : DLListIterator work_result_item = INITPTR;
1170 : int group_id;
1171 : filename_t orig_conf;
1172 : filename_t work_conf;
1173 : test_result_s *result;
1174 74 : int fun_result = 0;
1175 : const char *test_result_type_str[] = {
1176 : "not run",
1177 : "passed",
1178 : "failed",
1179 : "crashed",
1180 : "aborted",
1181 : "timeout",
1182 : "all"
1183 74 : };
1184 :
1185 74 : work_module_item =
1186 : tm_get_ptr_by_pid (instantiated_modules, message->sender_);
1187 74 : if (work_module_item == DLListNULLIterator) {
1188 :
1189 1 : MIN_WARN ("Failed to fetch module data");
1190 1 : fun_result = -1;
1191 1 : goto EXIT;
1192 : }
1193 : /* if module was instantiated as temporary, handling is different
1194 : * since it was created only to run one test case
1195 : */
1196 73 : if (tm_get_status (work_module_item) == TEST_MODULE_BUSY_TEMP) {
1197 0 : ec_handle_temp_results (work_module_item, message);
1198 0 : fun_result = 1;
1199 0 : goto EXIT;
1200 : }
1201 : /* in current design, there is only one test case with status : ongoing
1202 : * belonging to module with given PID, so we search "selected cases"
1203 : * list for test case based on that information
1204 : */
1205 73 : pthread_mutex_lock (&tec_mutex_);
1206 :
1207 :
1208 73 : work_case_item = dl_list_head (selected_cases);
1209 690 : while (work_case_item != DLListNULLIterator) {
1210 :
1211 617 : work_case = (test_case_s *) dl_list_data (work_case_item);
1212 617 : if (((tc_get_status (work_case_item)) == TEST_CASE_ONGOING) &&
1213 : ((tm_get_pid (tc_get_test_module_ptr (work_case_item))) ==
1214 : message->sender_))
1215 : /* we found ongoing case with module matching message
1216 : * sender's pid, co we can stop
1217 : * iterating through list
1218 : */
1219 73 : break;
1220 544 : work_case_item = dl_list_next (work_case_item);
1221 :
1222 : }
1223 :
1224 73 : pthread_mutex_unlock (&tec_mutex_);
1225 :
1226 73 : if (work_case_item == DLListNULLIterator) {
1227 0 : fun_result = -1;
1228 0 : goto EXIT;
1229 : }
1230 :
1231 :
1232 73 : work_result_list = tc_get_tr_list (work_case_item);
1233 73 : if (work_result_list == INITPTR) {
1234 0 : MIN_WARN ("Fault in test data");
1235 0 : fun_result = -1;
1236 0 : goto EXIT;
1237 : }
1238 :
1239 73 : work_result_item = dl_list_head (work_result_list);
1240 73 : tr_set_result_description (work_result_item, message->message_);
1241 73 : tr_set_end_time (work_result_item, time (NULL));
1242 :
1243 73 : switch (message->param_) {
1244 :
1245 : case TP_CRASHED:
1246 0 : min_return_value ++;
1247 0 : tr_set_result_type (work_result_item, TEST_RESULT_CRASHED);
1248 0 : break;
1249 :
1250 : case TP_TIMEOUTED:
1251 0 : min_return_value ++;
1252 0 : tr_set_result_type (work_result_item, TEST_RESULT_TIMEOUT);
1253 0 : break;
1254 :
1255 : case TP_PASSED:
1256 :
1257 64 : tr_set_result_type (work_result_item, TEST_RESULT_PASSED);
1258 64 : break;
1259 :
1260 : case TP_FAILED:
1261 8 : min_return_value ++;
1262 8 : tr_set_result_type (work_result_item, TEST_RESULT_FAILED);
1263 8 : break;
1264 :
1265 : case TP_NC:
1266 1 : min_return_value ++;
1267 1 : tr_set_result_type (work_result_item, TEST_RESULT_ABORTED);
1268 1 : break;
1269 :
1270 : case TP_LEAVE:
1271 0 : min_return_value ++;
1272 0 : tr_set_result_type (work_result_item, TEST_RESULT_FAILED);
1273 0 : break;
1274 :
1275 : default:
1276 :
1277 0 : MIN_WARN ("Faulty data received");
1278 0 : fun_result = -1;
1279 0 : goto EXIT;
1280 : }
1281 73 : MIN_DEBUG ("RESULT CODE = %s (%d)",
1282 : test_result_type_str [tr_get_result_type
1283 : (work_result_item)],
1284 : tr_get_result_type (work_result_item));
1285 73 : tm_set_status (work_module_item, TEST_MODULE_READY);
1286 73 : tc_set_status (work_case_item, TEST_CASE_TERMINATED);
1287 73 : group_id = tc_get_group_id (work_case_item);
1288 :
1289 : /*if (in->case_result) in->case_result (tc_get_run_id (work_case_item),
1290 : message->param_,
1291 : message->message_,
1292 : tr_get_start_time
1293 : (work_result_item),
1294 : tr_get_end_time
1295 : (work_result_item));*/
1296 73 : MINAPI_PLUGIN_CALL (case_result,
1297 : case_result (tc_get_run_id (work_case_item),
1298 : message->param_,
1299 : message->message_,
1300 : tr_get_start_time
1301 : (work_result_item),
1302 : tr_get_end_time
1303 : (work_result_item)));
1304 :
1305 : #ifndef MIN_EXTIF
1306 67 : MIN_DEBUG ("is it ip slave case ?");
1307 67 : work_case = (test_case_s *)dl_list_data (work_case_item);
1308 67 : if (work_case->ip_slave_case_) {
1309 0 : MIN_DEBUG ("ip slave case");
1310 :
1311 0 : tcp_master_report (work_case->tc_run_id_, 1, message->param_,
1312 : message->desc_);
1313 :
1314 : }
1315 : #endif
1316 : /* Now let's link created result item to original test case.
1317 : * We will use module link, test case id and test case filename
1318 : */
1319 73 : dest_case_item = dl_list_head (tm_get_tclist (work_module_item));
1320 73 : tc_get_cfg_filename (work_case_item, work_conf);
1321 :
1322 :
1323 691 : while (dest_case_item != DLListNULLIterator) {
1324 618 : tc_get_cfg_filename (dest_case_item, orig_conf);
1325 618 : if ((tc_get_id (dest_case_item) == tc_get_id (work_case_item))
1326 : && (strcmp (work_conf, orig_conf) == 0)) {
1327 73 : break;
1328 : }
1329 545 : dest_case_item = dl_list_next (dest_case_item);
1330 : }
1331 73 : result = NEW (test_result_s);
1332 73 : memcpy (result,
1333 : dl_list_data (work_result_item), sizeof (test_result_s));
1334 73 : ((test_result_s *) dl_list_data (work_result_item))->printouts_list_ =
1335 : INITPTR;
1336 73 : work_result_item = tr_add (tc_get_tr_list (dest_case_item), result);
1337 :
1338 73 : ((test_result_s *) dl_list_data (work_result_item))->tc_data_item_ =
1339 : dest_case_item;
1340 : /*now add result to global "results" list */
1341 : /*dl_list_add(dl_list_data(work_result_item),results); */
1342 :
1343 73 : MIN_DEBUG ("orig_case has %d results now",
1344 : dl_list_size (tc_get_tr_list (dest_case_item)));
1345 73 : work_result_item = dl_list_head (tc_get_tr_list (dest_case_item));
1346 220 : while (work_result_item != DLListNULLIterator) {
1347 74 : MIN_DEBUG ("RESULT CODE = %s (%d)",
1348 : test_result_type_str
1349 : [tr_get_result_type (work_result_item)],
1350 : tr_get_result_type (work_result_item));
1351 :
1352 74 : work_result_item = dl_list_next (work_result_item);
1353 : }
1354 :
1355 :
1356 73 : if (group_id != 0)
1357 66 : ec_check_next_in_group (group_id);
1358 74 : EXIT:
1359 74 : return fun_result;
1360 : }
1361 :
1362 : /** Function handling MSG_TCD message. It creates new test_case_s structure and
1363 : * inserts it into
1364 : * apropriate module's case list.
1365 : * @param message - pointer to MsgBuffer containing message
1366 : * @return result of message handling, 0 if message was handled, -1 otherwise
1367 : */
1368 : LOCAL int ec_msg_tcd_handler (MsgBuffer * message)
1369 802 : {
1370 802 : int result = -1;
1371 802 : int work_module_status = 0;
1372 802 : int address = 0;
1373 802 : DLListIterator work_module_item = DLListNULLIterator;
1374 802 : DLListIterator work_case_item = DLListNULLIterator;
1375 802 : test_case_s *work_case = INITPTR;
1376 802 : DLList *work_tclist = INITPTR;
1377 :
1378 802 : work_module_item =
1379 : tm_get_ptr_by_pid (instantiated_modules, message->sender_);
1380 802 : if (work_module_item == DLListNULLIterator)
1381 0 : goto EXIT;
1382 :
1383 802 : work_module_status = tm_get_status (work_module_item);
1384 :
1385 802 : work_tclist = tm_get_tclist (work_module_item);
1386 802 : if (work_tclist == INITPTR)
1387 0 : goto EXIT;
1388 :
1389 802 : if (message->param_ == 0) {
1390 :
1391 179 : switch (work_module_status) {
1392 : case TEST_MODULE_TC_SENDING:
1393 177 : MIN_DEBUG ("finished tc gathering");
1394 177 : if (dl_list_size (tm_get_tclist (work_module_item)) ==
1395 : 0) {
1396 : /* something went wrong, module has 0 tcs,
1397 : * and can be removed - at least in current
1398 : * design
1399 : */
1400 : /*if (in->module_ready)
1401 : in->module_ready
1402 : (tm_get_module_id
1403 : (work_module_item));*/
1404 6 : MINAPI_PLUGIN_CALL (module_ready,
1405 : module_ready
1406 : (tm_get_module_id
1407 : (work_module_item)));
1408 6 : address = tm_get_pid (work_module_item);
1409 6 : mq_send_message2 (mq_id, address, MSG_END, 0,
1410 : "Shut down !");
1411 6 : tm_remove (work_module_item);
1412 6 : waitpid (address, NULL, 0);
1413 :
1414 6 : result = 0;
1415 6 : goto EXIT;
1416 : break;
1417 : } else {
1418 171 : tm_set_status (work_module_item,
1419 : TEST_MODULE_READY);
1420 171 : result = 0;
1421 : /*if (in->module_ready)
1422 : in->module_ready
1423 : (tm_get_module_id
1424 : (work_module_item));*/
1425 171 : MINAPI_PLUGIN_CALL (module_ready,
1426 : module_ready
1427 : (tm_get_module_id
1428 : (work_module_item)));
1429 171 : goto EXIT;
1430 : }
1431 : break;
1432 : case TEST_MODULE_INITIALIZED_TEMP:
1433 2 : tm_set_status (work_module_item,
1434 : TEST_MODULE_BUSY_TEMP);
1435 : /* first case from list will be fetched and executed,
1436 : * since temp module has only one case in list
1437 : */
1438 2 : result = ec_exec_case_temp (work_module_item);
1439 2 : goto EXIT;
1440 : break;
1441 : default:
1442 0 : MIN_WARN (" UNEXPECTED MESSAGE SEQUENCE ");
1443 0 : result = -1;
1444 0 : goto EXIT;
1445 : break;
1446 : }
1447 : }
1448 :
1449 623 : if (work_module_status == TEST_MODULE_TC_SENDING &&
1450 : !ec_filter_it(message->message_)) {
1451 597 : work_case =
1452 : tc_create (work_module_item, message->desc_,
1453 : message->message_);
1454 597 : work_case_item = tc_add (work_tclist, work_case);
1455 597 : tc_set_id (work_case_item, message->param_);
1456 597 : work_case->tc_ext_id_ =
1457 : dl_list_size (work_tclist);
1458 597 : MINAPI_PLUGIN_CALL (new_case,
1459 : new_case (tm_get_module_id
1460 : (work_module_item),
1461 : work_case->tc_ext_id_,
1462 : work_case->title_));
1463 : }
1464 623 : result = 0;
1465 802 : EXIT:
1466 802 : return result;
1467 : }
1468 :
1469 :
1470 : /** Function handling MSG_EVENT message.
1471 : * @param message - pointer to MsgBuffer containing message
1472 : * @return result of message handling, 0 if message was handled, -1 otherwise
1473 : */
1474 : LOCAL int ec_msg_event_handler (MsgBuffer * message)
1475 14 : {
1476 : minTestEventParam_t param;
1477 : minEventSrc_t esrc;
1478 14 : int result = 0;
1479 : int status;
1480 :
1481 14 : if (!event_system_up ()) {
1482 0 : MIN_WARN ("Event System is not initialized, can not handle "
1483 : "message");
1484 0 : result = -1;
1485 0 : goto EXIT;
1486 : }
1487 14 : param.event.event_type_ = (message->param_ >> 8) & 0xff;
1488 14 : param.command_ = message->param_ & 0xff;
1489 :
1490 14 : param.event.event_name_ = NEW2 (char, strlen (message->message_) + 1);
1491 :
1492 14 : STRCPY (param.event.event_name_, message->message_,
1493 : strlen (message->message_) + 1);
1494 :
1495 14 : esrc.remote = 0;
1496 14 : esrc.pid = message->special_;
1497 14 : switch (param.event.event_type_) {
1498 : case EIndication:
1499 4 : switch (param.command_) {
1500 : case EReqEvent:
1501 3 : MIN_DEBUG ("Indication Event: REQUEST");
1502 3 : ind_event_handle_request (¶m, &esrc);
1503 3 : break;
1504 : case EWaitEvent:
1505 0 : MIN_DEBUG ("Indication Event: WAIT");
1506 0 : ind_event_handle_wait (¶m, &esrc, &status);
1507 0 : break;
1508 : case ERelEvent:
1509 0 : MIN_DEBUG ("Indication Event: RELEASE");
1510 0 : ind_event_handle_release (¶m, &esrc);
1511 0 : break;
1512 : case ESetEvent:
1513 1 : MIN_DEBUG ("Indication Event: SET");
1514 1 : ind_event_handle_set (¶m, &esrc);
1515 1 : break;
1516 : case EUnsetEvent:
1517 0 : MIN_DEBUG ("Indication Event: UNSET N/A for"
1518 : " Indications");
1519 : break;
1520 : default:
1521 : break;
1522 : }
1523 4 : break;
1524 : case EState:
1525 10 : switch (param.command_) {
1526 : case EReqEvent:
1527 4 : MIN_DEBUG ("State Event: REQUEST");
1528 4 : state_event_handle_request (¶m, &esrc);
1529 4 : break;
1530 : case EWaitEvent:
1531 1 : MIN_DEBUG ("State Event: WAIT");
1532 1 : state_event_handle_wait (¶m, &esrc,
1533 : &status);
1534 1 : break;
1535 : case ERelEvent:
1536 1 : MIN_DEBUG ("State Event: RELEASE");
1537 1 : state_event_handle_release (¶m, &esrc);
1538 1 : break;
1539 : case ESetEvent:
1540 3 : MIN_DEBUG ("State Event: SET");
1541 3 : state_event_handle_set (¶m, &esrc);
1542 3 : break;
1543 : case EUnsetEvent:
1544 1 : MIN_DEBUG ("State Event: UNSET");
1545 1 : state_event_handle_unset (¶m, &esrc);
1546 : break;
1547 : default:
1548 : break;
1549 : }
1550 10 : break;
1551 : default:
1552 0 : MIN_WARN ("Unsupported event type %d\n",
1553 : param.event.event_type_);
1554 : break;
1555 : }
1556 :
1557 14 : DELETE (param.event.event_name_);
1558 14 : EXIT:
1559 14 : return result;
1560 : }
1561 :
1562 :
1563 : /** Function handling MSG_USR message. this message is used to pass
1564 : * "printouts" from test case to console UI. Handler will write received
1565 : * data to apropriate place in test result's printouts list according to
1566 : * priority of printout. Accessing proper
1567 : * test case/result data will be done in a way similar to MSG_RET handler.
1568 : * @param message pointer to MsgBuffer containing read message
1569 : * @return result of message handling, 0 if message was handled, -1 otherwise.
1570 : */
1571 : LOCAL int ec_msg_usr_handler (MsgBuffer * message)
1572 68 : {
1573 :
1574 68 : DLListIterator work_module_item = INITPTR;
1575 68 : DLListIterator work_case_item = INITPTR;
1576 68 : DLListIterator work_printout_item = INITPTR;
1577 68 : test_case_s *work_case = INITPTR;
1578 68 : DLListIterator work_result_item = INITPTR;
1579 68 : DLList *work_list = INITPTR;
1580 : test_result_printout_s *print_msg;
1581 68 : unsigned int it = 0; /*general purpose iterator */
1582 : int case_id;
1583 68 : int result = 0;
1584 :
1585 68 : work_module_item =
1586 : tm_get_ptr_by_pid (instantiated_modules, message->sender_);
1587 68 : print_msg = tr_create_printout (message->param_, message->message_);
1588 :
1589 : /*
1590 : ** Messages with descriction __error_console__ have a special handling
1591 : */
1592 68 : if (!strcmp (message->desc_, "__error_console__")) {
1593 : /*if (in->error_report) in->error_report (message->message_);*/
1594 2 : MINAPI_PLUGIN_CALL (error_report,
1595 : error_report (message->message_));
1596 2 : tr_remove_printout (print_msg);
1597 2 : goto EXIT;
1598 : }
1599 :
1600 66 : if (work_module_item == DLListNULLIterator) {
1601 0 : MIN_WARN ("Failed to fetch module data");
1602 0 : result = -1;
1603 0 : tr_remove_printout (print_msg);
1604 0 : goto EXIT;
1605 : }
1606 :
1607 : /* in current design, there is only one test case with status :
1608 : * ongoing belonging to module with given PID, so we search
1609 : * "selected cases" list for test case based on that
1610 : * information
1611 : */
1612 66 : pthread_mutex_lock (&tec_mutex_);
1613 :
1614 66 : case_id = 0;
1615 66 : work_case_item = dl_list_head (selected_cases);
1616 480 : while (work_case_item != DLListNULLIterator) {
1617 :
1618 414 : work_case = (test_case_s *) dl_list_data (work_case_item);
1619 :
1620 414 : if (((tc_get_status (work_case_item)) == TEST_CASE_ONGOING) &&
1621 : ((tm_get_pid (tc_get_test_module_ptr (work_case_item))) ==
1622 : message->sender_))
1623 : /* we found ongoing case with module matching message
1624 : * sender's pid, co we can stop iterating through list
1625 : */
1626 66 : break;
1627 348 : case_id++;
1628 348 : work_case_item = dl_list_next (work_case_item);
1629 :
1630 : }
1631 :
1632 66 : pthread_mutex_unlock (&tec_mutex_);
1633 :
1634 66 : if (work_case_item == DLListNULLIterator){
1635 0 : result = -1;
1636 0 : tr_remove_printout (print_msg);
1637 0 : goto EXIT;
1638 : }
1639 :
1640 66 : work_list = tc_get_tr_list (work_case_item);
1641 66 : if (work_list == INITPTR) {
1642 0 : MIN_WARN ("Fault in test data");
1643 0 : result = -1;
1644 0 : tr_remove_printout (print_msg);
1645 0 : goto EXIT;
1646 : }
1647 :
1648 66 : work_result_item = dl_list_head (work_list);
1649 132 : while (work_result_item != DLListNULLIterator) {
1650 66 : if (tr_get_result_type (work_result_item) ==
1651 : TEST_RESULT_NOT_RUN)
1652 66 : break;
1653 0 : work_result_item = dl_list_next (work_result_item);
1654 : }
1655 :
1656 : /*if (in->module_prints) in->module_prints (message->sender_,
1657 : message->message_);
1658 : MINAPI_PLUGIN_CALL (module_prints, module_prints (message->sender_,
1659 : message->message_));
1660 : Why twice ??
1661 : */
1662 66 : work_list = tr_get_priontouts_list (work_result_item);
1663 66 : work_printout_item = dl_list_head (work_list);
1664 356 : while (work_printout_item != DLListNULLIterator) {
1665 224 : if (((test_result_printout_s *)
1666 : dl_list_data (work_printout_item))->priority_ >
1667 : message->param_)
1668 0 : break;
1669 224 : it++;
1670 224 : work_printout_item = dl_list_next (work_printout_item);
1671 : }
1672 : //dl_list_add_at (work_list, ( void* ) print_msg, it);
1673 66 : dl_list_add (work_list, (void *)print_msg);
1674 : /*if (in->module_prints)
1675 : in->module_prints (tc_get_run_id (work_case_item),
1676 : message->message_);*/
1677 66 : MINAPI_PLUGIN_CALL(module_prints,
1678 : module_prints (tc_get_run_id (work_case_item),
1679 : message->message_));
1680 68 : EXIT:
1681 68 : return result;
1682 : }
1683 :
1684 :
1685 : /** Function handling MSG_RUN_ID message.
1686 : * @param message - pointer to MsgBuffer containing message
1687 : * @return result of message handling, 0 if message was handled, -1 otherwise
1688 : */
1689 : LOCAL int ec_msg_run_id_handler (MsgBuffer * message)
1690 95 : {
1691 95 : int result = -1;
1692 95 : DLListIterator work_module_item = DLListNULLIterator;
1693 95 : DLListIterator work_case_item = DLListNULLIterator;
1694 95 : test_case_s *work_case = INITPTR;
1695 :
1696 :
1697 95 : work_module_item =
1698 : tm_get_ptr_by_pid (instantiated_modules, message->sender_);
1699 95 : if (work_module_item == DLListNULLIterator)
1700 0 : goto EXIT;
1701 :
1702 95 : work_case_item = dl_list_head (selected_cases);
1703 736 : while (work_case_item != DLListNULLIterator) {
1704 :
1705 641 : work_case = (test_case_s *) dl_list_data (work_case_item);
1706 641 : if (((tc_get_status (work_case_item)) == TEST_CASE_ONGOING) &&
1707 : ((tm_get_pid (tc_get_test_module_ptr (work_case_item))) ==
1708 : message->sender_))
1709 95 : break;
1710 546 : work_case_item = dl_list_next (work_case_item);
1711 :
1712 : }
1713 95 : if (work_case_item == DLListNULLIterator)
1714 0 : goto EXIT;
1715 :
1716 95 : tc_set_run_id (work_case_item, message->param_);
1717 :
1718 95 : MINAPI_PLUGIN_CALL(case_started,
1719 : case_started(tm_get_module_id(work_module_item),
1720 : tc_get_ext_id (work_case_item),
1721 : tc_get_run_id (work_case_item)));
1722 :
1723 :
1724 95 : result = 0;
1725 95 : EXIT:
1726 95 : return result;
1727 : }
1728 :
1729 : /** Function called to dispatch message - it recognizes message type and
1730 : * calls function that handles message. If received message is not of the type
1731 : * expected by engine, function logs error information.
1732 : * @param message - pointer to received MsgBuffer
1733 : * @return result of message handling, 0 if message was handled, -1 otherwise.
1734 : */
1735 : LOCAL int ec_message_dispatch (MsgBuffer * rcvd_message)
1736 1243 : {
1737 1243 : int msg_handling_result = -1;
1738 :
1739 1243 : MIN_DEBUG ("MsgBuffer::message = %s", rcvd_message->message_);
1740 1243 : MIN_DEBUG ("MsgBuffer::desc = %s", rcvd_message->desc_);
1741 1243 : MIN_DEBUG ("MsgBuffer::type = %d", rcvd_message->type_);
1742 1243 : switch (rcvd_message->type_) {
1743 : case MSG_OK:
1744 :
1745 183 : msg_handling_result = ec_msg_ok_handler (rcvd_message);
1746 183 : break;
1747 :
1748 : case MSG_USR:
1749 :
1750 68 : msg_handling_result = ec_msg_usr_handler (rcvd_message);
1751 68 : break;
1752 :
1753 : case MSG_RET:
1754 :
1755 74 : msg_handling_result = ec_msg_ret_handler (rcvd_message);
1756 74 : break;
1757 :
1758 : case MSG_KO:
1759 :
1760 1 : msg_handling_result = ec_msg_ko_handler (rcvd_message);
1761 1 : break;
1762 :
1763 : case MSG_TCD:
1764 :
1765 801 : msg_handling_result = ec_msg_tcd_handler (rcvd_message);
1766 801 : break;
1767 :
1768 : case MSG_EVENT:
1769 14 : msg_handling_result = ec_msg_event_handler (rcvd_message);
1770 14 : break;
1771 : case MSG_EXTIF:
1772 6 : msg_handling_result = ec_msg_ms_handler (rcvd_message);
1773 6 : break;
1774 : case MSG_SNDRCV:
1775 0 : msg_handling_result = ec_msg_sndrcv_handler (rcvd_message);
1776 0 : break;
1777 : case MSG_RUN_ID:
1778 95 : msg_handling_result = ec_msg_run_id_handler (rcvd_message);
1779 95 : break;
1780 :
1781 : default:
1782 :
1783 1 : MIN_WARN ("Faulty message received of type: %d",
1784 : rcvd_message->type_);
1785 : }
1786 :
1787 1243 : return msg_handling_result;
1788 :
1789 : }
1790 :
1791 :
1792 : /** Function that is the basis for message listening thread. Contains while
1793 : * loop that checks messages in queue and calls ec_msg_dispatch to handle any
1794 : * message
1795 : * @param arg some dummy pointer, to keep compiler from complaining
1796 : */
1797 : LOCAL void *ec_message_listener (void *arg)
1798 124 : {
1799 :
1800 124 : int handling_result = 0;
1801 124 : long own_address = 0;
1802 124 : unsigned long wait_time = 2; /*time in miliseconds that thread
1803 : spends sleeping during periods
1804 : with no IPC traffic */
1805 : MsgBuffer received_msg;
1806 :
1807 124 : pthread_mutex_lock (&tec_mutex_);
1808 : /* Engine's process id was made global, because passing it to message
1809 : * listener function as a pointer has proven to be unreliable,
1810 : * especially on ARM targets.
1811 : */
1812 124 : own_address = ec_settings.engine_pid_;
1813 124 : pthread_mutex_unlock (&tec_mutex_);
1814 :
1815 : #ifdef MIN_UNIT_TEST
1816 7 : unit_test_result = 1;
1817 : #endif /*MIN_UNIT_TEST */
1818 : while (1) {
1819 5449 : handling_result = mq_peek_message (mq_id, own_address);
1820 5449 : if (handling_result != 0) {
1821 1238 : wait_time = 2;
1822 1238 : handling_result =
1823 : mq_read_message (mq_id, own_address,
1824 : &received_msg);
1825 1238 : if (handling_result > 8) {
1826 1238 : ec_message_dispatch (&received_msg);
1827 : } else {
1828 0 : MIN_WARN ("Message_handling_fault");
1829 : }
1830 : } else {
1831 4211 : if (errno == EINVAL) {
1832 19 : MIN_INFO ("Message queue was destroyed,"
1833 : " exiting listener thread");
1834 19 : pthread_exit (NULL);
1835 : } else {
1836 4192 : if (wait_time < 200000)
1837 2868 : wait_time = wait_time * 10;
1838 : /*sleep should not be longer than 0.2 sec. */
1839 4192 : usleep (wait_time);
1840 : }
1841 : }
1842 :
1843 :
1844 :
1845 : #ifdef MIN_UNIT_TEST
1846 38 : unit_test_result = handling_result;
1847 : #endif
1848 5325 : }
1849 :
1850 : return NULL;
1851 : }
1852 :
1853 : /*-----------------------------------------------------------------------*/
1854 : /** Function that wraps test module controller process starting. In case of
1855 : * failure to start a module, information will be logged.
1856 : * @param work_module_item item from available modules list
1857 : * @return pid of newly created process, or -1 in case of failure*/
1858 :
1859 : LOCAL pid_t ec_start_tmc (DLListIterator work_module_item)
1860 257 : {
1861 257 : char **exec_args = NULL;
1862 :
1863 : DLListIterator work_file_item;
1864 257 : char *mod_fpath = NULL;
1865 257 : char *mod_fpath_new = NULL;
1866 257 : char *dir = NULL;
1867 257 : char *mod_name = NULL;
1868 257 : char *conf_name = NULL;
1869 257 : char *conf_path = NULL;
1870 :
1871 257 : int it = 0; /*general purpose loop iterator */
1872 : /*position of directory in search paths list */
1873 257 : int path_pos = 0;
1874 257 : int result = -1;
1875 257 : int retval = -1;
1876 257 : pid_t res_pid = 0;
1877 :
1878 : DLList *work_list;
1879 :
1880 257 : work_list = tm_get_cfg_filenames (work_module_item);
1881 257 : exec_args = NEW2 (char *, dl_list_size (work_list) + 3);
1882 257 : exec_args[it++] = ec_settings.tmc_app_path_;
1883 :
1884 257 : if (*((test_module_info_s *) dl_list_data (work_module_item))->
1885 : module_filename_ == '/') {
1886 11 : mod_fpath =
1887 : ((test_module_info_s *) dl_list_data (work_module_item))->
1888 : module_filename_;
1889 11 : result = access (mod_fpath, F_OK);
1890 11 : if (result != 0) {
1891 0 : MIN_WARN ("Module not found %s",mod_fpath);
1892 0 : retval = -1;
1893 0 : goto out;
1894 : }
1895 : } else {
1896 246 : mod_name =
1897 : NEW2 (char,
1898 : strlen (((test_module_info_s *)
1899 : dl_list_data (work_module_item))->
1900 : module_filename_) + 4);
1901 246 : sprintf (mod_name, "%s.so",
1902 : ((test_module_info_s *)
1903 : dl_list_data (work_module_item))->module_filename_);
1904 246 : path_pos = ec_search_lib (mod_name);
1905 :
1906 246 : if (path_pos != -1) {
1907 245 : dir =
1908 : (char *)
1909 : dl_list_data (dl_list_at
1910 : (ec_settings.search_dirs,
1911 : path_pos));
1912 245 : mod_fpath_new =
1913 : NEW2 (char, strlen (dir) + strlen (mod_name) + 2);
1914 245 : mod_fpath = mod_fpath_new;
1915 245 : sprintf (mod_fpath, "%s/%s", dir, mod_name);
1916 : }
1917 : }
1918 :
1919 257 : if (mod_fpath == NULL) {
1920 1 : MIN_WARN ("Module not found");
1921 1 : retval = -1;
1922 1 : goto out;
1923 : }
1924 256 : exec_args[it++] = mod_fpath;
1925 256 : work_file_item = dl_list_head (work_list);
1926 569 : while (work_file_item != DLListNULLIterator) {
1927 57 : conf_name = (char *)dl_list_data (work_file_item);
1928 57 : work_file_item = dl_list_next (work_file_item);
1929 57 : if (*conf_name == '/') {
1930 : /*config file was defined as full path */
1931 2 : conf_path = NEW2 (char, strlen (conf_name) + 1);
1932 2 : sprintf (conf_path, "%s", conf_name);
1933 2 : exec_args[it++] = conf_path;
1934 2 : continue;
1935 : }
1936 :
1937 55 : conf_path = NEW2 (char, strlen (conf_name) +
1938 : strlen ((char *)
1939 : dl_list_data (dl_list_at
1940 : (ec_settings.
1941 : search_dirs,
1942 : path_pos))) + 2);
1943 55 : sprintf (conf_path, "%s/%s",
1944 : (char *)
1945 : dl_list_data (dl_list_at
1946 : (ec_settings.search_dirs, path_pos)),
1947 : conf_name);
1948 : /* now check if config exists in the same directory as
1949 : module */
1950 55 : result = access (conf_path, F_OK);
1951 55 : if (result == 0) {
1952 0 : exec_args[it++] = conf_path;
1953 0 : continue;
1954 : }
1955 : /*config not found so far, let's look for it in search
1956 : paths */
1957 55 : path_pos = ec_search_lib (conf_name);
1958 55 : if (path_pos != -1) {
1959 55 : dir =
1960 : (char *)
1961 : dl_list_data (dl_list_at
1962 : (ec_settings.search_dirs,
1963 : path_pos));
1964 55 : if (conf_path)
1965 55 : DELETE (conf_path);
1966 55 : conf_path =
1967 : NEW2 (char,
1968 : strlen (dir) + strlen (conf_name) + 2);
1969 55 : sprintf (conf_path, "%s/%s", dir, conf_name);
1970 55 : exec_args[it++] = conf_path;
1971 55 : continue;
1972 : }
1973 0 : MIN_WARN ("specified config not found : %s", conf_name);
1974 0 : retval = -1;
1975 0 : goto out;
1976 :
1977 : }
1978 256 : exec_args[it++] = NULL;
1979 256 : res_pid = fork ();
1980 313 : switch (res_pid) {
1981 : case -1:
1982 0 : MIN_FATAL ("Failed to create process !");
1983 0 : break;
1984 : case 0:
1985 125 : sched_yield ();
1986 125 : execve (exec_args[0], exec_args, envp);
1987 5 : MIN_FATAL ("Failed to load test module controller app :%s",
1988 : strerror (errno));
1989 5 : exit (-1);
1990 : break;
1991 : default:
1992 : break;
1993 : };
1994 188 : tm_set_pid (work_module_item, res_pid);
1995 188 : retval = res_pid;
1996 189 : out:
1997 189 : DELETE (exec_args);
1998 189 : DELETE (mod_fpath_new);
1999 189 : DELETE (mod_name);
2000 189 : DELETE (conf_path);
2001 189 : return retval;
2002 : }
2003 :
2004 :
2005 : /** Function that initializes data for instantiated module
2006 : * @param work_module_item list item with module
2007 : * @param proc_id PID of associated TMC process
2008 : * @return always 0
2009 : */
2010 : LOCAL int ec_init_module_data (DLListItem * work_module_item)
2011 187 : {
2012 :
2013 187 : int result = 0;
2014 : DLList *cases_list;
2015 :
2016 187 : tm_set_status (work_module_item, TEST_MODULE_INITIALIZED);
2017 187 : cases_list = dl_list_create ();
2018 187 : tm_set_tclist (work_module_item, cases_list);
2019 :
2020 187 : return result;
2021 : }
2022 :
2023 : /** Function that instantializes all modules from available moduls list at
2024 : * startup of the application.
2025 : * @return: number of started modules
2026 : */
2027 : int ec_start_modules ()
2028 120 : {
2029 :
2030 120 : int result = 0;
2031 120 : pid_t module_started = 0;
2032 : test_module_info_s *work_module;
2033 120 : DLListIterator work_list_item = dl_list_head (available_modules);
2034 : DLListIterator result_list_item;
2035 120 : int opresult = 0;
2036 :
2037 120 : MIN_DEBUG ("%d available modules",
2038 : dl_list_size (available_modules));
2039 :
2040 120 : work_module = (test_module_info_s *) dl_list_data (work_list_item);
2041 284 : while (work_list_item != DLListNULLIterator) {
2042 44 : module_started = ec_start_tmc (work_list_item);
2043 :
2044 44 : if (module_started > 0) {
2045 44 : result_list_item =
2046 : tm_add (instantiated_modules, work_module);
2047 44 : opresult = ec_init_module_data (result_list_item);
2048 44 : if (opresult < 0)
2049 0 : MIN_WARN ("Failed to initialize "
2050 : "data for module");
2051 : /* To be decided if additional handling of that
2052 : * fault is needed
2053 : */
2054 44 : result++;
2055 : }
2056 :
2057 44 : work_list_item = dl_list_next (work_list_item);
2058 :
2059 44 : if (work_list_item != DLListNULLIterator) {
2060 26 : work_module = dl_list_data (work_list_item);
2061 : }
2062 : }
2063 :
2064 120 : return result;
2065 : }
2066 :
2067 : LOCAL int ec_read_module_section (MinParser * inifile)
2068 42 : {
2069 42 : test_module_info_s *module = INITPTR;
2070 42 : DLListIterator module_item = DLListNULLIterator;
2071 42 : MinSectionParser *module_def = INITPTR;
2072 : MinItemParser *line_item;
2073 42 : char *bin_path = INITPTR, *tc_file_path = NULL;
2074 42 : int it = 1;
2075 : DLList *work_list;
2076 :
2077 :
2078 42 : module_def = mp_section (inifile, "[New_Module]", "[End_Module]", it);
2079 :
2080 126 : while (module_def != INITPTR) {
2081 :
2082 :
2083 42 : line_item = mmp_get_item_line(module_def,
2084 : "ModuleName",
2085 : ESTag);
2086 :
2087 42 : if (line_item == INITPTR){
2088 0 : MIN_WARN ("Data fault!");
2089 0 : break;
2090 : }
2091 :
2092 42 : mip_get_string(line_item,
2093 : "ModuleName",
2094 : &bin_path);
2095 :
2096 :
2097 42 : if (bin_path == INITPTR) {
2098 0 : MIN_WARN ("Could not read module definition");
2099 0 : break;
2100 : }
2101 : /* make dummy list of cfgs for now */
2102 :
2103 42 : work_list = dl_list_create ();
2104 42 : module = tm_create (bin_path, work_list, 0);
2105 42 : module_item = tm_add (available_modules, module);
2106 : /*if (in->new_module) {
2107 : in->new_module (bin_path, module->module_id_);
2108 : }*/
2109 42 : MINAPI_PLUGIN_CALL(new_module,
2110 : new_module (bin_path, module->module_id_));
2111 :
2112 42 : if (module_item == DLListNULLIterator) {
2113 0 : MIN_WARN ("Could not insert %s into list",
2114 : bin_path);
2115 0 : break;
2116 : }
2117 :
2118 : /* Now let's read test case files, tag : TestCaseFile= */
2119 : do {
2120 56 : DELETE (bin_path);
2121 56 : mip_destroy(&line_item);
2122 :
2123 56 : line_item = mmp_get_next_item_line(module_def);
2124 :
2125 56 : mip_get_string(line_item,
2126 : "TestCaseFile",
2127 : &bin_path);
2128 :
2129 :
2130 :
2131 56 : if (bin_path != INITPTR) {
2132 14 : tc_file_path = NEW2 (char,
2133 : strlen (bin_path) + 2);
2134 14 : STRCPY (tc_file_path, bin_path,
2135 : strlen (bin_path) + 1);
2136 14 : dl_list_add (work_list, (void *)tc_file_path);
2137 : }
2138 :
2139 56 : } while (bin_path != INITPTR);;
2140 :
2141 42 : mmp_destroy (&module_def);
2142 42 : it++;
2143 :
2144 42 : module_def = mp_section (inifile,
2145 : "[New_Module]", "[End_Module]", it);
2146 :
2147 : }
2148 42 : return 0;
2149 : }
2150 :
2151 : #ifndef MIN_EXTIF
2152 : LOCAL int ec_read_slaves_section (MinParser * inifile)
2153 25 : {
2154 25 : char *hostname = NULL;
2155 25 : char *slavetype = NULL;
2156 : MinSectionParser *slave_def;
2157 : MinItemParser *line;
2158 25 : struct addrinfo hints, *result = NULL;
2159 25 : int i = 1, ret;
2160 :
2161 25 : slave_def = mp_section (inifile, "[Slaves]", "[End_Slaves]", i);
2162 65 : while (slave_def != INITPTR) {
2163 :
2164 15 : line = mmp_get_item_line (slave_def, "", ESNoTag);
2165 :
2166 45 : while (line != INITPTR) {
2167 15 : ret = mip_get_string (line, "", &hostname);
2168 15 : if (ret != ENOERR) {
2169 0 : MIN_WARN ("error parsing slaves section:"
2170 : "no hostname specified");
2171 0 : goto next_line;
2172 : }
2173 :
2174 15 : memset(&hints, 0, sizeof(struct addrinfo));
2175 15 : hints.ai_family = AF_INET;
2176 15 : hints.ai_socktype = SOCK_STREAM;
2177 15 : hints.ai_flags = 0;
2178 15 : hints.ai_protocol = 0;
2179 :
2180 15 : ret = getaddrinfo(hostname, "51551", &hints, &result);
2181 15 : if (ret != 0) {
2182 0 : MIN_WARN ("failed to resolve host %s: %s",
2183 : strerror (h_errno));
2184 0 : return 1;
2185 : }
2186 :
2187 :
2188 15 : mip_get_next_string (line, &slavetype);
2189 :
2190 15 : tec_add_ip_slave_to_pool (&result,
2191 : slavetype ?
2192 : slavetype : "phone");
2193 15 : result = NULL;
2194 15 : DELETE (slavetype);
2195 15 : DELETE (hostname);
2196 15 : next_line:
2197 15 : mip_destroy(&line);
2198 :
2199 15 : line = mmp_get_next_item_line (slave_def);
2200 : }
2201 15 : mmp_destroy (&slave_def);
2202 15 : i ++;
2203 15 : slave_def = mp_section (inifile, "[Slaves]", "[End_Slaves]", i);
2204 : }
2205 :
2206 25 : return 0;
2207 : }
2208 : #endif /* ndef MIN_EXTIF */
2209 : LOCAL int ec_read_module_confdir ()
2210 14 : {
2211 :
2212 : DIR *dir;
2213 : struct dirent *dirent;
2214 14 : MinParser *modfile = INITPTR;
2215 :
2216 14 : dir = opendir ("/etc/min.d");
2217 :
2218 14 : if (dir == NULL) {
2219 0 : MIN_WARN ("directory /etc/min.d missing");
2220 0 : return 1;
2221 : }
2222 :
2223 14 : dirent = readdir (dir);
2224 70 : while (dirent != NULL) {
2225 42 : if (dirent->d_type == DT_LNK || dirent->d_type == DT_REG) {
2226 14 : modfile = mp_create ("/etc/min.d/",
2227 : dirent->d_name, ENoComments);
2228 14 : ec_read_module_section (modfile);
2229 : #ifndef MIN_EXTIF
2230 5 : ec_read_slaves_section (modfile);
2231 : #endif
2232 : }
2233 42 : dirent = readdir (dir);
2234 : }
2235 :
2236 14 : closedir (dir);
2237 :
2238 14 : return 0;
2239 : }
2240 :
2241 : /** Function reads data from config file given as argument
2242 : */
2243 : LOCAL int ec_read_conf (MinParser * inifile, int operation_mode)
2244 238 : {
2245 238 : MinSectionParser *engine_def = INITPTR;
2246 238 : MinSectionParser *logger_def = INITPTR;
2247 238 : MinItemParser *line_item = INITPTR;
2248 : struct stat tmcstat;
2249 238 : char *search_path = INITPTR;
2250 238 : char *path_string = NULL;
2251 238 : char *bin_path = INITPTR;
2252 238 : char *locdir = NULL;
2253 238 : char *home_d = getenv ("HOME");
2254 : /*int res = 0;for checking funtion return values */
2255 :
2256 : /*read engine's settings */
2257 238 : engine_def = mp_section (inifile,
2258 : "[Engine_Defaults]", "[End_Defaults]", 1);
2259 :
2260 238 : if (engine_def == INITPTR) {
2261 119 : MIN_FATAL ("For information about mandatory min.conf"
2262 : " contents refer to manual");
2263 : }
2264 :
2265 :
2266 238 : line_item = mmp_get_item_line(engine_def,
2267 : "TmcBinPath",
2268 : ESTag);
2269 :
2270 238 : mip_get_string(line_item,
2271 : "TmcBinPath",
2272 : &bin_path);
2273 :
2274 :
2275 238 : if (bin_path == INITPTR) {
2276 238 : bin_path = NEW2(char,
2277 : strlen(MIN_BIN_DIR) + strlen("/tmc") + 1 );
2278 238 : sprintf (bin_path, "%s/tmc", MIN_BIN_DIR);
2279 : }
2280 :
2281 : /*
2282 : ** Check if tmc lies in the specified place
2283 : */
2284 238 : memset (&tmcstat, 0, sizeof (struct stat));
2285 238 : if (stat (bin_path, &tmcstat)) {
2286 0 : MIN_FATAL ("TMC binary not available: %s. Exiting..\n",
2287 : strerror (errno));
2288 0 : goto err_exit;
2289 : }
2290 238 : if (!(tmcstat.st_mode & S_IXUSR &&
2291 : tmcstat.st_mode & S_IXGRP &&
2292 : tmcstat.st_mode & S_IXOTH)) {
2293 0 : MIN_FATAL ("TMC binary %s does not have execution permission."
2294 : "Exiting..\n", bin_path);
2295 0 : goto err_exit;
2296 :
2297 : }
2298 238 : STRCPY (ec_settings.tmc_app_path_, bin_path, MaxFileName);
2299 :
2300 :
2301 238 : if (line_item != INITPTR) mip_destroy(&line_item);
2302 :
2303 238 : line_item = mmp_get_item_line(engine_def,
2304 : "ModSearchPath",
2305 : ESTag);
2306 :
2307 238 : mip_get_string(line_item,
2308 : "ModSearchPath",
2309 : &search_path);
2310 :
2311 714 : while (search_path != INITPTR) {
2312 238 : if (strstr (search_path, "$HOME") == NULL) {
2313 119 : path_string = NEW2 (char, strlen (search_path) + 1);
2314 119 : sprintf (path_string, "%s", search_path);
2315 119 : dl_list_add (ec_settings.search_dirs,
2316 : (void *)path_string);
2317 : } else {
2318 119 : if (home_d == NULL) {
2319 0 : MIN_WARN ("$HOME == NULL, not adding "
2320 : "%s to engine settings",
2321 : search_path);
2322 0 : goto next_item;
2323 : }
2324 119 : locdir = strchr (search_path, '/');
2325 119 : if (locdir != NULL) {
2326 119 : path_string =
2327 : NEW2 (char,
2328 : strlen (locdir)
2329 : + strlen (home_d) +
2330 : 1);
2331 119 : sprintf (path_string, "%s%s", home_d, locdir);
2332 119 : dl_list_add (ec_settings.search_dirs,
2333 : (void *)path_string);
2334 : } else {
2335 0 : MIN_WARN ("Invalid path");
2336 : }
2337 : }
2338 238 : next_item:
2339 238 : mip_destroy(&line_item);
2340 238 : line_item = mmp_get_next_item_line(engine_def);
2341 238 : DELETE(search_path);
2342 238 : mip_get_string(line_item,
2343 : "ModSearchPath",
2344 : &search_path);
2345 :
2346 :
2347 : }
2348 238 : if (bin_path != INITPTR) {
2349 238 : DELETE (bin_path);
2350 : }
2351 238 : mmp_destroy (&engine_def);
2352 : /* check if logger settings are present and read them */
2353 238 : logger_def = mp_section (inifile,
2354 : "[Logger_Defaults]",
2355 : "[End_Logger_Defaults]", 1);
2356 :
2357 238 : if (logger_def != INITPTR) {
2358 238 : ec_get_logger_settings (logger_def);
2359 238 : mmp_destroy (&logger_def);
2360 : }
2361 238 : if (operation_mode == 0) {
2362 : /*we should read module definitions only
2363 : if we don't use external controller */
2364 28 : ec_read_module_section (inifile);
2365 : }
2366 : #ifndef MIN_EXTIF
2367 20 : ec_read_slaves_section (inifile);
2368 : #endif
2369 238 : return 0;
2370 0 : err_exit:
2371 0 : ec_cleanup();
2372 0 : exit (-1);
2373 :
2374 : return -1;
2375 : }
2376 : /** Function reads config files in following order : MIN_CONF_DIR/min.conf,
2377 : * $HOME/.min/min.conf, ./min.conf. Settings with single value are
2378 : * overwritten, module and search paths are appended.
2379 : */
2380 : int ec_configure ()
2381 119 : {
2382 119 : MinParser *inifile = INITPTR;
2383 119 : char *home_d = getenv ("HOME");
2384 119 : char *curr_d = getenv ("PWD");
2385 119 : char *def_d = MIN_CONF_DIR;
2386 : char *min_d;
2387 119 : int op_mode = ec_settings.operation_mode_;
2388 :
2389 119 : ec_init_logger_settings ();
2390 :
2391 : /*Initialize logger settings */
2392 : /*Read settings from global .conf */
2393 119 : if (curr_d == NULL || strcmp (MIN_CONF_DIR, curr_d) != 0) {
2394 119 : inifile = mp_create (def_d, "min.conf", ENoComments);
2395 :
2396 119 : if (inifile == INITPTR) {
2397 0 : MIN_WARN ("Could not open %s/min.conf %s\n",
2398 : MIN_CONF_DIR, strerror (errno));
2399 : } else {
2400 119 : ec_read_conf (inifile, op_mode);
2401 119 : mp_destroy (&inifile);
2402 : }
2403 : }
2404 : /*Read $HOME/.min/min.conf */
2405 119 : if (home_d != NULL) {
2406 119 : min_d = NEW2 (char, strlen (home_d) + 7);
2407 119 : sprintf (min_d, "%s/.min", home_d);
2408 119 : if (strcmp (min_d, curr_d) != 0) {
2409 119 : inifile = mp_create (min_d, "min.conf", ENoComments);
2410 :
2411 119 : if (inifile == INITPTR) {
2412 0 : MIN_WARN ("Could not open "
2413 : "%s/min.conf %s\n",
2414 : min_d, strerror (errno));
2415 : } else {
2416 119 : ec_read_conf (inifile, op_mode);
2417 119 : mp_destroy (&inifile);
2418 : }
2419 : }
2420 119 : DELETE (min_d);
2421 : } else {
2422 0 : MIN_WARN ("$HOME == NULL, not reading "
2423 : "min.conf from ~/.min");
2424 : }
2425 : /*try to read ./min.conf */
2426 119 : if (curr_d != NULL) {
2427 119 : inifile = mp_create (curr_d, "min.conf", ENoComments);
2428 :
2429 119 : if (inifile == INITPTR) {
2430 119 : MIN_DEBUG ("Could not open %s/min.conf %s\n",
2431 : curr_d,
2432 : strerror (errno));
2433 : } else {
2434 0 : ec_read_conf (inifile, op_mode);
2435 0 : mp_destroy (&inifile);
2436 : }
2437 : } else {
2438 0 : MIN_WARN ("$PWD == NULL, not reading "
2439 : "min.conf from .");
2440 : }
2441 :
2442 : /*
2443 : ** Read module definitions from /etc/min.d/
2444 : */
2445 119 : if (op_mode == 0)
2446 14 : ec_read_module_confdir ();
2447 119 : ec_settings_send ();
2448 :
2449 118 : min_log_open ("MIN", 3);
2450 :
2451 118 : return 0;
2452 : }
2453 :
2454 : /** Checks if the user configuration dir exists and creates it if not
2455 : */
2456 : LOCAL void create_local_confdir ()
2457 19 : {
2458 : struct stat dirstat;
2459 : Text *confpath;
2460 19 : char *home = getenv ("HOME");
2461 :
2462 19 : if (home == NULL)
2463 0 : return;
2464 :
2465 19 : confpath = tx_create (home);
2466 19 : tx_c_append (confpath, "/.min");
2467 :
2468 19 : memset (&dirstat, 0, sizeof (struct stat));
2469 19 : if (stat (tx_share_buf(confpath), &dirstat)) {
2470 : /* directory does not exist, try to create */
2471 0 : if (mkdir (tx_share_buf(confpath), S_IRWXU)) {
2472 0 : MIN_FATAL ("Failed to create %s: %s\n"
2473 : "Exiting ...\n",tx_share_buf,
2474 : strerror (errno));
2475 0 : goto err_exit;
2476 : }
2477 : }
2478 : /*
2479 : ** Check that the directory has write permissions
2480 : */
2481 19 : else if (!(dirstat.st_mode & S_IWUSR)) {
2482 0 : MIN_FATAL ("User does not have write permission to %s\n"
2483 : "Exiting ...\n", tx_share_buf (confpath));
2484 :
2485 0 : goto err_exit;
2486 :
2487 : }
2488 :
2489 19 : tx_destroy (&confpath);
2490 19 : return;
2491 :
2492 0 : err_exit:
2493 0 : tx_destroy (&confpath);
2494 0 : ec_cleanup ();
2495 0 : exit (-1);
2496 : return;
2497 : }
2498 :
2499 : /**Function initializes all engine's global variables, creates message queues
2500 : * and threads. In case of problems during operations vital to test execution,
2501 : * function exits process - since if any of those operations fail - MIN will
2502 : * not be able to work anyway
2503 : * @param completecallbk pointer to function called when test case completes
2504 : * @param printcallbk pointer to function called when test case tries to print
2505 : * output
2506 : * @param extifsendcallbk pointer to function sending external controller
2507 : * messages
2508 : * @param envp pointer to enviroment settings var
2509 : * @param operation_mode - describes what is the operation mode of min
2510 : * instance - 0 means console interface,
2511 : * 1 - external controller interface.
2512 : */
2513 : void ec_min_init (char *envp_[], int operation_mode)
2514 124 : {
2515 : int thread_creation_result;
2516 : pthread_t listener_thread;
2517 : #ifndef MIN_EXTIF
2518 : pthread_t socket_thread;
2519 : #endif
2520 124 : long tmp = 0;
2521 :
2522 124 : ec_settings.operation_mode_ = operation_mode;
2523 :
2524 124 : envp = envp_;
2525 124 : if (operation_mode == 0)
2526 19 : create_local_confdir();
2527 :
2528 : /*
2529 : ** Global data initialization
2530 : */
2531 124 : available_modules = dl_list_create ();
2532 124 : instantiated_modules = dl_list_create ();
2533 124 : selected_cases = dl_list_create ();
2534 :
2535 124 : pthread_mutex_lock (&tec_mutex_);
2536 124 : rcp_handling_init ();
2537 :
2538 124 : ec_settings.engine_pid_ = getpid ();
2539 124 : pthread_mutex_unlock (&tec_mutex_);
2540 124 : ec_settings.search_dirs = dl_list_create ();
2541 :
2542 :
2543 : #ifndef MIN_EXTIF
2544 15 : in->send_rcp = socket_send_rcp;
2545 : #endif /* MIN_EXTIF */
2546 :
2547 124 : MIN_DEBUG ("available_modules %x", available_modules);
2548 : /* results = dl_list_create ( ); */
2549 124 : if ((available_modules == INITPTR)
2550 : || (instantiated_modules == INITPTR)
2551 : || (selected_cases == INITPTR) || (results == INITPTR)) {
2552 :
2553 0 : MIN_FATAL ("Not enough memory to create list");
2554 0 : min_log_close ();
2555 0 : exit (-1);
2556 :
2557 : }
2558 :
2559 124 : mq_id = mq_open_queue ('a');
2560 : /*
2561 : ** Try to clean up
2562 : */
2563 124 : if (mq_id < 0) {
2564 0 : MIN_WARN ("failed to create message queue "
2565 : " - trying to clean up");
2566 0 : system ("/usr/bin/min-clean.sh");
2567 : }
2568 :
2569 124 : mq_id = mq_open_queue ('a');
2570 124 : if (mq_id < 0) {
2571 0 : MIN_WARN ("Failed to create message queue: %s",
2572 : strerror (errno));
2573 0 : min_log_close ();
2574 0 : exit (-1);
2575 : }
2576 124 : event_system_init ();
2577 :
2578 :
2579 : /*start modules */
2580 : /* ec_start_modules (); */
2581 : /* Listener thread(s) creation */
2582 124 : thread_creation_result =
2583 : pthread_create (&listener_thread, NULL, ec_message_listener,
2584 : (void *)tmp);
2585 124 : if (thread_creation_result != 0) {
2586 0 : MIN_WARN ("Failed to create new thread");
2587 0 : char *fault_text = "unspecified problem";
2588 0 : switch (thread_creation_result) {
2589 : case EAGAIN:
2590 0 : fault_text =
2591 : "Limit of threads in the system exceeded";
2592 0 : break;
2593 : case EPERM:
2594 0 : fault_text =
2595 : "Insufficient user rights to create thread";
2596 : break;
2597 : }
2598 0 : MIN_FATAL ("%s", fault_text);
2599 0 : min_log_close ();
2600 0 : exit (-1);
2601 : }
2602 : #ifndef MIN_EXTIF
2603 15 : thread_creation_result =
2604 : pthread_create (&socket_thread, NULL, ec_poll_sockets,
2605 : (void *)tmp);
2606 15 : if (thread_creation_result != 0) {
2607 0 : MIN_WARN ("Failed to create new thread");
2608 0 : char *fault_text = "unspecified problem";
2609 0 : switch (thread_creation_result) {
2610 : case EAGAIN:
2611 0 : fault_text =
2612 : "Limit of threads in the system exceeded";
2613 0 : break;
2614 : case EPERM:
2615 0 : fault_text =
2616 : "Insufficient user rights to create thread";
2617 : break;
2618 : }
2619 0 : MIN_FATAL ("%s", fault_text);
2620 0 : min_log_close ();
2621 0 : exit (-1);
2622 : }
2623 :
2624 : #endif
2625 124 : sl_set_sighandler (SIGSEGV, handle_sigsegv);
2626 124 : sl_set_sighandler (SIGTERM, handle_sigterm);
2627 124 : sl_set_sighandler (SIGBUS, handle_sigbus);
2628 124 : sl_set_sighandler (SIGQUIT, handle_sigquit);
2629 124 : sl_set_sighandler (SIGINT, handle_sigint);
2630 124 : }
2631 :
2632 : LOCAL void handle_sigsegv (int signum)
2633 1 : {
2634 1 : raise (SIGQUIT);
2635 1 : }
2636 :
2637 : LOCAL void handle_sigquit (int signum)
2638 1 : {
2639 1 : ec_cleanup ();
2640 1 : exit (-1);
2641 : }
2642 :
2643 : LOCAL void handle_sigbus (int signum)
2644 0 : {
2645 0 : raise (SIGQUIT);
2646 0 : }
2647 :
2648 : LOCAL void handle_sigterm (int signum)
2649 0 : {
2650 0 : ec_cleanup ();
2651 0 : exit (0);
2652 : }
2653 :
2654 : LOCAL void handle_sigint (int signum)
2655 0 : {
2656 0 : ec_cleanup ();
2657 0 : exit (0);
2658 : }
2659 :
2660 : /* ======================== FUNCTIONS ====================================== */
2661 : /**Function called to execute one selected test case.
2662 : * It adds test case to selected test cases list, sets its status to ongoing
2663 : * and group id to 0, since it does not belong to group. Also, it adds
2664 : * new item to test case's results list.Function Sets module status to busy,
2665 : * then creates and sends MSG_EXE using data fetched from test case and
2666 : * module info
2667 : * @param work_case_item pointer to list itemwith case to be executed
2668 : * @return result of operation(TBD)
2669 : */
2670 : int ec_exec_test_case (DLListIterator work_case_item)
2671 10 : {
2672 10 : int result = 0;
2673 10 : pthread_mutex_lock (&tec_mutex_);
2674 : /*add to selected cases list */
2675 10 : work_case_item = ec_select_case (work_case_item, 0);
2676 :
2677 10 : pthread_mutex_unlock (&tec_mutex_);
2678 10 : result = ec_exec_case (work_case_item);
2679 :
2680 10 : return result;
2681 : }
2682 :
2683 :
2684 : /** Function called by UI to pause execution of selected test case.
2685 : * @param work_case_item pointer to dl_list_item containig selected test case.
2686 : * @return result of operation :0 if message was sent successfully, -1 in case
2687 : * of data or message queue error, -2 if case is already paused,
2688 : * -3 if case is not running
2689 : */
2690 : int ec_pause_test_case (DLListIterator work_case_item)
2691 6 : {
2692 : DLListIterator work_module_item;
2693 6 : int result = 0;
2694 6 : int case_status = tc_get_status (work_case_item);
2695 6 : long addr = 0;
2696 :
2697 6 : switch (case_status) {
2698 : case TEST_CASE_ONGOING:
2699 6 : work_module_item = tc_get_test_module_ptr (work_case_item);
2700 6 : addr = tm_get_pid (work_module_item);
2701 6 : result = mq_send_message2 (mq_id, addr, MSG_PAUSE, 0, "\0");
2702 6 : if (result == 0)
2703 6 : tc_set_status (work_case_item, TEST_CASE_PAUSED);
2704 : /*if (in->case_paused) in->case_paused
2705 : (tc_get_run_id (work_case_item));*/
2706 6 : MINAPI_PLUGIN_CALL (case_paused,case_paused
2707 : (tc_get_run_id (work_case_item)));
2708 6 : break;
2709 : case TEST_CASE_PAUSED:
2710 0 : result = -2;
2711 0 : break;
2712 : default:
2713 0 : result = -3;
2714 : }
2715 :
2716 6 : return result;
2717 : }
2718 :
2719 :
2720 : /** Function called by UI to resume execution of previously paused case:
2721 : * @param work_case_item pointer to dl_list_item containing selected test case
2722 : * @return : result of operation: 0 if message was sent successfully,
2723 : * -1 in case of data or message queue error,
2724 : * -2 if case was not paused,
2725 : * -3 if case is not running (not started or
2726 : * already finished).
2727 : */
2728 : int ec_resume_test_case (DLListIterator work_case_item)
2729 2 : {
2730 : DLListIterator work_module_item;
2731 2 : int result = 0;
2732 2 : int case_status = tc_get_status (work_case_item);
2733 2 : long addr = 0;
2734 :
2735 2 : switch (case_status) {
2736 : case TEST_CASE_PAUSED:
2737 2 : work_module_item = tc_get_test_module_ptr (work_case_item);
2738 2 : addr = tm_get_pid (work_module_item);
2739 2 : result = mq_send_message2 (mq_id, addr, MSG_RESUME, 0, "\0");
2740 2 : if (result == 0) {
2741 2 : tc_set_status (work_case_item, TEST_CASE_ONGOING);
2742 : }
2743 2 : MINAPI_PLUGIN_CALL(case_resumed,
2744 : case_resumed (tc_get_run_id
2745 : (work_case_item)));
2746 2 : break;
2747 : case TEST_CASE_ONGOING:
2748 0 : result = -2;
2749 0 : break;
2750 : default:
2751 0 : result = -3;
2752 : break;
2753 : }
2754 :
2755 2 : return result;
2756 : }
2757 :
2758 :
2759 : /**Function called byu UI to stop test case execution.
2760 : * @param work_case_item pointer to dl_list_item containing selected test case
2761 : * @return result of operation: 0 if message was sent successfully, -1 in case
2762 : * of data or message queue error, -2 if case has already finished execution.
2763 : */
2764 : int ec_abort_test_case (DLListIterator work_case_item)
2765 3 : {
2766 : DLListIterator work_module_item;
2767 3 : int result = 0;
2768 3 : int case_status = tc_get_status (work_case_item);
2769 3 : long addr = 0;
2770 :
2771 3 : switch (case_status) {
2772 : case TEST_CASE_PAUSED:
2773 : case TEST_CASE_ONGOING:
2774 3 : work_module_item = tc_get_test_module_ptr (work_case_item);
2775 3 : addr = tm_get_pid (work_module_item);
2776 3 : result = mq_send_message2 (mq_id, addr, MSG_STOP, 0, "\0");
2777 3 : break;
2778 : case TEST_CASE_TERMINATED:
2779 0 : result = -2;
2780 0 : break;
2781 : default:
2782 0 : result = -1;
2783 : }
2784 :
2785 3 : return result;
2786 : }
2787 : /* ------------------------------------------------------------------------- */
2788 : /** Function for freeing the "session"
2789 : */
2790 :
2791 : void ec_reinit()
2792 51 : {
2793 : long address;
2794 : DLListIterator work_module_item;
2795 : DLListIterator work_module_item2;
2796 : DLListIterator work_case_item;
2797 : DLListIterator work_case_item2;
2798 : DLListIterator filter_item;
2799 51 : test_case_s *work_case = INITPTR;
2800 : DLList *work_list;
2801 : title_filter *filter;
2802 :
2803 51 : work_module_item = dl_list_head (instantiated_modules);
2804 : /*shutdown all running tmcs and free list*/
2805 178 : while (work_module_item != DLListNULLIterator) {
2806 76 : address = tm_get_pid (work_module_item);
2807 76 : mq_send_message2 (mq_id, address, MSG_END, 0, "Shut down !");
2808 76 : waitpid (address, NULL, 0);
2809 : /*we suppose that sending this message to TMC will ensure
2810 : that it shuts down properly */
2811 76 : work_module_item2 = dl_list_next (work_module_item);
2812 76 : tm_remove (work_module_item);
2813 76 : work_module_item = work_module_item2;
2814 : }
2815 :
2816 51 : work_module_item = dl_list_head (instantiated_modules);
2817 102 : while (work_module_item != DLListNULLIterator) {
2818 0 : work_module_item2 = dl_list_next (work_module_item);
2819 0 : work_list = tm_get_tclist (work_module_item);
2820 0 : work_case_item = dl_list_head (work_list);
2821 0 : while (work_case_item != DLListNULLIterator) {
2822 0 : work_case_item2 = dl_list_next (work_case_item);
2823 0 : tc_delete ((test_case_s *)
2824 : dl_list_data (work_case_item));
2825 0 : tc_remove (work_case_item);
2826 0 : work_case_item = work_case_item2;
2827 : }
2828 0 : tm_delete ((test_module_info_s *)
2829 : dl_list_data (work_module_item));
2830 0 : tm_remove (work_module_item);
2831 0 : work_module_item = work_module_item2;
2832 : }
2833 :
2834 51 : work_case_item = dl_list_head (selected_cases);
2835 183 : while (work_case_item != DLListNULLIterator) {
2836 81 : work_case = (test_case_s *) dl_list_data (work_case_item);
2837 81 : tc_remove (work_case_item);
2838 81 : tc_delete (work_case);
2839 81 : work_case_item = dl_list_head (selected_cases);
2840 : }
2841 :
2842 51 : filter_item = dl_list_head (filters);
2843 105 : while (filter_item != DLListNULLIterator) {
2844 3 : filter = (title_filter *) dl_list_data (filter_item);
2845 3 : tx_destroy (&filter->filter_);
2846 3 : DELETE (filter);
2847 3 : dl_list_remove_it (filter_item);
2848 3 : filter_item = dl_list_head (filters);
2849 : }
2850 :
2851 51 : }
2852 : /* ------------------------------------------------------------------------- */
2853 : /** Function that takes care of removal of all created objects, freeing
2854 : * memory and so on.
2855 : */
2856 : void ec_cleanup ()
2857 19 : {
2858 19 : event_system_cleanup ();
2859 19 : rcp_handling_cleanup ();
2860 19 : ec_reinit();
2861 :
2862 19 : dl_list_free (&instantiated_modules);
2863 19 : dl_list_free (&available_modules);
2864 19 : dl_list_free (&selected_cases);
2865 19 : dl_list_free (&filters);
2866 19 : dl_list_free_data (&ec_settings.search_dirs);
2867 19 : dl_list_free (&ec_settings.search_dirs);
2868 :
2869 : /* This sleep period allows for handling of all sent messages before
2870 : * destroying message queue
2871 : */
2872 :
2873 19 : usleep (50000);
2874 19 : sm_destroy (ec_settings.sh_mem_id_);
2875 19 : mq_close_queue (mq_id);
2876 19 : min_log_close();
2877 19 : usleep (30000);
2878 19 : }
2879 :
2880 : /**Function called by user (external controller or console IF) to execute
2881 : * sequence of test cases
2882 : * @param work_cases_list list of test cases to be executed - user has to build
2883 : * list of test cases by himself.
2884 : */
2885 : int ec_run_cases_seq (DLList * work_cases_list)
2886 1 : {
2887 1 : DLListIterator work_case_item = dl_list_head (work_cases_list);
2888 1 : DLListIterator exec_case = DLListNULLIterator;
2889 1 : int group_id = random (); /* generate unique group id */
2890 :
2891 1 : if (work_case_item == DLListNULLIterator) {
2892 0 : MIN_WARN ("Invalid list of test cases passed !");
2893 0 : return -1;
2894 : }
2895 1 : pthread_mutex_lock (&tec_mutex_);
2896 :
2897 : /*we mark first case of the group to be executed */
2898 1 : exec_case = ec_select_case (work_case_item, group_id);
2899 1 : work_case_item = dl_list_next (work_case_item);
2900 : /*now we will iterate through the remaining cases in received list */
2901 3 : while (work_case_item != DLListNULLIterator) {
2902 1 : ec_select_case (work_case_item, group_id);
2903 1 : work_case_item = dl_list_next (work_case_item);
2904 : }
2905 1 : pthread_mutex_unlock (&tec_mutex_);
2906 :
2907 : /*now we need to clear passed list, so we don't leave any garbage
2908 : behind. The list itself cannot be destroyed,because it is
2909 : console's global variable. This can change, though. */
2910 1 : work_case_item = dl_list_head (work_cases_list);
2911 4 : while (work_case_item != DLListNULLIterator) {
2912 2 : dl_list_remove_it (work_case_item);
2913 2 : work_case_item = dl_list_head (work_cases_list);
2914 : }
2915 : /*all done, now start execution of group with first case */
2916 1 : ec_exec_case (exec_case);
2917 1 : return 0;
2918 : }
2919 :
2920 :
2921 :
2922 :
2923 : int ec_run_cases_par (DLList * work_cases_list)
2924 1 : {
2925 1 : DLListIterator work_case_item = dl_list_head (work_cases_list);
2926 1 : DLListIterator exec_case = DLListNULLIterator;
2927 :
2928 1 : if (work_case_item == DLListNULLIterator) {
2929 0 : MIN_WARN ("Invalid list of test cases passed !!");
2930 0 : return -1;
2931 : }
2932 1 : pthread_mutex_lock (&tec_mutex_);
2933 :
2934 : /*"select" all cases in received list */
2935 4 : while (work_case_item != DLListNULLIterator) {
2936 2 : exec_case = ec_select_case (work_case_item, 0);
2937 2 : ec_exec_case (exec_case);
2938 2 : work_case_item = dl_list_next (work_case_item);
2939 : }
2940 1 : pthread_mutex_unlock (&tec_mutex_);
2941 :
2942 : /*now we need to clear passed list, so that we don't leave any garbage
2943 : behind. The list itself cannot be destroyed,because it is
2944 : console's global variable. This can change, though. */
2945 1 : work_case_item = dl_list_head (work_cases_list);
2946 4 : while (work_case_item != DLListNULLIterator) {
2947 2 : dl_list_remove_it (work_case_item);
2948 2 : work_case_item = dl_list_head (work_cases_list);
2949 : }
2950 :
2951 1 : return 0;
2952 : }
2953 :
2954 : /**Function used to add test module to MIN framework at any time.
2955 : * @param mod_name name of module to be added
2956 : * @param testcase_files list containing names of testcasefiles associated
2957 : * with module.
2958 : * @param id test module identifier
2959 : * @return result of operation: WARNING: function fails if there is problem
2960 : * with initializing data for module entity, possibly some memory problem, or
2961 : * if any of specified files does not exist. Information, if module was
2962 : * started successfully, (returned test cases) is not available. Indication of
2963 : * problems of
2964 : * that kind would be failure to start case from that module later.
2965 : */
2966 : int ec_add_module (TSChar * mod_name, DLList * testcase_files,
2967 : test_module_id_t id, int report)
2968 206 : {
2969 206 : DLListIterator work_module_item = DLListNULLIterator;
2970 206 : test_module_info_s *work_module = INITPTR;
2971 206 : pid_t result = 0;
2972 206 : int retval = -1;
2973 :
2974 206 : work_module = tm_create (mod_name, testcase_files, id);
2975 206 : if (work_module == INITPTR)
2976 0 : goto FAULT;
2977 206 : work_module_item = tm_add (available_modules, work_module);
2978 206 : result = ec_start_tmc (work_module_item);
2979 143 : ec_init_module_data (work_module_item);
2980 143 : if (result > 0) {
2981 142 : pthread_mutex_lock (&tec_mutex_);
2982 142 : tm_add (instantiated_modules, work_module);
2983 142 : pthread_mutex_unlock (&tec_mutex_);
2984 142 : retval = 0;
2985 142 : if (report) {
2986 5 : MINAPI_PLUGIN_CALL(new_module,
2987 : new_module (mod_name,
2988 : work_module->module_id_)
2989 : );
2990 :
2991 : }
2992 : } else {
2993 1 : retval = -1;
2994 : }
2995 :
2996 143 : FAULT:
2997 143 : return retval;
2998 : }
2999 :
3000 :
3001 : /**Function searches defined library search paths for library with given name
3002 : * @param name of file to be found
3003 : * @return position of correct path on search paths list, or -1 if file is
3004 : * not found.
3005 : */
3006 : int ec_search_lib (char *mod_name)
3007 301 : {
3008 301 : char *full_path = NULL;
3009 301 : DLListIterator work_path_item = DLListNULLIterator;
3010 301 : int result = 666;
3011 301 : int pos = 0;
3012 301 : char *work_path = NULL;
3013 301 : int retval = -1;
3014 :
3015 438 : for (pos = 0; pos < dl_list_size (ec_settings.search_dirs); pos++) {
3016 437 : work_path_item = dl_list_at (ec_settings.search_dirs, pos);
3017 437 : work_path = (char *)dl_list_data (work_path_item);
3018 437 : full_path =
3019 : NEW2 (char, strlen (work_path) + strlen (mod_name) + 2);
3020 437 : sprintf (full_path, "%s/%s", work_path, mod_name);
3021 437 : result = access (full_path, F_OK);
3022 437 : DELETE (full_path);
3023 437 : if (result == 0) {
3024 300 : retval = pos;
3025 300 : break;
3026 : }
3027 : }
3028 :
3029 301 : return retval;
3030 : }
3031 : /* ------------------------------------------------------------------------- */
3032 : void
3033 : ec_add_title_filter (char *filter_str, int regexp)
3034 4 : {
3035 : title_filter *filter;
3036 4 : filter = NEW (title_filter);
3037 :
3038 4 : filter->filter_ = tx_create (filter_str);
3039 4 : filter->regexp_ = regexp;
3040 :
3041 4 : if (filters == INITPTR) filters = dl_list_create();
3042 :
3043 4 : dl_list_add (filters, filter);
3044 :
3045 : return;
3046 : }
3047 : /* ------------------------------------------------------------------------- */
3048 : int ec_read_settings (char *engine_ini)
3049 0 : {
3050 0 : MinParser *passed_config = INITPTR;
3051 0 : char *out = NULL;
3052 0 : char *fname = NULL;
3053 0 : char *dir = NULL;
3054 0 : int cont_flag = 0;
3055 0 : int status = 0;
3056 0 : int result = 0;
3057 0 : int i = 0;
3058 0 : DLListIterator work_module_item = DLListNULLIterator;
3059 0 : char *temp = engine_ini;
3060 :
3061 : do {
3062 0 : out = &temp[1];
3063 0 : temp = strchr (out, '/');
3064 0 : } while (temp != NULL);
3065 :
3066 0 : fname = out;
3067 0 : dir = NEW2 (char, strlen (engine_ini) - strlen (fname));
3068 0 : strncpy (dir, engine_ini, strlen (engine_ini) - strlen (fname) - 1);
3069 0 : dir[strlen (engine_ini) - strlen (fname) - 1] = '\0';
3070 0 : printf (" read : %s | %s \n", dir, fname);
3071 0 : passed_config = mp_create (dir, fname, ENoComments);
3072 0 : ec_read_conf (passed_config, 0);
3073 : /*in case settings shared memory segment exists already, destroy it */
3074 0 : sm_destroy (ec_settings.sh_mem_id_);
3075 : /*now send new settings */
3076 0 : ec_settings_send ();
3077 :
3078 0 : ec_start_modules ();
3079 0 : while (cont_flag == 0) {
3080 0 : usleep (500000);
3081 0 : i++;
3082 0 : work_module_item = dl_list_head (instantiated_modules);
3083 0 : cont_flag = 1;
3084 0 : while (work_module_item != DLListNULLIterator) {
3085 0 : status = tm_get_status (work_module_item);
3086 0 : if (status == TEST_MODULE_READY)
3087 0 : cont_flag = cont_flag | 1;
3088 : else
3089 0 : cont_flag = 0;
3090 0 : work_module_item = dl_list_next (work_module_item);
3091 : }
3092 0 : if (i > 20) {
3093 0 : result = -1;
3094 0 : break;
3095 : };
3096 : }
3097 :
3098 0 : return result;
3099 : }
3100 :
3101 :
3102 : /* ================= OTHER EXPORTED FUNCTIONS ============================== */
3103 : /* None */
3104 :
3105 :
3106 : /* ================= TESTS FOR LOCAL FUNCTIONS ============================= */
3107 : #ifdef MIN_UNIT_TEST
3108 : #include "tec.tests"
3109 : #endif /* MIN_UNIT_TEST */
3110 :
3111 : /* End of file */
|