a614b7c2b83c3aee9241e0d6c2d60c4ee806a39f
[debian/amanda] / common-src / testutils.c
1 /*
2  * Copyright (c) 2005-2008 Zmanda Inc.  All Rights Reserved.
3  *
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.
7  *
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
11  * for more details.
12  *
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
16  *
17  * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300
18  * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19  */
20
21 #include "amanda.h"
22 #include "testutils.h"
23
24 int tu_debugging_enabled = FALSE;
25
26 static void
27 alarm_hdlr(int sig G_GNUC_UNUSED)
28 {
29     fprintf(stderr, "-- TEST TIMED OUT --\n");
30     exit(1);
31 }
32
33 /* Call testfn in a forked process, such that any failures will trigger a
34  * test failure, but allow the other tests to proceed.
35  */
36 static int
37 callinfork(TestUtilsTest *test, int ignore_timeouts)
38 {
39     pid_t pid;
40     int success;
41     amwait_t status;
42
43     switch (pid = fork()) {
44         case 0: /* child */
45             /* kill the test after a bit */
46             signal(SIGALRM, alarm_hdlr);
47             if (!ignore_timeouts) alarm(test->timeout);
48
49             success = test->fn();
50             exit(success? 0:1);
51
52         case -1:
53             perror("fork");
54             exit(1);
55
56         default: /* parent */
57             waitpid(pid, &status, 0);
58             if (status == 0) {
59                 fprintf(stderr, " PASS %s\n", test->name);
60             } else {
61                 fprintf(stderr, " FAIL %s\n", test->name);
62             }
63             return status == 0;
64     }
65 }
66
67 static void
68 usage(
69     TestUtilsTest *tests)
70 {
71     printf("USAGE: <test-script> [-d] [-h] [testname [testname [..]]]\n"
72         "\n"
73         "\t-h: this message\n"
74         "\t-d: print debugging messages\n"
75         "\t-t: ignore timeouts\n"
76         "\n"
77         "If no test names are specified, all tests are run.  Available tests:\n"
78         "\n");
79     while (tests->fn) {
80         printf("\t%s\n", tests->name);
81         tests++;
82     }
83 }
84
85 static void
86 ignore_debug_messages(
87             const gchar *log_domain G_GNUC_UNUSED,
88             GLogLevelFlags log_level G_GNUC_UNUSED,
89             const gchar *message G_GNUC_UNUSED,
90             gpointer user_data G_GNUC_UNUSED)
91 {
92 }
93
94 int
95 testutils_run_tests(
96     int argc,
97     char **argv,
98     TestUtilsTest *tests)
99 {
100     TestUtilsTest *t;
101     int run_all = 1;
102     int success;
103     int ignore_timeouts = 0;
104
105     /* first_parse the command line */
106     while (argc > 1) {
107         if (strcmp(argv[1], "-d") == 0) {
108             tu_debugging_enabled = TRUE;
109         } else if (strcmp(argv[1], "-t") == 0) {
110             ignore_timeouts = TRUE;
111         } else if (strcmp(argv[1], "-h") == 0) {
112             usage(tests);
113             return 1;
114         } else {
115             int found = 0;
116
117             for (t = tests; t->fn; t++) {
118                 if (strcmp(argv[1], t->name) == 0) {
119                     found = 1;
120                     t->selected = 1;
121                     break;
122                 }
123             }
124
125             if (!found) {
126                 fprintf(stderr, "Test '%s' not found\n", argv[1]);
127                 return 1;
128             }
129
130             run_all = 0;
131         }
132
133         argc--; argv++;
134     }
135
136     /* Make sure g_critical and g_error will exit */
137     g_log_set_always_fatal(G_LOG_LEVEL_ERROR |  G_LOG_LEVEL_CRITICAL);
138
139     /* and silently drop debug messages unless we're debugging */
140     if (!tu_debugging_enabled) {
141         g_log_set_handler(NULL, G_LOG_LEVEL_DEBUG, ignore_debug_messages, NULL);
142     }
143
144     /* Now actually run the tests */
145     success = 1;
146     for (t = tests; t->fn; t++) {
147         if (run_all || t->selected) {
148             success = callinfork(t, ignore_timeouts) && success;
149         }
150     }
151
152     return success? 0:1;
153 }