00001
00002
00003
00004
00005 #include <sys/types.h>
00006 #include <sys/time.h>
00007 #include <signal.h>
00008 #include <stddef.h>
00009 #include <stdio.h>
00010 #include <stdarg.h>
00011 #include <strings.h>
00012 #include <time.h>
00013
00014 #include <toolbox/carpal.h>
00015 #include <toolbox/misc.h>
00016 #include <toolbox/test.h>
00017
00018 #if defined(HAVE_WAIT3) || defined(HAVE_WAIT)
00019 #include <sys/wait.h>
00020 #endif
00021 #ifdef HAVE_STRUCT_RUSAGE
00022 #include <sys/resource.h>
00023 #endif
00024 #if defined(HAVE_FORK)
00025 #define U_TEST_SANDBOX_ENABLED 1
00026 #endif
00027 #ifdef HAVE_UNAME
00028 #include <sys/utsname.h>
00029 #endif
00030
00031 static char g_interrupted = 0;
00032 static char g_debug = 0;
00033 static char g_verbose = 0;
00034 #define CHAT(...) \
00035 do { if (g_verbose) { printf("[CHAT] "); printf(__VA_ARGS__); } } while (0)
00036
00037 #define U_TEST_CASE_PID_INITIALIZER -1
00038
00039 typedef enum { U_TEST_CASE_T, U_TEST_SUITE_T } u_test_what_t;
00040
00041
00042 typedef struct
00043 {
00044 unsigned int currank, nchildren;
00045 LIST_HEAD(, u_test_obj_s) objs;
00046 } TO;
00047
00048
00049 typedef LIST_HEAD(, u_test_dep_s) TD;
00050
00051
00052 struct u_test_dep_s
00053 {
00054 char id[U_TEST_ID_MAX];
00055 LIST_ENTRY(u_test_dep_s) links;
00056 struct u_test_obj_s *upref;
00057 };
00058
00059 typedef struct u_test_dep_s u_test_dep_t;
00060
00061
00062 struct u_test_syn_s
00063 {
00064 unsigned int total, pass, fail, abrt, skip;
00065 };
00066
00067 typedef struct u_test_syn_s u_test_syn_t;
00068
00069
00070
00071
00072 struct u_test_obj_s
00073 {
00074 u_test_what_t what;
00075 TO *parent;
00076 char sequenced;
00077 unsigned int rank;
00078 char id[U_TEST_ID_MAX];
00079 int status;
00080 time_t start, stop;
00081 LIST_ENTRY(u_test_obj_s) links;
00082 TD deps;
00083 };
00084
00085 typedef struct u_test_obj_s u_test_obj_t;
00086
00087
00088 struct u_test_case_s
00089 {
00090 int (*func) (struct u_test_case_s *);
00091 u_test_obj_t o;
00092 pid_t pid;
00093 #ifdef HAVE_STRUCT_RUSAGE
00094 struct rusage stats;
00095 #endif
00096 struct u_test_suite_s *pts;
00097 };
00098
00099
00100 struct u_test_suite_s
00101 {
00102 TO u_test_cases;
00103 u_test_obj_t o;
00104 u_test_syn_t syn;
00105 struct u_test_s *pt;
00106 };
00107
00108
00109 struct u_test_rep_s
00110 {
00111 u_test_rep_f t_cb;
00112 u_test_suite_rep_f ts_cb;
00113 u_test_case_rep_f tc_cb;
00114 };
00115
00116
00117 struct u_test_s
00118 {
00119 unsigned int currank;
00120 char id[U_TEST_ID_MAX];
00121 TO u_test_suites;
00122 char outfn[4096];
00123 time_t start, stop;
00124 char sandboxed;
00125 unsigned int max_parallel;
00126 u_test_syn_t syn;
00127 char host[1024];
00128
00129
00130 struct u_test_rep_s reporters;
00131 };
00132
00133
00134 #define TS_HANDLE(optr) \
00135 (u_test_suite_t *) ((char *) optr - offsetof(u_test_suite_t, o))
00136
00137
00138 #define TC_HANDLE(optr) \
00139 (u_test_case_t *) ((char *) optr - offsetof(u_test_case_t, o))
00140
00141
00142 static int u_test_obj_dep_add (u_test_dep_t *td, u_test_obj_t *to);
00143 static int u_test_obj_depends_on (const char *id, const char *depid,
00144 TO *parent);
00145 static int u_test_obj_evict_id (TO *h, const char *id);
00146 static int u_test_obj_init (const char *id, u_test_what_t what,
00147 u_test_obj_t *to);
00148 static int u_test_obj_scheduler (TO *h, int (*sched)(u_test_obj_t *));
00149 static int u_test_obj_sequencer (TO *h);
00150 static u_test_obj_t *u_test_obj_pick_top (TO *h);
00151 static u_test_obj_t *u_test_obj_search (TO *h, const char *id);
00152 static void u_test_obj_free (u_test_obj_t *to);
00153 static void u_test_obj_print (char nindent, u_test_obj_t *to);
00154
00155
00156 static int u_test_dep_new (const char *id, u_test_dep_t **ptd);
00157 static u_test_dep_t *u_test_dep_search (TD *h, const char *id);
00158 static char u_test_dep_dry (TD *h);
00159 static char u_test_dep_failed (TD *h);
00160 static void u_test_dep_free (u_test_dep_t *td);
00161 static void u_test_dep_print (char nindent, u_test_dep_t *td);
00162
00163
00164 static void u_test_case_print (u_test_case_t *tc);
00165 static int u_test_case_dep_add (u_test_dep_t *td, u_test_case_t *tc);
00166 static int u_test_case_scheduler (u_test_obj_t *to);
00167 static int u_test_case_report_txt (FILE *fp, u_test_case_t *tc);
00168 static int u_test_case_report_xml (FILE *fp, u_test_case_t *tc);
00169 static int u_test_case_exec (u_test_case_t *tc);
00170
00171
00172 static int u_test_cases_reap (TO *h);
00173 static u_test_case_t *u_test_cases_search_by_pid (TO *h, pid_t pid);
00174
00175
00176 static int u_test_suite_scheduler (u_test_obj_t *to);
00177 static void u_test_suite_print (u_test_suite_t *ts);
00178 static int u_test_suite_dep_add (u_test_dep_t *td, u_test_suite_t *ts);
00179 static int u_test_suite_report_txt (FILE *fp, u_test_suite_t *ts,
00180 u_test_rep_tag_t tag);
00181 static int u_test_suite_report_xml (FILE *fp, u_test_suite_t *ts,
00182 u_test_rep_tag_t tag);
00183 static int u_test_suite_update_all_status (u_test_suite_t *ts, int status);
00184
00185
00186 static int u_test_sequencer (u_test_t *t);
00187 static int u_test_scheduler (u_test_t *t);
00188 static void u_test_print (u_test_t *t);
00189 static int u_test_getopt (int ac, char *av[], u_test_t *t);
00190 static void u_test_usage (const char *prog, const char *msg);
00191 static int u_test_set_outfmt (u_test_t *t, const char *fmt);
00192 static int u_test_reporter (u_test_t *t);
00193 static int u_test_report_txt (FILE *fp, u_test_t *t, u_test_rep_tag_t tag);
00194 static int u_test_report_xml (FILE *fp, u_test_t *t, u_test_rep_tag_t tag);
00195 static int u_test_uname (u_test_t *t);
00196
00197
00198 static int u_test_syn_update (u_test_syn_t *syn, TO *h);
00199
00200
00201 static const char *u_test_status_str (int status);
00202 static int u_test_init (u_test_t *t);
00203 static int u_test_signals (void);
00204 static void u_test_interrupted (int signo);
00205 static void u_test_bail_out (TO *h);
00206 static int u_test_obj_ts_fmt (u_test_obj_t *to, char b[80], char e[80],
00207 char d[80]);
00208 #ifdef HAVE_STRUCT_RUSAGE
00209 static int u_test_case_rusage_fmt (u_test_case_t *tc, char uti[80],
00210 char sti[80]);
00211 static int __timeval_fmt (struct timeval *tv, char t[80]);
00212 #endif
00213
00214
00215 struct u_test_rep_s xml_reps = {
00216 u_test_report_xml,
00217 u_test_suite_report_xml,
00218 u_test_case_report_xml
00219 };
00220
00221 struct u_test_rep_s txt_reps = {
00222 u_test_report_txt,
00223 u_test_suite_report_txt,
00224 u_test_case_report_txt
00225 };
00226
00319 int u_test_run (int ac, char *av[], u_test_t *t)
00320 {
00321 con_err_if (u_test_init(t));
00322 con_err_if (u_test_getopt(ac, av, t));
00323 con_err_if (u_test_sequencer(t));
00324
00325
00326 if (g_debug)
00327 u_test_print(t);
00328
00329 con_err_if (u_test_scheduler(t));
00330 con_err_if (u_test_reporter(t));
00331
00332 return (t->syn.total == t->syn.pass) ? 0 : ~0;
00333 err:
00334 return ~0;
00335 }
00336
00348 int u_test_suite_dep_register (const char *id, u_test_suite_t *ts)
00349 {
00350 u_test_dep_t *td = NULL;
00351
00352 dbg_err_if (u_test_dep_new(id, &td));
00353 dbg_err_if (u_test_suite_dep_add(td, ts));
00354
00355 return 0;
00356 err:
00357 u_test_dep_free(td);
00358 return ~0;
00359 }
00360
00376 int u_test_case_depends_on (const char *tcid, const char *depid,
00377 u_test_suite_t *ts)
00378 {
00379 return u_test_obj_depends_on(tcid, depid, &ts->u_test_cases);
00380 }
00381
00397 int u_test_suite_depends_on (const char *tsid, const char *depid, u_test_t *t)
00398 {
00399 return u_test_obj_depends_on(tsid, depid, &t->u_test_suites);
00400 }
00401
00413 int u_test_case_dep_register (const char *id, u_test_case_t *tc)
00414 {
00415 u_test_dep_t *td = NULL;
00416
00417 dbg_err_if (u_test_dep_new(id, &td));
00418 dbg_err_if (u_test_case_dep_add(td, tc));
00419
00420 return 0;
00421 err:
00422 u_test_dep_free(td);
00423 return ~0;
00424 }
00425
00442 int u_test_case_register (const char *id, u_test_f func, u_test_suite_t *ts)
00443 {
00444 u_test_case_t *tc = NULL;
00445
00446 dbg_err_if (u_test_case_new(id, func, &tc));
00447 dbg_err_if (u_test_case_add(tc, ts));
00448
00449 return 0;
00450 err:
00451 u_test_case_free(tc);
00452 return ~0;
00453 }
00454
00467 int u_test_case_printf (u_test_case_t *tc, const char *fmt, ...)
00468 {
00469 int rc;
00470 va_list ap;
00471
00472 dbg_return_if (tc == NULL, -1);
00473
00474 (void) printf("{%s} ", tc->o.id);
00475
00476 va_start(ap, fmt);
00477 rc = vprintf(fmt, ap);
00478 va_end(ap);
00479
00480 if (rc > 0)
00481 (void) printf("\n");
00482
00483 return rc;
00484 }
00485
00498 int u_test_suite_new (const char *id, u_test_suite_t **pts)
00499 {
00500 u_test_suite_t *ts = NULL;
00501
00502 dbg_return_if (id == NULL, ~0);
00503 dbg_return_if (pts == NULL, ~0);
00504
00505 dbg_err_sif ((ts = u_malloc(sizeof *ts)) == NULL);
00506 LIST_INIT(&ts->u_test_cases.objs);
00507 ts->u_test_cases.currank = 0;
00508 memset(&ts->syn, 0, sizeof ts->syn);
00509
00510 dbg_err_if (u_test_obj_init(id, U_TEST_SUITE_T, &ts->o));
00511
00512 *pts = ts;
00513
00514 return 0;
00515 err:
00516 u_test_suite_free(ts);
00517 return ~0;
00518 }
00519
00530 void u_test_suite_free (u_test_suite_t *ts)
00531 {
00532 u_test_case_t *tc;
00533 u_test_obj_t *to, *nto;
00534
00535 if (ts == NULL)
00536 return;
00537
00538
00539 u_test_obj_free(&ts->o);
00540
00541
00542 LIST_FOREACH_SAFE (to, &ts->u_test_cases.objs, links, nto)
00543 {
00544 tc = TC_HANDLE(to);
00545 u_test_case_free(tc);
00546 }
00547
00548 u_free(ts);
00549
00550 return;
00551 }
00552
00563 void u_test_free (u_test_t *t)
00564 {
00565 u_test_suite_t *ts;
00566 u_test_obj_t *to, *nto;
00567
00568 if (t == NULL)
00569 return;
00570
00571
00572 LIST_FOREACH_SAFE (to, &t->u_test_suites.objs, links, nto)
00573 {
00574 ts = TS_HANDLE(to);
00575 u_test_suite_free(ts);
00576 }
00577
00578
00579 u_free(t);
00580
00581 return;
00582 }
00583
00596 int u_test_set_u_test_rep (u_test_t *t, u_test_rep_f func)
00597 {
00598 dbg_return_if (t == NULL, ~0);
00599 dbg_return_if (func == NULL, ~0);
00600
00601 t->reporters.t_cb = func;
00602
00603 return 0;
00604 }
00605
00618 int u_test_set_u_test_case_rep (u_test_t *t, u_test_case_rep_f func)
00619 {
00620 dbg_return_if (t == NULL, ~0);
00621 dbg_return_if (func == NULL, ~0);
00622
00623 t->reporters.tc_cb = func;
00624
00625 return 0;
00626 }
00627
00640 int u_test_set_u_test_suite_rep (u_test_t *t, u_test_suite_rep_f func)
00641 {
00642 dbg_return_if (t == NULL, ~0);
00643 dbg_return_if (func == NULL, ~0);
00644
00645 t->reporters.ts_cb = func;
00646
00647 return 0;
00648 }
00649
00661 int u_test_set_outfn (u_test_t *t, const char *outfn)
00662 {
00663 dbg_return_if (t == NULL, ~0);
00664 dbg_return_if (outfn == NULL, ~0);
00665
00666 dbg_return_if (u_strlcpy(t->outfn, outfn, sizeof t->outfn), ~0);
00667
00668 return 0;
00669 }
00670
00683 int u_test_new (const char *id, u_test_t **pt)
00684 {
00685 u_test_t *t = NULL;
00686
00687 dbg_return_if (pt == NULL, ~0);
00688
00689 dbg_err_sif ((t = u_malloc(sizeof *t)) == NULL);
00690
00691 LIST_INIT(&t->u_test_suites.objs);
00692 t->u_test_suites.currank = 0;
00693 dbg_err_if (u_strlcpy(t->id, id, sizeof t->id));
00694 t->currank = 0;
00695 t->start = t->stop = -1;
00696 (void) u_strlcpy(t->outfn, U_TEST_OUTFN_DFL, sizeof t->outfn);
00697 #ifdef U_TEST_SANDBOX_ENABLED
00698
00699
00700 t->sandboxed = 1;
00701 #else
00702 t->sandboxed = 0;
00703 #endif
00704 t->max_parallel = U_TEST_MAX_PARALLEL;
00705
00706
00707 t->reporters = txt_reps;
00708
00709
00710 memset(&t->syn, 0, sizeof t->syn);
00711
00712 *pt = t;
00713
00714 return 0;
00715 err:
00716 u_free(t);
00717 return ~0;
00718 }
00719
00730 void u_test_case_free (u_test_case_t *tc)
00731 {
00732 if (tc == NULL)
00733 return;
00734
00735
00736 u_test_obj_free(&tc->o);
00737
00738
00739 u_free(tc);
00740
00741 return;
00742 }
00743
00758 int u_test_case_new (const char *id, u_test_f func, u_test_case_t **ptc)
00759 {
00760 u_test_case_t *tc = NULL;
00761
00762 dbg_return_if (id == NULL, ~0);
00763 dbg_return_if (ptc == NULL, ~0);
00764
00765 dbg_err_sif ((tc = u_malloc(sizeof *tc)) == NULL);
00766 dbg_err_if (u_test_obj_init(id, U_TEST_CASE_T, &tc->o));
00767
00768 tc->func = func;
00769 tc->pid = U_TEST_CASE_PID_INITIALIZER;
00770 #ifdef HAVE_STRUCT_RUSAGE
00771 memset(&tc->stats, 0, sizeof tc->stats);
00772 #endif
00773
00774 *ptc = tc;
00775
00776 return 0;
00777 err:
00778 u_test_case_free(tc);
00779 return ~0;
00780 }
00781
00793 int u_test_case_add (u_test_case_t *tc, u_test_suite_t *ts)
00794 {
00795 dbg_return_if (tc == NULL, ~0);
00796 dbg_return_if (ts == NULL, ~0);
00797
00798 LIST_INSERT_HEAD(&ts->u_test_cases.objs, &tc->o, links);
00799 tc->o.parent = &ts->u_test_cases;
00800 tc->pts = ts;
00801
00802 return 0;
00803 }
00804
00816 int u_test_suite_add (u_test_suite_t *ts, u_test_t *t)
00817 {
00818 dbg_return_if (t == NULL, ~0);
00819 dbg_return_if (ts == NULL, ~0);
00820
00821 LIST_INSERT_HEAD(&t->u_test_suites.objs, &ts->o, links);
00822 ts->o.parent = &t->u_test_suites;
00823 ts->pt = t;
00824
00825 return 0;
00826 }
00827
00839 void u_test_print (u_test_t *t)
00840 {
00841 u_test_obj_t *to;
00842
00843 dbg_return_if (t == NULL, );
00844
00845 u_con("[test] %s", t->id);
00846
00847 LIST_FOREACH (to, &t->u_test_suites.objs, links)
00848 u_test_suite_print(TS_HANDLE(to));
00849
00850 return;
00851 }
00852
00857 static void u_test_suite_print (u_test_suite_t *ts)
00858 {
00859 u_test_dep_t *td;
00860 u_test_obj_t *to;
00861
00862 dbg_return_if (ts == NULL, );
00863
00864 u_test_obj_print(4, &ts->o);
00865
00866 LIST_FOREACH (td, &ts->o.deps, links)
00867 u_test_dep_print(4, td);
00868
00869 LIST_FOREACH (to, &ts->u_test_cases.objs, links)
00870 u_test_case_print(TC_HANDLE(to));
00871
00872 return;
00873 }
00874
00875 static void u_test_case_print (u_test_case_t *tc)
00876 {
00877 u_test_dep_t *td;
00878
00879 dbg_return_if (tc == NULL, );
00880
00881 u_test_obj_print(8, &tc->o);
00882
00883 LIST_FOREACH (td, &tc->o.deps, links)
00884 u_test_dep_print(8, td);
00885
00886 return;
00887 }
00888
00889 static void u_test_obj_print (char nindent, u_test_obj_t *to)
00890 {
00891 dbg_return_if (to == NULL, );
00892
00893 u_con("%*c=> [%s] %s",
00894 nindent, ' ', to->what == U_TEST_CASE_T ? "case" : "suite", to->id);
00895
00896
00897 u_con("%*c .rank = %u", nindent, ' ', to->rank);
00898 u_con("%*c .seq = %s", nindent, ' ', to->sequenced ? "true" : "false");
00899
00900 return;
00901 }
00902
00903 static void u_test_dep_print (char nindent, u_test_dep_t *td)
00904 {
00905 u_con("%*c .<dep> = %s", nindent, ' ', td->id);
00906 return;
00907 }
00908
00909 static int u_test_dep_new (const char *id, u_test_dep_t **ptd)
00910 {
00911 u_test_dep_t *td = NULL;
00912
00913 dbg_return_if (id == NULL, ~0);
00914 dbg_return_if (ptd == NULL, ~0);
00915
00916 dbg_err_sif ((td = u_malloc(sizeof *td)) == NULL);
00917 dbg_err_if (u_strlcpy(td->id, id, sizeof td->id));
00918 td->upref = NULL;
00919
00920 *ptd = td;
00921
00922 return 0;
00923 err:
00924 u_test_dep_free(td);
00925 return ~0;
00926 }
00927
00928 static void u_test_dep_free (u_test_dep_t *td)
00929 {
00930 if (td)
00931 u_free(td);
00932
00933 return;
00934 }
00935
00936 static u_test_dep_t *u_test_dep_search (TD *h, const char *id)
00937 {
00938 u_test_dep_t *td;
00939
00940 dbg_return_if (h == NULL, NULL);
00941 dbg_return_if (id == NULL, NULL);
00942
00943 LIST_FOREACH (td, h, links)
00944 {
00945 if (!strcmp(td->id, id))
00946 return td;
00947 }
00948
00949 return NULL;
00950 }
00951
00952 static u_test_obj_t *u_test_obj_search (TO *h, const char *id)
00953 {
00954 u_test_obj_t *to;
00955
00956 dbg_return_if (h == NULL, NULL);
00957 dbg_return_if (id == NULL, NULL);
00958
00959 LIST_FOREACH (to, &h->objs, links)
00960 {
00961 if (!strcmp(to->id, id))
00962 return to;
00963 }
00964
00965 return NULL;
00966 }
00967
00968 static int u_test_suite_dep_add (u_test_dep_t *td, u_test_suite_t *ts)
00969 {
00970 return u_test_obj_dep_add(td, &ts->o);
00971 }
00972
00973 static int u_test_case_dep_add (u_test_dep_t *td, u_test_case_t *tc)
00974 {
00975 return u_test_obj_dep_add(td, &tc->o);
00976 }
00977
00978
00979
00980 static int u_test_obj_dep_add (u_test_dep_t *td, u_test_obj_t *to)
00981 {
00982 dbg_return_if (to == NULL, ~0);
00983 dbg_return_if (td == NULL, ~0);
00984
00985
00986
00987 if (u_test_dep_search(&to->deps, to->id) == NULL)
00988 {
00989 LIST_INSERT_HEAD(&to->deps, td, links);
00990 }
00991 else
00992 u_free(td);
00993
00994 return 0;
00995 }
00996
00997 static void u_test_obj_free (u_test_obj_t *to)
00998 {
00999 u_test_dep_t *td, *ntd;
01000
01001
01002
01003
01004 LIST_FOREACH_SAFE (td, &to->deps, links, ntd)
01005 u_test_dep_free(td);
01006
01007 return;
01008 }
01009
01010 static char u_test_dep_dry (TD *h)
01011 {
01012 u_test_dep_t *td;
01013
01014 dbg_return_if (h == NULL, 1);
01015
01016 LIST_FOREACH (td, h, links)
01017 {
01018
01019 if (td->upref == NULL)
01020 return 0;
01021 }
01022
01023
01024 return 1;
01025 }
01026
01027 static char u_test_dep_failed (TD *h)
01028 {
01029 u_test_dep_t *td;
01030
01031 dbg_return_if (h == NULL, 0);
01032
01033 LIST_FOREACH (td, h, links)
01034 {
01035 if (td->upref && td->upref->status != U_TEST_SUCCESS)
01036 return 1;
01037 }
01038
01039 return 0;
01040 }
01041
01042 static u_test_obj_t *u_test_obj_pick_top (TO *h)
01043 {
01044
01045 u_test_obj_t *to;
01046
01047 LIST_FOREACH (to, &h->objs, links)
01048 {
01049 if (!to->sequenced && u_test_dep_dry(&to->deps))
01050 {
01051
01052
01053 to->parent->currank = U_MAX(to->rank, to->parent->currank);
01054 return to;
01055 }
01056 }
01057
01058 return NULL;
01059 }
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 static int u_test_obj_sequencer (TO *h)
01072 {
01073 u_test_obj_t *to, *fto;
01074 u_test_suite_t *ts;
01075
01076 dbg_return_if (h == NULL, ~0);
01077
01078
01079 while ((to = u_test_obj_pick_top(h)) != NULL)
01080 {
01081 dbg_err_if (u_test_obj_evict_id(h, to->id));
01082 }
01083
01084
01085
01086 LIST_FOREACH (to, &h->objs, links)
01087 {
01088 dbg_err_ifm (!to->sequenced,
01089 "%s not sequenced: dependency loop !", to->id);
01090 }
01091
01092
01093 if ((fto = LIST_FIRST(&h->objs)) && fto->what == U_TEST_SUITE_T)
01094 {
01095 LIST_FOREACH (to, &h->objs, links)
01096 {
01097 ts = TS_HANDLE(to);
01098 dbg_err_if (u_test_obj_sequencer(&ts->u_test_cases));
01099 }
01100 }
01101
01102 return 0;
01103 err:
01104 return ~0;
01105 }
01106
01107 static int u_test_obj_evict_id (TO *h, const char *id)
01108 {
01109 u_test_obj_t *to;
01110 u_test_dep_t *td;
01111
01112 dbg_return_if (id == NULL, ~0);
01113
01114
01115
01116 LIST_FOREACH (to, &h->objs, links)
01117 {
01118 LIST_FOREACH (td, &to->deps, links)
01119 {
01120 if (!strcmp(td->id, id))
01121 {
01122
01123
01124 to->rank = to->parent->currank + 1;
01125
01126 td->upref = u_test_obj_search(to->parent, id);
01127 break;
01128 }
01129 }
01130
01131
01132
01133 if (!strcmp(to->id, id))
01134 to->sequenced = 1;
01135 }
01136
01137 return 0;
01138 }
01139
01140 static int u_test_sequencer (u_test_t *t)
01141 {
01142 dbg_return_if (t == NULL, ~0);
01143
01144 return u_test_obj_sequencer(&t->u_test_suites);
01145 }
01146
01147 static int u_test_obj_init (const char *id, u_test_what_t what,
01148 u_test_obj_t *to)
01149 {
01150 dbg_return_if (id == NULL, ~0);
01151 dbg_return_if (to == NULL, ~0);
01152
01153 LIST_INIT(&to->deps);
01154 to->what = what;
01155 to->parent = NULL;
01156 to->sequenced = 0;
01157 to->rank = 0;
01158 to->status = U_TEST_SUCCESS;
01159 to->start = to->stop = -1;
01160 dbg_err_if (u_strlcpy(to->id, id, sizeof to->id));
01161
01162 return 0;
01163 err:
01164 return ~0;
01165 }
01166
01167 static int u_test_obj_depends_on (const char *id, const char *depid, TO *parent)
01168 {
01169 u_test_obj_t *to;
01170 u_test_dep_t *td = NULL;
01171
01172
01173
01174 dbg_err_if ((to = u_test_obj_search(parent, id)) == NULL);
01175
01176
01177 if ((td = u_test_dep_search(&to->deps, depid)))
01178 return 0;
01179
01180
01181
01182 dbg_err_if (u_test_dep_new(depid, &td));
01183 dbg_err_if (u_test_obj_dep_add(td, to));
01184
01185 return 0;
01186 err:
01187 u_test_dep_free(td);
01188 return ~0;
01189 }
01190
01191 static int u_test_obj_scheduler (TO *h, int (*sched)(u_test_obj_t *))
01192 {
01193 char simple_sched = 0;
01194 unsigned int r, parallel = 0;
01195 u_test_obj_t *to, *fto, *tptr;
01196 u_test_case_t *ftc;
01197
01198 dbg_return_if (h == NULL, ~0);
01199 dbg_return_if (sched == NULL, ~0);
01200
01201
01202
01203 if ((fto = LIST_FIRST(&h->objs)) == NULL)
01204 return 0;
01205
01206
01207
01208
01209 h->nchildren = 0;
01210
01211
01212
01213
01214
01215 if (fto->what == U_TEST_SUITE_T)
01216 simple_sched = 1;
01217 else
01218 simple_sched = (ftc = TC_HANDLE(fto), ftc->pts->pt->sandboxed) ? 0 : 1;
01219
01220
01221
01222 for (r = 0; r <= h->currank && !g_interrupted; ++r)
01223 {
01224
01225 if (simple_sched)
01226 {
01227 LIST_FOREACH (to, &h->objs, links)
01228 {
01229 if (to->rank == r)
01230 {
01231
01232 if (u_test_dep_failed(&to->deps))
01233 {
01234 CHAT("Skip %s due to dependency failure\n", to->id);
01235
01236 to->status = U_TEST_SKIPPED;
01237
01238
01239 if (to->what == U_TEST_SUITE_T)
01240 {
01241 (void) u_test_suite_update_all_status(TS_HANDLE(to),
01242 U_TEST_SKIPPED);
01243 }
01244
01245 continue;
01246 }
01247
01248 (void) sched(to);
01249 }
01250 }
01251 }
01252 else
01253 {
01254
01255
01256
01257
01258
01259 u_test_case_t *tc;
01260
01261 tptr = LIST_FIRST(&h->objs);
01262 tc = TC_HANDLE(tptr);
01263
01264 resched:
01265 for (to = tptr; to != NULL; to = LIST_NEXT(to, links))
01266 {
01267 if (to->rank == r)
01268 {
01269
01270 if (u_test_dep_failed(&to->deps))
01271 {
01272 CHAT("Skip %s due to dependency failure\n", to->id);
01273 to->status = U_TEST_SKIPPED;
01274 continue;
01275 }
01276
01277
01278
01279 dbg_if (sched(to));
01280
01281
01282 if ((parallel += 1) == tc->pts->pt->max_parallel)
01283 {
01284
01285 tptr = LIST_NEXT(to, links);
01286 goto reap;
01287 }
01288 }
01289
01290
01291
01292
01293 tptr = NULL;
01294 }
01295
01296 reap:
01297 dbg_err_if (u_test_cases_reap(h));
01298
01299
01300 if (tptr != NULL)
01301 {
01302 parallel = 0;
01303 goto resched;
01304 }
01305 }
01306 }
01307
01308 return 0;
01309 err:
01310 return ~0;
01311 }
01312
01313 static int u_test_cases_reap (TO *h)
01314 {
01315 #ifdef U_TEST_SANDBOX_ENABLED
01316 int status;
01317 pid_t child;
01318 u_test_case_t *tc;
01319 #ifdef HAVE_STRUCT_RUSAGE
01320 struct rusage rusage;
01321 #endif
01322
01323 dbg_return_if (h == NULL, ~0);
01324
01325 while (h->nchildren > 0)
01326 {
01327 #ifdef HAVE_WAIT3
01328 if ((child = wait3(&status, 0, &rusage)) == -1)
01329 #else
01330 if ((child = wait(&status)) == -1)
01331 #endif
01332 {
01333
01334
01335 if (errno == EINTR || errno == ECHILD)
01336 break;
01337 else
01338 con_err_sifm (1, "wait3 failed badly, test aborted");
01339 }
01340
01341 if ((tc = u_test_cases_search_by_pid(h, child)) == NULL)
01342 {
01343 CHAT("not a waited test case: %d\n", child);
01344 continue;
01345 }
01346
01347
01348
01349 if (WIFSTOPPED(status))
01350 continue;
01351
01352
01353 tc->pid = U_TEST_CASE_PID_INITIALIZER;
01354
01355
01356 if (WIFEXITED(status))
01357 {
01358
01359
01360
01361
01362 tc->o.status = WEXITSTATUS(status);
01363 dbg_if (tc->o.status != U_TEST_SUCCESS &&
01364 tc->o.status != U_TEST_FAILURE);
01365 }
01366 else if (WIFSIGNALED(status))
01367 {
01368
01369 tc->o.status = U_TEST_ABORTED;
01370 CHAT("test case %s terminated by signal %d\n", tc->o.id,
01371 WTERMSIG(status));
01372 }
01373
01374 #ifdef HAVE_STRUCT_RUSAGE
01375 tc->stats = rusage;
01376 #endif
01377
01378 tc->o.stop = time(NULL);
01379
01380 h->nchildren -= 1;
01381 }
01382
01383 if (h->nchildren != 0)
01384 {
01385 CHAT("%u child(ren) still in wait !\n", h->nchildren);
01386 goto err;
01387 }
01388
01389 return 0;
01390 err:
01391 return ~0;
01392 #else
01393 u_con("What are you doing here ?");
01394 return ~0;
01395 #endif
01396 }
01397
01398 static u_test_case_t *u_test_cases_search_by_pid (TO *h, pid_t pid)
01399 {
01400 u_test_obj_t *to;
01401 u_test_case_t *tc;
01402
01403 LIST_FOREACH (to, &h->objs, links)
01404 {
01405 if (tc = TC_HANDLE(to), tc->pid == pid)
01406 return tc;
01407 }
01408
01409 return NULL;
01410 }
01411
01412 static int u_test_syn_update (u_test_syn_t *syn, TO *h)
01413 {
01414 u_test_obj_t *to;
01415
01416 dbg_return_if (h == NULL, ~0);
01417 dbg_return_if (syn == NULL, ~0);
01418
01419 LIST_FOREACH (to, &h->objs, links)
01420 {
01421 syn->total += 1;
01422
01423 switch (to->status)
01424 {
01425 case U_TEST_SUCCESS:
01426 syn->pass += 1;
01427 break;
01428 case U_TEST_FAILURE:
01429 syn->fail += 1;
01430 break;
01431 case U_TEST_ABORTED:
01432 syn->abrt += 1;
01433 break;
01434 case U_TEST_SKIPPED:
01435 syn->skip += 1;
01436 break;
01437 default:
01438 u_warn("unknown status %d in test obj %s", to->status, to->id);
01439 }
01440 }
01441
01442 return 0;
01443 }
01444
01445 static int u_test_scheduler (u_test_t *t)
01446 {
01447 int rc;
01448
01449 dbg_return_if (t == NULL, ~0);
01450
01451
01452 rc = u_test_obj_scheduler(&t->u_test_suites, u_test_suite_scheduler);
01453
01454
01455 (void) u_test_syn_update(&t->syn, &t->u_test_suites);
01456
01457 return rc;
01458 }
01459
01460 static int u_test_suite_scheduler (u_test_obj_t *to)
01461 {
01462 int rc;
01463 u_test_obj_t *tco;
01464 u_test_suite_t *ts;
01465
01466 dbg_return_if (to == NULL || (ts = TS_HANDLE(to)) == NULL, ~0);
01467
01468 CHAT("now scheduling test suite %s\n", ts->o.id);
01469
01470
01471 ts->o.start = time(NULL);
01472
01473
01474 rc = u_test_obj_scheduler(&ts->u_test_cases, u_test_case_scheduler);
01475
01476
01477
01478 if (g_interrupted)
01479 u_test_bail_out(&ts->u_test_cases);
01480
01481
01482 ts->o.stop = time(NULL);
01483
01484
01485 LIST_FOREACH (tco, &ts->u_test_cases.objs, links)
01486 {
01487
01488
01489 if (tco->status != U_TEST_SUCCESS)
01490 {
01491 ts->o.status = U_TEST_FAILURE;
01492 break;
01493 }
01494 }
01495
01496
01497 (void) u_test_syn_update(&ts->syn, &ts->u_test_cases);
01498
01499 return rc;
01500 }
01501
01502 static int u_test_suite_update_all_status (u_test_suite_t *ts, int status)
01503 {
01504 u_test_obj_t *to;
01505
01506 dbg_return_if (ts == NULL, ~0);
01507
01508 LIST_FOREACH (to, &ts->u_test_cases.objs, links)
01509 to->status = status;
01510
01511 return 0;
01512 }
01513
01514 static int u_test_case_scheduler (u_test_obj_t *to)
01515 {
01516 dbg_return_if (to == NULL, ~0);
01517
01518 CHAT("now scheduling test case %s\n", to->id);
01519
01520 return u_test_case_exec(TC_HANDLE(to));
01521 }
01522
01523 static int u_test_case_exec (u_test_case_t *tc)
01524 {
01525 int rc;
01526 pid_t pid;
01527
01528 dbg_return_if (tc == NULL, ~0);
01529
01530 if (tc->func == NULL)
01531 return 0;
01532
01533
01534 tc->o.start = time(NULL);
01535
01536
01537
01538 if (!tc->pts->pt->sandboxed)
01539 {
01540 dbg_if ((rc = tc->func(tc)) != U_TEST_SUCCESS && rc != U_TEST_FAILURE);
01541
01542
01543 tc->o.status = rc;
01544 tc->o.stop = time(NULL);
01545
01546 return 0;
01547 }
01548
01549 #ifdef U_TEST_SANDBOX_ENABLED
01550 switch (pid = fork())
01551 {
01552 case -1:
01553 u_warn("test case %s spawn failed: %s", tc->o.id, strerror(errno));
01554 return ~0;
01555 case 0:
01556 exit(tc->func(tc));
01557 default:
01558 break;
01559 }
01560
01561 tc->pid = pid;
01562 tc->o.parent->nchildren += 1;
01563
01564
01565 CHAT("started test case %s with pid %d\n", tc->o.id, (int) tc->pid);
01566 #endif
01567
01568
01569 return 0;
01570 }
01571
01572 static int u_test_reporter (u_test_t *t)
01573 {
01574 FILE *fp;
01575 u_test_obj_t *tso, *tco;
01576 u_test_suite_t *ts;
01577
01578 dbg_return_if (t == NULL, ~0);
01579
01580
01581
01582
01583 if (strcmp(t->outfn, "-"))
01584 dbg_err_sif ((fp = fopen(t->outfn, "w")) == NULL);
01585 else
01586 fp = stdout;
01587
01588 dbg_err_if (t->reporters.t_cb(fp, t, U_TEST_REP_HEAD));
01589
01590 LIST_FOREACH (tso, &t->u_test_suites.objs, links)
01591 {
01592 ts = TS_HANDLE(tso);
01593
01594 dbg_err_if (t->reporters.ts_cb(fp, ts, U_TEST_REP_HEAD));
01595
01596 LIST_FOREACH (tco, &ts->u_test_cases.objs, links)
01597 dbg_err_if (t->reporters.tc_cb(fp, TC_HANDLE(tco)));
01598
01599 dbg_err_if (t->reporters.ts_cb(fp, ts, U_TEST_REP_TAIL));
01600 }
01601
01602 dbg_err_if (t->reporters.t_cb(fp, t, U_TEST_REP_TAIL));
01603
01604 (void) fclose(fp);
01605
01606 return 0;
01607 err:
01608 return ~0;
01609 }
01610
01611 static int u_test_report_txt (FILE *fp, u_test_t *t, u_test_rep_tag_t tag)
01612 {
01613 u_test_syn_t *syn = &t->syn;
01614
01615 if (tag == U_TEST_REP_HEAD)
01616 {
01617 (void) fprintf(fp, "%s", t->id);
01618
01619
01620 (void) fprintf(fp, " (%s)\n", t->host);
01621 }
01622
01623 if (tag == U_TEST_REP_TAIL)
01624 {
01625 (void) fprintf(fp, "Number of test suites: %u\n", syn->total);
01626 (void) fprintf(fp, " Passed: %u\n", syn->pass);
01627 (void) fprintf(fp, " Failed: %u\n", syn->fail);
01628 (void) fprintf(fp, " Aborted: %u\n", syn->abrt);
01629 (void) fprintf(fp, " Skipped: %u\n", syn->skip);
01630 }
01631
01632 return 0;
01633 }
01634
01635 static int u_test_suite_report_txt (FILE *fp, u_test_suite_t *ts,
01636 u_test_rep_tag_t tag)
01637 {
01638 int status;
01639 char b[80] = { '\0' }, e[80] = { '\0' }, d[80] = { '\0' };
01640 u_test_syn_t *syn = &ts->syn;
01641
01642 dbg_return_if (fp == NULL, ~0);
01643 dbg_return_if (ts == NULL, ~0);
01644
01645 if (tag == U_TEST_REP_HEAD)
01646 {
01647 status = ts->o.status;
01648
01649 (void) fprintf(fp, "\t* [%s] %s\n",
01650 u_test_status_str(status), ts->o.id);
01651
01652
01653 if (status == U_TEST_SUCCESS)
01654 {
01655 (void) u_test_obj_ts_fmt(&ts->o, b, e, d);
01656 (void) fprintf(fp, "\t begin: %s\n", b);
01657 (void) fprintf(fp, "\t end: %s\n", e);
01658 (void) fprintf(fp, "\t elapsed: %s\n", d);
01659 }
01660 }
01661
01662 if (tag == U_TEST_REP_TAIL)
01663 {
01664 (void) fprintf(fp, "\tNumber of test cases: %u\n", syn->total);
01665 (void) fprintf(fp, "\t Passed: %u\n", syn->pass);
01666 (void) fprintf(fp, "\t Failed: %u\n", syn->fail);
01667 (void) fprintf(fp, "\t Aborted: %u\n", syn->abrt);
01668 (void) fprintf(fp, "\t Skipped: %u\n", syn->skip);
01669 }
01670
01671 return 0;
01672 }
01673
01674 static int u_test_case_report_txt (FILE *fp, u_test_case_t *tc)
01675 {
01676 int status;
01677 #ifdef HAVE_STRUCT_RUSAGE
01678 char s[80] = { '\0' }, u[80] = { '\0' };
01679 #endif
01680 char d[80] = { '\0' };
01681
01682 dbg_return_if (fp == NULL, ~0);
01683 dbg_return_if (tc == NULL, ~0);
01684
01685 status = tc->o.status;
01686
01687 (void) fprintf(fp, "\t\t* [%s] %s\n", u_test_status_str(status), tc->o.id);
01688
01689 if (status == U_TEST_SUCCESS)
01690 {
01691 #ifdef HAVE_STRUCT_RUSAGE
01692 if (tc->pts->pt->sandboxed)
01693 {
01694 (void) u_test_case_rusage_fmt(tc, u, s);
01695 (void) fprintf(fp, "\t\t sys time: %s\n", s);
01696 (void) fprintf(fp, "\t\t user time: %s\n", u);
01697 }
01698 else
01699 #endif
01700 {
01701 (void) u_test_obj_ts_fmt(&tc->o, NULL, NULL, d);
01702 (void) fprintf(fp, "\t\t elapsed:%s\n", d);
01703 }
01704 }
01705
01706 return 0;
01707 }
01708
01709 static int u_test_report_xml (FILE *fp, u_test_t *t, u_test_rep_tag_t tag)
01710 {
01711 u_test_syn_t *syn = &t->syn;
01712
01713 dbg_return_if (t == NULL, ~0);
01714 dbg_return_if (fp == NULL, ~0);
01715
01716 if (tag == U_TEST_REP_HEAD)
01717 {
01718 (void) fprintf(fp, "<?xml version=\"1.0\"?>\n");
01719 (void) fprintf(fp, "<test id=\"%s\">\n", t->id);
01720
01721
01722 (void) fprintf(fp, "\t<total>%u</total>\n", syn->total);
01723 (void) fprintf(fp, "\t<passed>%u</passed>\n", syn->pass);
01724 (void) fprintf(fp, "\t<failed>%u</failed>\n", syn->fail);
01725 (void) fprintf(fp, "\t<aborted>%u</aborted>\n", syn->abrt);
01726 (void) fprintf(fp, "\t<skipped>%u</skipped>\n", syn->skip);
01727
01728
01729 (void) fprintf(fp, "\t<host>%s</host>\n", t->host);
01730 }
01731
01732 if (tag == U_TEST_REP_TAIL)
01733 (void) fprintf(fp, "</test>\n");
01734
01735 return 0;
01736 }
01737
01738 static int u_test_suite_report_xml (FILE *fp, u_test_suite_t *ts,
01739 u_test_rep_tag_t tag)
01740 {
01741 int status;
01742 u_test_syn_t *syn;
01743
01744 dbg_return_if (fp == NULL, ~0);
01745 dbg_return_if (ts == NULL, ~0);
01746
01747 syn = &ts->syn;
01748
01749 if (tag == U_TEST_REP_HEAD)
01750 {
01751 status = ts->o.status;
01752
01753 (void) fprintf(fp, "\t<test_suite id=\"%s\">\n", ts->o.id);
01754
01755
01756 (void) fprintf(fp, "\t\t<status>%s</status>\n",
01757 u_test_status_str(status));
01758
01759
01760 if (status == U_TEST_SUCCESS)
01761 {
01762 char b[80], d[80], e[80];
01763
01764 (void) u_test_obj_ts_fmt(&ts->o, b, e, d);
01765
01766 (void) fprintf(fp, "\t\t<begin>%s</begin>\n", b);
01767 (void) fprintf(fp, "\t\t<end>%s</end>\n", e);
01768 (void) fprintf(fp, "\t\t<elapsed>%s</elapsed>\n", d);
01769 }
01770
01771
01772 (void) fprintf(fp, "\t\t<total>%u</total>\n", syn->total);
01773 (void) fprintf(fp, "\t\t<passed>%u</passed>\n", syn->pass);
01774 (void) fprintf(fp, "\t\t<failed>%u</failed>\n", syn->fail);
01775 (void) fprintf(fp, "\t\t<aborted>%u</aborted>\n", syn->abrt);
01776 (void) fprintf(fp, "\t\t<skipped>%u</skipped>\n", syn->skip);
01777 }
01778
01779 if (tag == U_TEST_REP_TAIL)
01780 (void) fprintf(fp, "\t</test_suite>\n");
01781
01782 return 0;
01783 }
01784
01785 static int u_test_case_report_xml (FILE *fp, u_test_case_t *tc)
01786 {
01787 int status;
01788
01789 dbg_return_if (fp == NULL, ~0);
01790 dbg_return_if (tc == NULL, ~0);
01791
01792 status = tc->o.status;
01793
01794 (void) fprintf(fp, "\t\t<test_case id=\"%s\">\n", tc->o.id);
01795
01796 (void) fprintf(fp, "\t\t\t<status>%s</status>\n",
01797 u_test_status_str(status));
01798
01799 if (status == U_TEST_SUCCESS)
01800 {
01801 char d[80];
01802 #ifdef HAVE_STRUCT_RUSAGE
01803 char u[80], s[80];
01804
01805
01806 if (tc->pts->pt->sandboxed)
01807 {
01808 (void) u_test_case_rusage_fmt(tc, u, s);
01809 (void) fprintf(fp, "\t\t\t<sys_time>%s</sys_time>\n", s);
01810 (void) fprintf(fp, "\t\t\t<user_time>%s</user_time>\n", u);
01811 }
01812 else
01813 #endif
01814 {
01815 (void) u_test_obj_ts_fmt(&tc->o, NULL, NULL, d);
01816 (void) fprintf(fp, "\t\t\t<elapsed>%s</elapsed>\n", d);
01817 }
01818 }
01819
01820 (void) fprintf(fp, "\t\t</test_case>\n");
01821
01822 return 0;
01823 }
01824
01825 static const char *u_test_status_str (int status)
01826 {
01827 switch (status)
01828 {
01829 case U_TEST_SUCCESS: return "PASS";
01830 case U_TEST_FAILURE: return "FAIL";
01831 case U_TEST_ABORTED: return "ABRT";
01832 case U_TEST_SKIPPED: return "SKIP";
01833 }
01834
01835 return "?";
01836 }
01837
01838 static int u_test_getopt (int ac, char *av[], u_test_t *t)
01839 {
01840 int c, mp;
01841
01842 dbg_return_if (t == NULL, ~0);
01843
01844 while ((c = getopt(ac, av, "df:ho:p:sv")) != -1)
01845 {
01846 switch (c)
01847 {
01848 case 'o':
01849 (void) u_strlcpy(t->outfn, optarg, sizeof t->outfn);
01850 break;
01851 case 'f':
01852 if (u_test_set_outfmt(t, optarg))
01853 u_test_usage(av[0], "bad report format");
01854 break;
01855 case 'v':
01856 g_verbose = 1;
01857 break;
01858 case 'd':
01859 g_debug = 1;
01860 break;
01861 #ifdef U_TEST_SANDBOX_ENABLED
01862 case 'p':
01863 if (u_atoi(optarg, &mp) || mp < 0)
01864 u_test_usage(av[0], "bad max parallel");
01865 t->max_parallel = (unsigned int) mp;
01866 break;
01867 case 's':
01868 t->sandboxed = 0;
01869 break;
01870 #endif
01871 case 'h': default:
01872 u_test_usage(av[0], NULL);
01873 break;
01874 }
01875 }
01876
01877 return 0;
01878 }
01879
01880 static void u_test_usage (const char *prog, const char *msg)
01881 {
01882 const char *us =
01883 " \n"
01884 "Synopsis: %s [options] \n"
01885 " \n"
01886 " where \'options\' is a combination of the following: \n"
01887 " \n"
01888 " -o <file> Set the report output file \n"
01889 " -f <txt|xml> Choose report output format \n"
01890 #ifdef U_TEST_SANDBOX_ENABLED
01891 " -p <number> Set the max number of parallel tests \n"
01892 " -s Serialize test cases (non sandboxed) \n"
01893 #endif
01894 " -d Debug mode \n"
01895 " -v Be chatty \n"
01896 " -h Print this help \n"
01897 " \n"
01898 ;
01899
01900 if (msg)
01901 (void) fprintf(stderr, "\nError: %s\n", msg);
01902
01903 (void) fprintf(stderr, us, prog ? prog : "unitest");
01904
01905 exit(1);
01906 }
01907
01908 static int u_test_set_outfmt (u_test_t *t, const char *fmt)
01909 {
01910 dbg_return_if (t == NULL, ~0);
01911 dbg_return_if (fmt == NULL, ~0);
01912
01913 if (!strcasecmp(fmt, "txt"))
01914 t->reporters = txt_reps;
01915 else if (!strcasecmp(fmt, "xml"))
01916 t->reporters = xml_reps;
01917 else
01918 return ~0;
01919
01920 return 0;
01921 }
01922
01923 static int u_test_init (u_test_t *t)
01924 {
01925 dbg_return_if (t == NULL, ~0);
01926
01927 dbg_err_if (u_test_signals());
01928 dbg_err_if (u_test_uname(t));
01929
01930 return 0;
01931 err:
01932 return ~0;
01933 }
01934
01935 static int u_test_uname (u_test_t *t)
01936 {
01937 #ifdef HAVE_UNAME
01938 struct utsname h;
01939 #endif
01940
01941 dbg_return_if (t == NULL, ~0);
01942
01943 #ifdef HAVE_UNAME
01944 dbg_return_sif (uname(&h) == -1, ~0);
01945
01946 (void) u_snprintf(t->host, sizeof t->host, "%s - %s %s %s",
01947 h.nodename, h.sysname, h.release, h.machine);
01948 #else
01949
01950 (void) u_strlcpy(t->host, "unknown host name", sizeof t->host);
01951 #endif
01952
01953 return 0;
01954 }
01955
01956 static int u_test_signals (void)
01957 {
01958 #ifdef HAVE_SIGACTION
01959 struct sigaction sa;
01960
01961 sa.sa_handler = u_test_interrupted;
01962 sigemptyset(&sa.sa_mask);
01963 sa.sa_flags = 0;
01964
01965 dbg_err_sif (sigaction(SIGINT, &sa, NULL) == -1);
01966 dbg_err_sif (sigaction(SIGTERM, &sa, NULL) == -1);
01967 dbg_err_sif (sigaction(SIGQUIT, &sa, NULL) == -1);
01968 #else
01969 dbg_err_sif (signal(SIGINT, u_test_interrupted) == SIG_ERR);
01970 dbg_err_sif (signal(SIGTERM, u_test_interrupted) == SIG_ERR);
01971 #endif
01972
01973 return 0;
01974 err:
01975 return ~0;
01976 }
01977
01978 static void u_test_interrupted (int signo)
01979 {
01980 u_unused_args(signo);
01981 g_interrupted = 1;
01982 }
01983
01984 #ifdef HAVE_STRUCT_RUSAGE
01985 static int u_test_case_rusage_fmt (u_test_case_t *tc, char uti[80],
01986 char sti[80])
01987 {
01988 dbg_return_if (tc == NULL, ~0);
01989
01990 if (uti)
01991 (void) __timeval_fmt(&tc->stats.ru_utime, uti);
01992
01993 if (sti)
01994 (void) __timeval_fmt(&tc->stats.ru_stime, sti);
01995
01996
01997
01998
01999
02000 return 0;
02001 }
02002
02003 static int __timeval_fmt (struct timeval *tv, char t[80])
02004 {
02005 char _tv[80];
02006 time_t secs;
02007
02008 dbg_return_if (t == NULL, ~0);
02009 dbg_return_if (tv == NULL, ~0);
02010
02011 secs = tv->tv_sec;
02012
02013 dbg_if (strftime(_tv, sizeof _tv, "%M:%S", localtime(&secs)) == 0);
02014 dbg_if (u_snprintf(t, 80, "%s.%06.6d", _tv, tv->tv_usec));
02015
02016 return 0;
02017 }
02018 #endif
02019
02020 static int u_test_obj_ts_fmt (u_test_obj_t *to, char b[80], char e[80],
02021 char d[80])
02022 {
02023 time_t elapsed;
02024
02025 dbg_return_if (to == NULL, ~0);
02026
02027 elapsed = to->stop - to->start;
02028
02029 if (b)
02030 {
02031 dbg_if (strftime(b, 80, "%a %Y-%m-%d %H:%M:%S %Z",
02032 localtime(&to->start)) == 0);
02033 }
02034
02035 if (e)
02036 {
02037 dbg_if (strftime(e, 80, "%a %Y-%m-%d %H:%M:%S %Z",
02038 localtime(&to->stop)) == 0);
02039 }
02040
02041 if (d)
02042 dbg_if (strftime(d, 80, "%M:%S", localtime(&elapsed)) == 0);
02043
02044 return 0;
02045 }
02046
02047 static void u_test_bail_out (TO *h)
02048 {
02049 int status;
02050 u_test_obj_t *to;
02051 u_test_case_t *tc;
02052
02053 CHAT("Bailing out, as requested by the user\n");
02054
02055 #ifdef U_TEST_SANDBOX_ENABLED
02056
02057
02058
02059
02060
02061 LIST_FOREACH (to, &h->objs, links)
02062 {
02063 tc = TC_HANDLE(to);
02064
02065 if (tc->pid != U_TEST_CASE_PID_INITIALIZER)
02066 {
02067 CHAT("Killing test case %s [%d]\n", to->id, (int) tc->pid);
02068 dbg_if (kill(tc->pid, SIGKILL) == -1);
02069 }
02070 }
02071
02072 while (waitpid(-1, &status, 0) != -1) ;
02073
02074 #endif
02075
02076 exit(1);
02077 }