2 * Copyright (c) 2008, 2011 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
22 #include "testutils.h"
24 gboolean tu_debugging_enabled = FALSE;
26 static gboolean run_all = TRUE;
27 static gboolean ignore_timeouts = FALSE;
28 static gboolean skip_fork = FALSE;
29 static gboolean only_one = FALSE;
30 static gboolean loop_forever = FALSE;
31 static guint64 occurrences = 1;
34 alarm_hdlr(int sig G_GNUC_UNUSED)
36 g_fprintf(stderr, "-- TEST TIMED OUT --\n");
41 * Run a single test, accouting for the timeout (if timeouts are not ignored)
42 * and output runtime information (in milliseconds) at the end of the run.
43 * Output avg/min/max only if the number of runs is strictly greater than one.
46 static gboolean run_one_test(TestUtilsTest *test)
50 const char *test_name = test->name;
53 gdouble total = 0.0, thisrun, mintime = G_MAXDOUBLE, maxtime = G_MINDOUBLE;
55 signal(SIGALRM, alarm_hdlr);
57 timer = g_timer_new();
59 while (count++ < occurrences) {
67 thisrun = g_timer_elapsed(timer, NULL);
69 if (mintime > thisrun)
71 if (maxtime < thisrun)
78 g_timer_destroy(timer);
84 g_fprintf(stderr, " PASS %s (total: %.06f", test_name, total);
85 if (occurrences > 1) {
86 total /= (gdouble) occurrences;
87 g_fprintf(stderr, ", avg/min/max: %.06f/%.06f/%.06f",
88 total, mintime, maxtime);
90 g_fprintf(stderr, ")\n");
92 g_fprintf(stderr, " FAIL %s (run %ju of %ju, after %.06f secs)\n",
93 test_name, (uintmax_t)count, (uintmax_t)occurrences, total);
100 * Call testfn in a forked process, such that any failures will trigger a
101 * test failure, but allow the other tests to proceed. The only exception is if
102 * -n is supplied at the command line, but in this case only one test is allowed
107 callinfork(TestUtilsTest *test)
114 result = run_one_test(test);
116 switch (pid = fork()) {
118 exit(run_one_test(test) ? 0 : 1);
124 default: /* parent */
125 waitpid(pid, &status, 0);
126 result = status == 0;
136 TestUtilsTest *tests)
138 printf("USAGE: <test-script> [options] [testname [testname [..]]]\n"
140 "Options can be one of:\n"
142 "\t-h: this message\n"
143 "\t-d: print debugging messages\n"
144 "\t-t: ignore timeouts\n"
145 "\t-n: do not fork\n"
146 "\t-c <count>: run each test <count> times instead of only once\n"
147 "\t-l: loop the same test repeatedly (use with -n for leak checks)\n"
149 "If no test names are specified, all tests are run. Available tests:\n"
152 printf("\t%s\n", tests->name);
158 ignore_debug_messages(
159 const gchar *log_domain G_GNUC_UNUSED,
160 GLogLevelFlags log_level G_GNUC_UNUSED,
161 const gchar *message G_GNUC_UNUSED,
162 gpointer user_data G_GNUC_UNUSED)
170 TestUtilsTest *tests)
175 /* first_parse the command line */
177 if (strcmp(argv[1], "-d") == 0) {
178 tu_debugging_enabled = TRUE;
179 } else if (strcmp(argv[1], "-t") == 0) {
180 ignore_timeouts = TRUE;
181 } else if (strcmp(argv[1], "-n") == 0) {
184 } else if (strcmp(argv[1], "-l") == 0) {
187 } else if (strcmp(argv[1], "-c") == 0) {
190 occurrences = g_ascii_strtoull(argv[1], &p, 10);
191 if (errno == ERANGE) {
192 g_fprintf(stderr, "%s is out of range\n", argv[1]);
196 g_fprintf(stderr, "The -c option expects a positive integer "
197 "as an argument, but \"%s\" isn't\n", argv[1]);
200 if (occurrences == 0) {
201 g_fprintf(stderr, "Sorry, I will not run tests 0 times\n");
204 } else if (strcmp(argv[1], "-h") == 0) {
210 for (t = tests; t->fn; t++) {
211 if (strcmp(argv[1], t->name) == 0) {
219 g_fprintf(stderr, "Test '%s' not found\n", argv[1]);
230 * Check whether the -c option has been given. In this case, -l must not be
231 * specified at the same time.
233 if (occurrences > 1 && loop_forever) {
234 g_fprintf(stderr, "-c and -l are incompatible\n");
239 for (t = tests; t->fn; t++)
246 for (t = tests; t->fn; t++) {
252 g_fprintf(stderr, "Only run one test with '-n'\n");
257 /* Make sure g_critical and g_error will exit */
258 g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
260 /* and silently drop debug messages unless we're debugging */
261 if (!tu_debugging_enabled) {
262 g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, ignore_debug_messages, NULL);
265 /* Now actually run the tests */
267 for (t = tests; t->fn; t++) {
270 success = callinfork(t) && success;
271 } while (loop_forever);
275 return success ? 0 : 1;