]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libevent/test/tinytest.c
libevent: Import libevent 2.1.12
[FreeBSD/FreeBSD.git] / contrib / libevent / test / tinytest.c
1 /* tinytest.c -- Copyright 2009-2012 Nick Mathewson
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions
5  * are met:
6  * 1. Redistributions of source code must retain the above copyright
7  *    notice, this list of conditions and the following disclaimer.
8  * 2. Redistributions in binary form must reproduce the above copyright
9  *    notice, this list of conditions and the following disclaimer in the
10  *    documentation and/or other materials provided with the distribution.
11  * 3. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #ifdef TINYTEST_LOCAL
26 #include "tinytest_local.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33
34 #ifndef NO_FORKING
35
36 #ifdef _WIN32
37 #include <windows.h>
38 #else
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <unistd.h>
42 #endif
43
44 #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
45 #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
46     __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
47 /* Workaround for a stupid bug in OSX 10.6 */
48 #define FORK_BREAKS_GCOV
49 #include <vproc.h>
50 #endif
51 #endif
52
53 #endif /* !NO_FORKING */
54
55 #ifndef __GNUC__
56 #define __attribute__(x)
57 #endif
58
59 #include "tinytest.h"
60 #include "tinytest_macros.h"
61
62 #define LONGEST_TEST_NAME 16384
63 #define DEFAULT_TESTCASE_TIMEOUT 30U
64 #define MAGIC_EXITCODE 42
65
66 static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
67 static int n_ok = 0; /**< Number of tests that have passed */
68 static int n_bad = 0; /**< Number of tests that have failed. */
69 static int n_skipped = 0; /**< Number of tests that have been skipped. */
70
71 static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
72 static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
73 static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
74 static unsigned int opt_timeout = DEFAULT_TESTCASE_TIMEOUT; /**< Timeout for every test (using alarm()) */
75 const char *verbosity_flag = "";
76
77 const struct testlist_alias_t *cfg_aliases=NULL;
78
79 enum outcome { SKIP=2, OK=1, FAIL=0 };
80 static enum outcome cur_test_outcome = 0;
81 const char *cur_test_prefix = NULL; /**< prefix of the current test group */
82 /** Name of the current test, if we haven't logged is yet. Used for --quiet */
83 const char *cur_test_name = NULL;
84
85 static void usage(struct testgroup_t *groups, int list_groups)
86         __attribute__((noreturn));
87 static int process_test_option(struct testgroup_t *groups, const char *test);
88
89 #ifdef _WIN32
90 /* Copy of argv[0] for win32. */
91 static char commandname[MAX_PATH+1];
92
93 struct timeout_thread_args {
94         const testcase_fn *fn;
95         void *env;
96 };
97
98 static DWORD WINAPI
99 timeout_thread_proc_(LPVOID arg)
100 {
101         struct timeout_thread_args *args = arg;
102         (*(args->fn))(args->env);
103         ExitThread(cur_test_outcome == FAIL ? 1 : 0);
104 }
105
106 static enum outcome
107 testcase_run_in_thread_(const struct testcase_t *testcase, void *env)
108 {
109         /* We will never run testcase in a new thread when the
110         timeout is set to zero */
111         assert(opt_timeout);
112         DWORD ret, tid;
113         HANDLE handle;
114         struct timeout_thread_args args = {
115                 &(testcase->fn),
116                 env
117         };
118
119         handle =CreateThread(NULL, 0, timeout_thread_proc_,
120                 (LPVOID)&args, 0, &tid);
121         ret = WaitForSingleObject(handle, opt_timeout * 1000U);
122         if (ret == WAIT_OBJECT_0) {
123                 ret = 0;
124                 if (!GetExitCodeThread(handle, &ret)) {
125                         printf("GetExitCodeThread failed\n");
126                         ret = 1;
127                 }
128         } else if (ret == WAIT_TIMEOUT) {
129                 printf("timeout\n");
130         } else {
131                 printf("Wait failed\n");
132         }
133         CloseHandle(handle);
134         if (ret == 0)
135                 return OK;
136         else if (ret == MAGIC_EXITCODE)
137                 return SKIP;
138         else
139                 return FAIL;
140 }
141 #else
142 static unsigned int testcase_set_timeout_(void)
143 {
144         return alarm(opt_timeout);
145 }
146
147 static unsigned int testcase_reset_timeout_(void)
148 {
149         return alarm(0);
150 }
151 #endif
152
153 static enum outcome
154 testcase_run_bare_(const struct testcase_t *testcase)
155 {
156         void *env = NULL;
157         int outcome;
158         if (testcase->setup) {
159                 env = testcase->setup->setup_fn(testcase);
160                 if (!env)
161                         return FAIL;
162                 else if (env == (void*)TT_SKIP)
163                         return SKIP;
164         }
165
166         cur_test_outcome = OK;
167         {
168                 if (opt_timeout) {
169 #ifdef _WIN32
170                         cur_test_outcome = testcase_run_in_thread_(testcase, env);
171 #else
172                         testcase_set_timeout_();
173                         testcase->fn(env);
174                         testcase_reset_timeout_();
175 #endif
176                 } else {
177                         testcase->fn(env);
178                 }
179         }
180         outcome = cur_test_outcome;
181
182         if (testcase->setup) {
183                 if (testcase->setup->cleanup_fn(testcase, env) == 0)
184                         outcome = FAIL;
185         }
186
187         return outcome;
188 }
189
190
191 #ifndef NO_FORKING
192
193 static enum outcome
194 testcase_run_forked_(const struct testgroup_t *group,
195                      const struct testcase_t *testcase)
196 {
197 #ifdef _WIN32
198         /* Fork? On Win32?  How primitive!  We'll do what the smart kids do:
199            we'll invoke our own exe (whose name we recall from the command
200            line) with a command line that tells it to run just the test we
201            want, and this time without forking.
202
203            (No, threads aren't an option.  The whole point of forking is to
204            share no state between tests.)
205          */
206         int ok;
207         char buffer[LONGEST_TEST_NAME+256];
208         STARTUPINFOA si;
209         PROCESS_INFORMATION info;
210         DWORD ret;
211
212         if (!in_tinytest_main) {
213                 printf("\nERROR.  On Windows, testcase_run_forked_ must be"
214                        " called from within tinytest_main.\n");
215                 abort();
216         }
217         if (opt_verbosity>0)
218                 printf("[forking] ");
219
220         snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s --timeout 0 %s%s",
221                  commandname, verbosity_flag, group->prefix, testcase->name);
222
223         memset(&si, 0, sizeof(si));
224         memset(&info, 0, sizeof(info));
225         si.cb = sizeof(si);
226
227         ok = CreateProcessA(commandname, buffer, NULL, NULL, 0,
228                            0, NULL, NULL, &si, &info);
229         if (!ok) {
230                 printf("CreateProcess failed!\n");
231                 return FAIL;
232         }
233         ret = WaitForSingleObject(info.hProcess,
234                 (opt_timeout ? opt_timeout * 1000U : INFINITE));
235
236         if (ret == WAIT_OBJECT_0) {
237                 GetExitCodeProcess(info.hProcess, &ret);
238         } else if (ret == WAIT_TIMEOUT) {
239                 printf("timeout\n");
240         } else {
241                 printf("Wait failed\n");
242         }
243         CloseHandle(info.hProcess);
244         CloseHandle(info.hThread);
245         if (ret == 0)
246                 return OK;
247         else if (ret == MAGIC_EXITCODE)
248                 return SKIP;
249         else
250                 return FAIL;
251 #else
252         int outcome_pipe[2];
253         pid_t pid;
254         (void)group;
255
256         if (pipe(outcome_pipe))
257                 perror("opening pipe");
258
259         if (opt_verbosity>0)
260                 printf("[forking] ");
261         pid = fork();
262 #ifdef FORK_BREAKS_GCOV
263         vproc_transaction_begin(0);
264 #endif
265         if (!pid) {
266                 /* child. */
267                 int test_r, write_r;
268                 char b[1];
269                 close(outcome_pipe[0]);
270                 test_r = testcase_run_bare_(testcase);
271                 assert(0<=(int)test_r && (int)test_r<=2);
272                 b[0] = "NYS"[test_r];
273                 write_r = (int)write(outcome_pipe[1], b, 1);
274                 if (write_r != 1) {
275                         perror("write outcome to pipe");
276                         exit(1);
277                 }
278                 exit(0);
279                 return FAIL; /* unreachable */
280         } else {
281                 /* parent */
282                 int status, r, exitcode;
283                 char b[1];
284                 /* Close this now, so that if the other side closes it,
285                  * our read fails. */
286                 close(outcome_pipe[1]);
287                 r = (int)read(outcome_pipe[0], b, 1);
288                 if (r == 0) {
289                         printf("[Lost connection!] ");
290                         return FAIL;
291                 } else if (r != 1) {
292                         perror("read outcome from pipe");
293                 }
294                 waitpid(pid, &status, 0);
295                 exitcode = WEXITSTATUS(status);
296                 close(outcome_pipe[0]);
297                 if (opt_verbosity>1)
298                         printf("%s%s: exited with %i (%i)\n", group->prefix, testcase->name, exitcode, status);
299                 if (exitcode != 0)
300                 {
301                         printf("[atexit failure!] ");
302                         return FAIL;
303                 }
304                 return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL);
305         }
306 #endif
307 }
308
309 #endif /* !NO_FORKING */
310
311 int
312 testcase_run_one(const struct testgroup_t *group,
313                  const struct testcase_t *testcase)
314 {
315         enum outcome outcome;
316
317         if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) {
318                 if (opt_verbosity>0)
319                         printf("%s%s: %s\n",
320                            group->prefix, testcase->name,
321                            (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
322                 ++n_skipped;
323                 return SKIP;
324         }
325
326         if (opt_verbosity>0 && !opt_forked) {
327                 printf("%s%s: ", group->prefix, testcase->name);
328         } else {
329                 if (opt_verbosity==0) printf(".");
330                 cur_test_prefix = group->prefix;
331                 cur_test_name = testcase->name;
332         }
333
334 #ifndef NO_FORKING
335         if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) {
336                 outcome = testcase_run_forked_(group, testcase);
337         } else {
338 #else
339         {
340 #endif
341                 outcome = testcase_run_bare_(testcase);
342         }
343
344         if (outcome == OK) {
345                 if (opt_verbosity>0 && !opt_forked)
346                         puts(opt_verbosity==1?"OK":"");
347         } else if (outcome == SKIP) {
348                 if (opt_verbosity>0 && !opt_forked)
349                         puts("SKIPPED");
350         } else {
351                 if (!opt_forked)
352                         printf("\n  [%s FAILED]\n", testcase->name);
353         }
354
355         if (opt_forked) {
356                 exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1));
357                 return 1; /* unreachable */
358         } else {
359                 return (int)outcome;
360         }
361 }
362
363 int
364 tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag)
365 {
366         int i, j;
367         size_t length = LONGEST_TEST_NAME;
368         char fullname[LONGEST_TEST_NAME];
369         int found=0;
370         if (strstr(arg, ".."))
371                 length = strstr(arg,"..")-arg;
372         for (i=0; groups[i].prefix; ++i) {
373                 for (j=0; groups[i].cases[j].name; ++j) {
374                         struct testcase_t *testcase = &groups[i].cases[j];
375                         snprintf(fullname, sizeof(fullname), "%s%s",
376                                  groups[i].prefix, testcase->name);
377                         if (!flag) { /* Hack! */
378                                 printf("    %s", fullname);
379                                 if (testcase->flags & TT_OFF_BY_DEFAULT)
380                                         puts("   (Off by default)");
381                                 else if (testcase->flags & TT_SKIP)
382                                         puts("  (DISABLED)");
383                                 else
384                                         puts("");
385                         }
386                         if (!strncmp(fullname, arg, length)) {
387                                 if (set)
388                                         testcase->flags |= flag;
389                                 else
390                                         testcase->flags &= ~flag;
391                                 ++found;
392                         }
393                 }
394         }
395         return found;
396 }
397
398 static void
399 usage(struct testgroup_t *groups, int list_groups)
400 {
401         puts("Options are: [--verbose|--quiet|--terse] [--no-fork] [--timeout <sec>]");
402         puts("  Specify tests by name, or using a prefix ending with '..'");
403         puts("  To skip a test, prefix its name with a colon.");
404         puts("  To enable a disabled test, prefix its name with a plus.");
405         puts("  Use --list-tests for a list of tests.");
406         if (list_groups) {
407                 puts("Known tests are:");
408                 tinytest_set_flag_(groups, "..", 1, 0);
409         }
410         exit(0);
411 }
412
413 static int
414 process_test_alias(struct testgroup_t *groups, const char *test)
415 {
416         int i, j, n, r;
417         for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) {
418                 if (!strcmp(cfg_aliases[i].name, test)) {
419                         n = 0;
420                         for (j = 0; cfg_aliases[i].tests[j]; ++j) {
421                                 r = process_test_option(groups, cfg_aliases[i].tests[j]);
422                                 if (r<0)
423                                         return -1;
424                                 n += r;
425                         }
426                         return n;
427                 }
428         }
429         printf("No such test alias as @%s!",test);
430         return -1;
431 }
432
433 static int
434 process_test_option(struct testgroup_t *groups, const char *test)
435 {
436         int flag = TT_ENABLED_;
437         int n = 0;
438         if (test[0] == '@') {
439                 return process_test_alias(groups, test + 1);
440         } else if (test[0] == ':') {
441                 ++test;
442                 flag = TT_SKIP;
443         } else if (test[0] == '+') {
444                 ++test;
445                 ++n;
446                 if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
447                         printf("No such test as %s!\n", test);
448                         return -1;
449                 }
450         } else {
451                 ++n;
452         }
453         if (!tinytest_set_flag_(groups, test, 1, flag)) {
454                 printf("No such test as %s!\n", test);
455                 return -1;
456         }
457         return n;
458 }
459
460 void
461 tinytest_set_aliases(const struct testlist_alias_t *aliases)
462 {
463         cfg_aliases = aliases;
464 }
465
466 int
467 tinytest_main(int c, const char **v, struct testgroup_t *groups)
468 {
469         int i, j, n=0;
470
471 #ifdef _WIN32
472         const char *sp = strrchr(v[0], '.');
473         const char *extension = "";
474         if (!sp || stricmp(sp, ".exe"))
475                 extension = ".exe"; /* Add an exe so CreateProcess will work */
476         snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
477         commandname[MAX_PATH]='\0';
478 #endif
479         for (i=1; i<c; ++i) {
480                 if (v[i][0] == '-') {
481                         if (!strcmp(v[i], "--RUNNING-FORKED")) {
482                                 opt_forked = 1;
483                         } else if (!strcmp(v[i], "--no-fork")) {
484                                 opt_nofork = 1;
485                         } else if (!strcmp(v[i], "--quiet")) {
486                                 opt_verbosity = -1;
487                                 verbosity_flag = "--quiet";
488                         } else if (!strcmp(v[i], "--verbose")) {
489                                 opt_verbosity = 2;
490                                 verbosity_flag = "--verbose";
491                         } else if (!strcmp(v[i], "--terse")) {
492                                 opt_verbosity = 0;
493                                 verbosity_flag = "--terse";
494                         } else if (!strcmp(v[i], "--help")) {
495                                 usage(groups, 0);
496                         } else if (!strcmp(v[i], "--list-tests")) {
497                                 usage(groups, 1);
498                         } else if (!strcmp(v[i], "--timeout")) {
499                                 ++i;
500                                 if (i >= c) {
501                                         fprintf(stderr, "--timeout requires argument\n");
502                                         return -1;
503                                 }
504                                 opt_timeout = (unsigned)atoi(v[i]);
505                         } else {
506                                 fprintf(stderr, "Unknown option %s. Try --help\n", v[i]);
507                                 return -1;
508                         }
509                 } else {
510                         int r = process_test_option(groups, v[i]);
511                         if (r<0)
512                                 return -1;
513                         n += r;
514                 }
515         }
516         if (!n)
517                 tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
518
519 #ifdef _IONBF
520         setvbuf(stdout, NULL, _IONBF, 0);
521 #endif
522
523         ++in_tinytest_main;
524         for (i = 0; groups[i].prefix; ++i) {
525                 struct testgroup_t *group = &groups[i];
526                 for (j = 0; group->cases[j].name; ++j) {
527                         struct testcase_t *testcase = &group->cases[j];
528                         int test_attempts = 3;
529                         int test_ret_err;
530
531                         if (!(testcase->flags & TT_ENABLED_))
532                                 continue;
533
534                         for (;;) {
535                                 test_ret_err = testcase_run_one(group, testcase);
536
537                                 if (test_ret_err == OK)
538                                         break;
539                                 if (!(testcase->flags & TT_RETRIABLE))
540                                         break;
541                                 printf("\n  [RETRYING %s (%i)]\n", testcase->name, test_attempts);
542                                 if (!test_attempts--)
543                                         break;
544                         }
545
546                         switch (test_ret_err) {
547                                 case OK:   ++n_ok;      break;
548                                 case SKIP: ++n_skipped; break;
549                                 default:   ++n_bad;     break;
550                         }
551                 }
552         }
553
554         --in_tinytest_main;
555
556         if (opt_verbosity==0)
557                 puts("");
558
559         if (n_bad)
560                 printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad,
561                        n_bad+n_ok,n_skipped);
562         else if (opt_verbosity >= 1)
563                 printf("%d tests ok.  (%d skipped)\n", n_ok, n_skipped);
564
565         return (n_bad == 0) ? 0 : 1;
566 }
567
568 int
569 tinytest_get_verbosity_(void)
570 {
571         return opt_verbosity;
572 }
573
574 void
575 tinytest_set_test_failed_(void)
576 {
577         if (opt_verbosity <= 0 && cur_test_name) {
578                 if (opt_verbosity==0) puts("");
579                 printf("%s%s: ", cur_test_prefix, cur_test_name);
580                 cur_test_name = NULL;
581         }
582         cur_test_outcome = FAIL;
583 }
584
585 void
586 tinytest_set_test_skipped_(void)
587 {
588         if (cur_test_outcome==OK)
589                 cur_test_outcome = SKIP;
590 }
591
592 char *
593 tinytest_format_hex_(const void *val_, unsigned long len)
594 {
595         const unsigned char *val = val_;
596         char *result, *cp;
597         size_t i;
598
599         if (!val)
600                 return strdup("null");
601         if (!(result = malloc(len*2+1)))
602                 return strdup("<allocation failure>");
603         cp = result;
604         for (i=0;i<len;++i) {
605                 *cp++ = "0123456789ABCDEF"[val[i] >> 4];
606                 *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
607         }
608         *cp = 0;
609         return result;
610 }