r19298: make sure torture_fail() gives a useful message
[nivanova/samba-autobuild/.git] / source4 / torture / ui.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture UI functions
4
5    Copyright (C) Jelmer Vernooij 2006
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "torture/ui.h"
24 #include "lib/util/dlinklist.h"
25
26 void torture_comment(struct torture_context *context, const char *comment, ...)
27 {
28         va_list ap;
29         char *tmp;
30
31         if (!context->ui_ops->comment)
32                 return;
33
34         va_start(ap, comment);
35         tmp = talloc_vasprintf(context, comment, ap);
36                 
37         context->ui_ops->comment(context, tmp);
38         
39         talloc_free(tmp);
40 }
41
42 void torture_fail(struct torture_context *context, const char *fmt, ...)
43 {
44         va_list ap;
45
46         va_start(ap, fmt);
47         context->last_reason = talloc_vasprintf(context, fmt, ap);
48         /* make sure the reason for the failure is displayed */
49         context->ui_ops->comment(context, context->last_reason);
50         va_end(ap);
51         context->last_result = TORTURE_FAIL;
52 }
53
54 void torture_skip(struct torture_context *context, const char *fmt, ...)
55 {
56         va_list ap;
57         context->skipped++;
58
59         va_start(ap, fmt);
60         context->last_result = TORTURE_SKIP;
61         context->last_reason = talloc_vasprintf(context, fmt, ap);
62         va_end(ap);
63 }
64
65 struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name)
66 {
67         struct torture_suite *suite = talloc(ctx, struct torture_suite);
68
69         suite->name = talloc_strdup(suite, name);
70         suite->testcases = NULL;
71
72         return suite;
73 }
74
75 void torture_tcase_set_fixture(struct torture_tcase *tcase, 
76                 BOOL (*setup) (struct torture_context *, void **),
77                 BOOL (*teardown) (struct torture_context *, void *))
78 {
79         tcase->setup = setup;
80         tcase->teardown = teardown;
81 }
82
83 struct torture_test *torture_tcase_add_test(struct torture_tcase *tcase, 
84                                                 const char *name, 
85                                                 BOOL (*run) (struct torture_context *, 
86                                                                          const void *tcase_data,
87                                                                          const void *test_data),
88                                                 const void *data)
89 {
90         struct torture_test *test = talloc(tcase, struct torture_test);
91
92         test->name = talloc_strdup(test, name);
93         test->description = NULL;
94         test->run = run;
95         test->dangerous = False;
96         test->data = data;
97
98         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
99
100         return test;
101 }
102
103 struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, 
104                                                          const char *name)
105 {
106         struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
107
108         tcase->name = talloc_strdup(tcase, name);
109         tcase->description = NULL;
110         tcase->setup = NULL;
111         tcase->teardown = NULL;
112         tcase->fixture_persistent = True;
113         tcase->tests = NULL;
114
115         DLIST_ADD(suite->testcases, tcase);
116
117         return tcase;
118 }
119
120 BOOL torture_run_suite(struct torture_context *context, 
121                                            struct torture_suite *suite)
122 {
123         BOOL ret = True;
124         struct torture_tcase *tcase;
125
126         if (context->ui_ops->suite_start)
127                 context->ui_ops->suite_start(context, suite);
128
129         for (tcase = suite->testcases; tcase; tcase = tcase->next) {
130                 ret &= torture_run_tcase(context, tcase);
131         }
132
133         if (context->ui_ops->suite_finish)
134                 context->ui_ops->suite_finish(context, suite);
135         
136         return ret;
137 }
138
139 static BOOL internal_torture_run_test(struct torture_context *context, 
140                                           struct torture_tcase *tcase,
141                                           struct torture_test *test,
142                                           BOOL already_setup,
143                                           const void *tcase_data)
144 {
145         BOOL ret;
146         void *data = NULL;
147
148         if (test->dangerous && !lp_parm_bool(-1, "torture", "dangerous", False)) {
149                 torture_skip(context, "disabled %s - enable dangerous tests to use", 
150                                          test->name);
151                 return True;
152         }
153
154         if (!already_setup && tcase->setup && !tcase->setup(context, &data))
155                 return False;
156
157         context->active_tcase = tcase;
158         context->active_test = test;
159
160         if (context->ui_ops->test_start)
161                 context->ui_ops->test_start(context, tcase, test);
162
163         context->last_reason = NULL;
164         context->last_result = TORTURE_OK;
165
166         ret = test->run(context, !already_setup?data:tcase_data, test->data);
167         if (!ret) {
168                 context->last_reason = talloc_strdup(context, "...");
169                 context->last_result = TORTURE_FAIL;
170         }
171
172         if (context->ui_ops->test_result)
173                 context->ui_ops->test_result(context, context->last_result, 
174                                                                          context->last_reason);
175
176
177         switch (context->last_result) {
178                 case TORTURE_SKIP: context->success++; break;
179                 case TORTURE_FAIL: context->failed++; break;
180                 case TORTURE_TODO: context->todo++; break;
181                 case TORTURE_OK: context->success++; break;
182         }
183
184         talloc_free(context->last_reason);
185
186         context->active_test = NULL;
187         context->active_tcase = NULL;
188
189         if (!already_setup && tcase->teardown && !tcase->teardown(context, data))
190                 return False;
191
192         return ret;
193 }
194
195 BOOL torture_run_tcase(struct torture_context *context, 
196                                            struct torture_tcase *tcase)
197 {
198         BOOL ret = True;
199         void *data = NULL;
200         struct torture_test *test;
201
202         context->active_tcase = tcase;
203         if (context->ui_ops->tcase_start)
204                 context->ui_ops->tcase_start(context, tcase);
205
206         if (tcase->fixture_persistent && tcase->setup 
207                 && !tcase->setup(context, &data)) {
208                 ret = False;
209                 goto done;
210         }
211
212         for (test = tcase->tests; test; test = test->next) {
213                 ret &= internal_torture_run_test(context, tcase, test, 
214                                 tcase->fixture_persistent,
215                                 (tcase->setup?data:tcase->data));
216         }
217
218         if (tcase->fixture_persistent && tcase->teardown &&
219                 !tcase->teardown(context, data))
220                 ret = False;
221
222 done:
223         context->active_tcase = NULL;
224
225         if (context->ui_ops->tcase_finish)
226                 context->ui_ops->tcase_finish(context, tcase);
227
228         return ret;
229 }
230
231 BOOL torture_run_test(struct torture_context *context, 
232                                           struct torture_tcase *tcase,
233                                           struct torture_test *test)
234 {
235         return internal_torture_run_test(context, tcase, test, False, NULL);
236 }
237
238 const char *torture_setting(struct torture_context *test, const char *name, 
239                                                         const char *default_value)
240 {
241         const char *ret = lp_parm_string(-1, "torture", name);
242
243         if (ret == NULL)
244                 return default_value;
245
246         return ret;
247 }
248
249 static BOOL simple_tcase_helper(struct torture_context *test, 
250                                                                 const void *tcase_data,
251                                                                 const void *test_data)
252 {
253         BOOL (*run) (struct torture_context *, const void *) = test_data;
254
255         return run(test, tcase_data);
256 }
257
258 struct torture_tcase *torture_suite_add_simple_tcase(
259                                         struct torture_suite *suite, 
260                                         const char *name,
261                                         BOOL (*run) (struct torture_context *test, const void *),
262                                         const void *data)
263 {
264         struct torture_tcase *tcase;
265         
266         tcase = torture_suite_add_tcase(suite, name);
267         tcase->data = data;
268
269         torture_tcase_add_test(tcase, name, simple_tcase_helper, run);
270
271         return tcase;
272 }
273
274 BOOL torture_teardown_free(struct torture_context *torture, void *data)
275 {
276         return talloc_free(data);
277 }