2 * Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
23 #include "testutils.h"
25 gboolean tu_debugging_enabled = FALSE;
27 static gboolean run_all = TRUE;
28 static gboolean ignore_timeouts = FALSE;
29 static gboolean skip_fork = FALSE;
30 static gboolean only_one = FALSE;
31 static gboolean loop_forever = FALSE;
32 static guint64 occurrences = 1;
35 alarm_hdlr(int sig G_GNUC_UNUSED)
37 g_fprintf(stderr, "-- TEST TIMED OUT --\n");
42 * Run a single test, accouting for the timeout (if timeouts are not ignored)
43 * and output runtime information (in milliseconds) at the end of the run.
44 * Output avg/min/max only if the number of runs is strictly greater than one.
47 static gboolean run_one_test(TestUtilsTest *test)
51 const char *test_name = test->name;
54 gdouble total = 0.0, thisrun, mintime = G_MAXDOUBLE, maxtime = G_MINDOUBLE;
56 signal(SIGALRM, alarm_hdlr);
58 timer = g_timer_new();
60 while (count++ < occurrences) {
68 thisrun = g_timer_elapsed(timer, NULL);
70 if (mintime > thisrun)
72 if (maxtime < thisrun)
79 g_timer_destroy(timer);
85 g_fprintf(stderr, " PASS %s (total: %.06f", test_name, total);
86 if (occurrences > 1) {
87 total /= (gdouble) occurrences;
88 g_fprintf(stderr, ", avg/min/max: %.06f/%.06f/%.06f",
89 total, mintime, maxtime);
91 g_fprintf(stderr, ")\n");
93 g_fprintf(stderr, " FAIL %s (run %ju of %ju, after %.06f secs)\n",
94 test_name, (uintmax_t)count, (uintmax_t)occurrences, total);
101 * Call testfn in a forked process, such that any failures will trigger a
102 * test failure, but allow the other tests to proceed. The only exception is if
103 * -n is supplied at the command line, but in this case only one test is allowed
108 callinfork(TestUtilsTest *test)
115 result = run_one_test(test);
117 switch (pid = fork()) {
119 exit(run_one_test(test) ? 0 : 1);
125 default: /* parent */
126 waitpid(pid, &status, 0);
127 result = status == 0;
137 TestUtilsTest *tests)
139 printf("USAGE: <test-script> [options] [testname [testname [..]]]\n"
141 "Options can be one of:\n"
143 "\t-h: this message\n"
144 "\t-d: print debugging messages\n"
145 "\t-t: ignore timeouts\n"
146 "\t-n: do not fork\n"
147 "\t-c <count>: run each test <count> times instead of only once\n"
148 "\t-l: loop the same test repeatedly (use with -n for leak checks)\n"
150 "If no test names are specified, all tests are run. Available tests:\n"
153 printf("\t%s\n", tests->name);
159 ignore_debug_messages(
160 const gchar *log_domain G_GNUC_UNUSED,
161 GLogLevelFlags log_level G_GNUC_UNUSED,
162 const gchar *message G_GNUC_UNUSED,
163 gpointer user_data G_GNUC_UNUSED)
171 TestUtilsTest *tests)
176 /* first_parse the command line */
178 if (strcmp(argv[1], "-d") == 0) {
179 tu_debugging_enabled = TRUE;
180 } else if (strcmp(argv[1], "-t") == 0) {
181 ignore_timeouts = TRUE;
182 } else if (strcmp(argv[1], "-n") == 0) {
185 } else if (strcmp(argv[1], "-l") == 0) {
188 } else if (strcmp(argv[1], "-c") == 0) {
191 occurrences = g_ascii_strtoull(argv[1], &p, 10);
192 if (errno == ERANGE) {
193 g_fprintf(stderr, "%s is out of range\n", argv[1]);
197 g_fprintf(stderr, "The -c option expects a positive integer "
198 "as an argument, but \"%s\" isn't\n", argv[1]);
201 if (occurrences == 0) {
202 g_fprintf(stderr, "Sorry, I will not run tests 0 times\n");
205 } else if (strcmp(argv[1], "-h") == 0) {
211 for (t = tests; t->fn; t++) {
212 if (strcmp(argv[1], t->name) == 0) {
220 g_fprintf(stderr, "Test '%s' not found\n", argv[1]);
231 * Check whether the -c option has been given. In this case, -l must not be
232 * specified at the same time.
234 if (occurrences > 1 && loop_forever) {
235 g_fprintf(stderr, "-c and -l are incompatible\n");
240 for (t = tests; t->fn; t++)
247 for (t = tests; t->fn; t++) {
253 g_fprintf(stderr, "Only run one test with '-n'\n");
258 /* Make sure g_critical and g_error will exit */
259 g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
261 /* and silently drop debug messages unless we're debugging */
262 if (!tu_debugging_enabled) {
263 g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, ignore_debug_messages, NULL);
266 /* Now actually run the tests */
268 for (t = tests; t->fn; t++) {
271 success = callinfork(t) && success;
272 } while (loop_forever);
276 return success ? 0 : 1;