r16441: - give old tests a chance to report errors
[jra/samba/.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 "dlinklist.h"
25
26 void torture_comment(struct torture_context *context, const char *comment, ...) _PRINTF_ATTRIBUTE(2,3)
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, ...) _PRINTF_ATTRIBUTE(2,3)
43 {
44         va_list ap;
45
46         va_start(ap, fmt);
47         context->last_reason = talloc_vasprintf(context, fmt, ap);
48         va_end(ap);
49         context->last_result = TORTURE_FAIL;
50 }
51
52 void torture_skip(struct torture_context *context, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3)
53 {
54         va_list ap;
55         context->skipped++;
56
57         va_start(ap, fmt);
58         context->last_result = TORTURE_SKIP;
59         context->last_reason = talloc_vasprintf(context, fmt, ap);
60         va_end(ap);
61 }
62
63 struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name)
64 {
65         struct torture_suite *suite = talloc(ctx, struct torture_suite);
66
67         suite->name = talloc_strdup(suite, name);
68         suite->testcases = NULL;
69
70         return suite;
71 }
72
73 void torture_tcase_set_fixture(struct torture_tcase *tcase, 
74                 BOOL (*setup) (struct torture_context *, void **),
75                 BOOL (*teardown) (struct torture_context *, void *))
76 {
77         tcase->setup = setup;
78         tcase->teardown = teardown;
79 }
80
81 struct torture_test *torture_tcase_add_test(struct torture_tcase *tcase, 
82                                                 const char *name, 
83                                                 BOOL (*run) (struct torture_context *, 
84                                                                          const void *tcase_data,
85                                                                          const void *test_data),
86                                                 const void *data)
87 {
88         struct torture_test *test = talloc(tcase, struct torture_test);
89
90         test->name = talloc_strdup(test, name);
91         test->description = NULL;
92         test->run = run;
93         test->dangerous = False;
94         test->data = data;
95
96         DLIST_ADD(tcase->tests, test);
97
98         return test;
99 }
100
101 struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, 
102                                                          const char *name)
103 {
104         struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
105
106         tcase->name = talloc_strdup(tcase, name);
107         tcase->description = NULL;
108         tcase->setup = NULL;
109         tcase->teardown = NULL;
110         tcase->fixture_persistent = True;
111         tcase->tests = NULL;
112
113         DLIST_ADD(suite->testcases, tcase);
114
115         return tcase;
116 }
117
118 BOOL torture_run_suite(struct torture_context *context, 
119                                            struct torture_suite *suite)
120 {
121         BOOL ret = True;
122         struct torture_tcase *tcase;
123
124         if (context->ui_ops->suite_start)
125                 context->ui_ops->suite_start(context, suite);
126
127         for (tcase = suite->testcases; tcase; tcase = tcase->next) {
128                 ret &= torture_run_tcase(context, tcase);
129         }
130
131         if (context->ui_ops->suite_finish)
132                 context->ui_ops->suite_finish(context, suite);
133         
134         return ret;
135 }
136
137 static BOOL internal_torture_run_test(struct torture_context *context, 
138                                           struct torture_tcase *tcase,
139                                           struct torture_test *test,
140                                           BOOL already_setup,
141                                           const void *tcase_data)
142 {
143         BOOL ret;
144         void *data = NULL;
145
146         if (test->dangerous && !lp_parm_bool(-1, "torture", "dangerous", False)) {
147                 torture_skip(context, "disabled %s - enable dangerous tests to use", 
148                                          test->name);
149                 return True;
150         }
151
152         if (!already_setup && tcase->setup && !tcase->setup(context, &data))
153                 return False;
154
155         context->active_tcase = tcase;
156         context->active_test = test;
157
158         if (context->ui_ops->test_start)
159                 context->ui_ops->test_start(context, tcase, test);
160
161         context->last_reason = NULL;
162         context->last_result = TORTURE_OK;
163
164         ret = test->run(context, !already_setup?data:tcase_data, test->data);
165         if (!ret) {
166                 context->last_reason = talloc_strdup(context, "...");
167                 context->last_result = TORTURE_FAIL;
168         }
169
170         if (context->ui_ops->test_result)
171                 context->ui_ops->test_result(context, context->last_result, 
172                                                                          context->last_reason);
173
174
175         switch (context->last_result) {
176                 case TORTURE_SKIP: context->success++; break;
177                 case TORTURE_FAIL: context->failed++; break;
178                 case TORTURE_TODO: context->todo++; break;
179                 case TORTURE_OK: context->success++; break;
180         }
181
182         talloc_free(context->last_reason);
183
184         context->active_test = NULL;
185         context->active_tcase = NULL;
186
187         if (!already_setup && tcase->teardown && !tcase->teardown(context, data))
188                 return False;
189
190         return ret;
191 }
192
193 BOOL torture_run_tcase(struct torture_context *context, 
194                                            struct torture_tcase *tcase)
195 {
196         BOOL ret = True;
197         void *data = NULL;
198         struct torture_test *test;
199
200         context->active_tcase = tcase;
201         if (context->ui_ops->tcase_start)
202                 context->ui_ops->tcase_start(context, tcase);
203
204         if (tcase->fixture_persistent && tcase->setup 
205                 && !tcase->setup(context, &data)) {
206                 ret = False;
207                 goto done;
208         }
209
210         for (test = tcase->tests; test; test = test->next) {
211                 ret &= internal_torture_run_test(context, tcase, test, 
212                                 tcase->fixture_persistent,
213                                 (tcase->setup?data:tcase->data));
214         }
215
216         if (tcase->fixture_persistent && tcase->teardown &&
217                 !tcase->teardown(context, data))
218                 ret = False;
219
220 done:
221         context->active_tcase = NULL;
222
223         if (context->ui_ops->tcase_finish)
224                 context->ui_ops->tcase_finish(context, tcase);
225
226         return ret;
227 }
228
229 BOOL torture_run_test(struct torture_context *context, 
230                                           struct torture_tcase *tcase,
231                                           struct torture_test *test)
232 {
233         return internal_torture_run_test(context, tcase, test, False, NULL);
234 }
235
236 const char *torture_setting(struct torture_context *test, const char *name, 
237                                                         const char *default_value)
238 {
239         const char *ret = lp_parm_string(-1, "torture", name);
240
241         if (ret == NULL)
242                 return default_value;
243
244         return ret;
245 }
246
247 static BOOL simple_tcase_helper(struct torture_context *test, 
248                                                                 const void *tcase_data,
249                                                                 const void *test_data)
250 {
251         BOOL (*run) (struct torture_context *, const void *) = test_data;
252
253         return run(test, tcase_data);
254 }
255
256 struct torture_tcase *torture_suite_add_simple_tcase(
257                                         struct torture_suite *suite, 
258                                         const char *name,
259                                         BOOL (*run) (struct torture_context *test, const void *),
260                                         const void *data)
261 {
262         struct torture_tcase *tcase;
263         
264         tcase = torture_suite_add_tcase(suite, name);
265         tcase->data = data;
266
267         torture_tcase_add_test(tcase, name, simple_tcase_helper, run);
268
269         return tcase;
270 }
271
272 BOOL torture_teardown_free(struct torture_context *torture, void *data)
273 {
274         return talloc_free(data);
275 }