r19350: Properly list LOCAL-TALLOC under the "LOCAL" header.
[samba.git] / source / 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 "torture/torture.h"
25 #include "lib/util/dlinklist.h"
26
27 void torture_comment(struct torture_context *context, 
28                                                  const char *comment, ...)
29 {
30         va_list ap;
31         char *tmp;
32
33         if (!context->ui_ops->comment)
34                 return;
35
36         va_start(ap, comment);
37         tmp = talloc_vasprintf(context, comment, ap);
38                 
39         context->ui_ops->comment(context, tmp);
40         
41         talloc_free(tmp);
42 }
43
44 void _torture_fail_ext(struct torture_context *context, 
45                                           const char *fmt, ...)
46 {
47         va_list ap;
48
49         va_start(ap, fmt);
50         context->last_reason = talloc_vasprintf(context, fmt, ap);
51         /* make sure the reason for the failure is displayed */
52         context->ui_ops->comment(context, context->last_reason);
53         va_end(ap);
54         context->last_result = TORTURE_FAIL;
55 }
56
57 void _torture_skip_ext(struct torture_context *context, 
58                                           const char *fmt, ...)
59 {
60         va_list ap;
61         context->skipped++;
62
63         va_start(ap, fmt);
64         context->last_result = TORTURE_SKIP;
65         context->last_reason = talloc_vasprintf(context, fmt, ap);
66         va_end(ap);
67 }
68
69 struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name)
70 {
71         struct torture_suite *suite = talloc_zero(ctx, struct torture_suite);
72
73         suite->name = talloc_strdup(suite, name);
74         suite->testcases = NULL;
75         suite->children = NULL;
76
77         return suite;
78 }
79
80 void torture_tcase_set_fixture(struct torture_tcase *tcase, 
81                 BOOL (*setup) (struct torture_context *, void **),
82                 BOOL (*teardown) (struct torture_context *, void *))
83 {
84         tcase->setup = setup;
85         tcase->teardown = teardown;
86 }
87
88 static bool wrap_test_with_testcase(struct torture_context *torture_ctx,
89                                                                         struct torture_tcase *tcase,
90                                                                         struct torture_test *test)
91 {
92         bool (*fn) (struct torture_context *, 
93                                  const void *tcase_data,
94                                  const void *test_data);
95
96         fn = test->fn;
97
98         return fn(torture_ctx, tcase->data, test->data);
99 }
100
101 struct torture_test *torture_tcase_add_test(struct torture_tcase *tcase, 
102                                                 const char *name, 
103                                                 bool (*run) (struct torture_context *, 
104                                                                          const void *tcase_data,
105                                                                          const void *test_data),
106                                                 const void *data)
107 {
108         struct torture_test *test = talloc(tcase, struct torture_test);
109
110         test->name = talloc_strdup(test, name);
111         test->description = NULL;
112         test->run = wrap_test_with_testcase;
113         test->fn = run;
114         test->dangerous = False;
115         test->data = data;
116
117         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
118
119         return test;
120 }
121
122 struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, 
123                                                          const char *name)
124 {
125         struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
126
127         tcase->name = talloc_strdup(tcase, name);
128         tcase->description = NULL;
129         tcase->setup = NULL;
130         tcase->teardown = NULL;
131         tcase->fixture_persistent = True;
132         tcase->tests = NULL;
133
134         DLIST_ADD_END(suite->testcases, tcase, struct torture_tcase *);
135
136         return tcase;
137 }
138
139 BOOL torture_run_suite(struct torture_context *context, 
140                                            struct torture_suite *suite)
141 {
142         BOOL ret = True;
143         struct torture_tcase *tcase;
144         struct torture_suite *tsuite;
145
146         context->level++;
147         if (context->ui_ops->suite_start)
148                 context->ui_ops->suite_start(context, suite);
149
150         if (suite->path)
151                 torture_subunit_run_suite(context, suite);
152
153         for (tcase = suite->testcases; tcase; tcase = tcase->next) {
154                 ret &= torture_run_tcase(context, tcase);
155         }
156
157         for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
158                 ret &= torture_run_suite(context, tsuite);
159         }
160
161         if (context->ui_ops->suite_finish)
162                 context->ui_ops->suite_finish(context, suite);
163
164         context->level--;
165         
166         return ret;
167 }
168
169 void torture_ui_test_start(struct torture_context *context,
170                                                            struct torture_tcase *tcase,
171                                                            struct torture_test *test)
172 {
173         if (context->ui_ops->test_start)
174                 context->ui_ops->test_start(context, tcase, test);
175 }
176
177 void torture_ui_test_result(struct torture_context *context,
178                                                                 enum torture_result result,
179                                                                 const char *comment)
180 {
181         if (context->ui_ops->test_result)
182                 context->ui_ops->test_result(context, result, comment);
183
184
185         switch (result) {
186                 case TORTURE_SKIP: context->success++; break;
187                 case TORTURE_FAIL: context->failed++; break;
188                 case TORTURE_TODO: context->todo++; break;
189                 case TORTURE_OK: context->success++; break;
190         }
191 }
192
193 static BOOL internal_torture_run_test(struct torture_context *context, 
194                                           struct torture_tcase *tcase,
195                                           struct torture_test *test,
196                                           BOOL already_setup)
197 {
198         BOOL ret;
199
200         if (test->dangerous && !torture_setting_bool(context, "dangerous", False)) {
201                 _torture_skip_ext(context, 
202                                 "disabled %s - enable dangerous tests to use", test->name);
203                 return True;
204         }
205
206         if (!already_setup && tcase->setup && 
207                 !tcase->setup(context, &(tcase->data)))
208                 return False;
209
210         context->active_tcase = tcase;
211         context->active_test = test;
212
213         torture_ui_test_start(context, tcase, test);
214
215         context->last_reason = NULL;
216         context->last_result = TORTURE_OK;
217
218         ret = test->run(context, tcase, test);
219         if (!ret) {
220                 if (context->last_reason == NULL)
221                         context->last_reason = talloc_strdup(context, "...");
222                 context->last_result = TORTURE_FAIL;
223         }
224
225         torture_ui_test_result(context, context->last_result, context->last_reason);
226         
227         talloc_free(context->last_reason);
228
229         context->active_test = NULL;
230         context->active_tcase = NULL;
231
232         if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data))
233                 return False;
234
235         return ret;
236 }
237
238 BOOL torture_run_tcase(struct torture_context *context, 
239                                            struct torture_tcase *tcase)
240 {
241         BOOL ret = True;
242         struct torture_test *test;
243
244         context->level++;
245
246         context->active_tcase = tcase;
247         if (context->ui_ops->tcase_start)
248                 context->ui_ops->tcase_start(context, tcase);
249
250         if (tcase->fixture_persistent && tcase->setup 
251                 && !tcase->setup(context, &tcase->data)) {
252                 ret = False;
253                 goto done;
254         }
255
256         for (test = tcase->tests; test; test = test->next) {
257                 ret &= internal_torture_run_test(context, tcase, test, 
258                                 tcase->fixture_persistent);
259         }
260
261         if (tcase->fixture_persistent && tcase->teardown &&
262                 !tcase->teardown(context, tcase->data))
263                 ret = False;
264
265 done:
266         context->active_tcase = NULL;
267
268         if (context->ui_ops->tcase_finish)
269                 context->ui_ops->tcase_finish(context, tcase);
270
271         context->level--;
272
273         return ret;
274 }
275
276 BOOL torture_run_test(struct torture_context *context, 
277                                           struct torture_tcase *tcase,
278                                           struct torture_test *test)
279 {
280         return internal_torture_run_test(context, tcase, test, False);
281 }
282
283 int torture_setting_int(struct torture_context *test, const char *name, 
284                                                         int default_value)
285 {
286         return lp_parm_int(-1, "torture", name, default_value);
287 }
288
289 bool torture_setting_bool(struct torture_context *test, const char *name, 
290                                                         bool default_value)
291 {
292         return lp_parm_bool(-1, "torture", name, default_value);
293 }
294
295 const char *torture_setting_string(struct torture_context *test, const char *name, 
296                                                         const char *default_value)
297 {
298         const char *ret = lp_parm_string(-1, "torture", name);
299
300         if (ret == NULL)
301                 return default_value;
302
303         return ret;
304 }
305
306 static bool wrap_test_with_simple_tcase(struct torture_context *torture_ctx,
307                                                                         struct torture_tcase *tcase,
308                                                                         struct torture_test *test)
309 {
310         bool (*fn) (struct torture_context *, const void *tcase_data);
311
312         fn = test->fn;
313
314         return fn(torture_ctx, test->data);
315 }
316
317 struct torture_tcase *torture_suite_add_simple_tcase(
318                                         struct torture_suite *suite, 
319                                         const char *name,
320                                         bool (*run) (struct torture_context *test, const void *),
321                                         const void *data)
322 {
323         struct torture_tcase *tcase;
324         struct torture_test *test; 
325         
326         tcase = torture_suite_add_tcase(suite, name);
327
328         test = talloc(tcase, struct torture_test);
329
330         test->name = talloc_strdup(test, name);
331         test->description = NULL;
332         test->run = wrap_test_with_simple_tcase;
333         test->fn = run;
334         test->data = data;
335         test->dangerous = False;
336
337         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
338
339         return tcase;
340 }
341
342 static bool wrap_simple_test(struct torture_context *torture_ctx,
343                                                                         struct torture_tcase *tcase,
344                                                                         struct torture_test *test)
345 {
346         bool (*fn) (struct torture_context *);
347
348         fn = test->fn;
349
350         return fn(torture_ctx);
351 }
352
353 struct torture_tcase *torture_suite_add_simple_test(
354                                         struct torture_suite *suite, 
355                                         const char *name,
356                                         bool (*run) (struct torture_context *test))
357 {
358         struct torture_test *test; 
359         struct torture_tcase *tcase;
360         
361         tcase = torture_suite_add_tcase(suite, name);
362
363         test = talloc(tcase, struct torture_test);
364
365         test->name = talloc_strdup(test, name);
366         test->description = NULL;
367         test->run = wrap_simple_test;
368         test->fn = run;
369         test->dangerous = false;
370
371         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
372
373         return tcase;
374 }
375
376 BOOL torture_teardown_free(struct torture_context *torture, void *data)
377 {
378         return talloc_free(data);
379 }
380
381
382 bool torture_suite_add_suite(struct torture_suite *suite, 
383                                                          struct torture_suite *child)
384 {
385         if (child == NULL)
386                 return false;
387
388         DLIST_ADD_END(suite->children, child, struct torture_suite *);
389
390         /* FIXME: Check for duplicates and return false if the 
391          * added suite already exists as a child */
392
393         return true;
394 }
395
396
397 struct torture_suite *torture_find_suite(struct torture_suite *parent, 
398                                                                                  const char *name)
399 {
400         struct torture_suite *child;
401
402         for (child = parent->children; child; child = child->next) 
403                 if (!strcmp(child->name, name))
404                         return child;
405
406         return NULL;
407 }