r24741: More use of the torture API.
[gd/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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "torture/ui.h"
23 #include "torture/torture.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_warning(struct torture_context *context, const char *comment, ...)
43 {
44         va_list ap;
45         char *tmp;
46
47         if (!context->ui_ops->warning)
48                 return;
49
50         va_start(ap, comment);
51         tmp = talloc_vasprintf(context, comment, ap);
52
53         context->ui_ops->warning(context, tmp);
54
55         talloc_free(tmp);
56 }
57
58 void torture_result(struct torture_context *context, 
59                     enum torture_result result, const char *fmt, ...)
60 {
61         va_list ap;
62
63         va_start(ap, fmt);
64
65         context->last_result = result;
66         context->last_reason = talloc_vasprintf(context, fmt, ap);
67         va_end(ap);
68 }
69
70 struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name)
71 {
72         struct torture_suite *suite = talloc_zero(ctx, struct torture_suite);
73
74         suite->name = talloc_strdup(suite, name);
75         suite->testcases = NULL;
76         suite->children = NULL;
77
78         return suite;
79 }
80
81 void torture_tcase_set_fixture(struct torture_tcase *tcase, 
82                 BOOL (*setup) (struct torture_context *, void **),
83                 BOOL (*teardown) (struct torture_context *, void *))
84 {
85         tcase->setup = setup;
86         tcase->teardown = teardown;
87 }
88
89 static bool wrap_test_with_testcase(struct torture_context *torture_ctx,
90                                                                         struct torture_tcase *tcase,
91                                                                         struct torture_test *test)
92 {
93         bool (*fn) (struct torture_context *, 
94                                  const void *tcase_data,
95                                  const void *test_data);
96
97         fn = test->fn;
98
99         return fn(torture_ctx, tcase->data, test->data);
100 }
101
102 struct torture_test *torture_tcase_add_test(struct torture_tcase *tcase, 
103                                                 const char *name, 
104                                                 bool (*run) (struct torture_context *, 
105                                                                          const void *tcase_data,
106                                                                          const void *test_data),
107                                                 const void *data)
108 {
109         struct torture_test *test = talloc(tcase, struct torture_test);
110
111         test->name = talloc_strdup(test, name);
112         test->description = NULL;
113         test->run = wrap_test_with_testcase;
114         test->fn = run;
115         test->dangerous = False;
116         test->data = data;
117
118         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
119
120         return test;
121 }
122
123
124 bool torture_suite_init_tcase(struct torture_suite *suite,
125                                                                          struct torture_tcase *tcase,
126                                                                          const char *name)
127 {
128         tcase->name = talloc_strdup(tcase, name);
129         tcase->description = NULL;
130         tcase->setup = NULL;
131         tcase->teardown = NULL;
132         tcase->fixture_persistent = True;
133         tcase->tests = NULL;
134
135         DLIST_ADD_END(suite->testcases, tcase, struct torture_tcase *);
136
137         return true;
138 }
139
140
141 struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, 
142                                                          const char *name)
143 {
144         struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
145
146         if (!torture_suite_init_tcase(suite, tcase, name))
147                 return NULL;
148
149         return tcase;
150 }
151
152 BOOL torture_run_suite(struct torture_context *context, 
153                                            struct torture_suite *suite)
154 {
155         BOOL ret = True;
156         struct torture_tcase *tcase;
157         struct torture_suite *tsuite;
158         char *old_testname;
159
160         context->level++;
161         if (context->ui_ops->suite_start)
162                 context->ui_ops->suite_start(context, suite);
163
164         old_testname = context->active_testname;
165         if (old_testname != NULL)
166                 context->active_testname = talloc_asprintf(context, "%s-%s", 
167                                                                                            old_testname, suite->name);
168         else
169                 context->active_testname = talloc_strdup(context, suite->name);
170
171         for (tcase = suite->testcases; tcase; tcase = tcase->next) {
172                 ret &= torture_run_tcase(context, tcase);
173         }
174
175         for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
176                 ret &= torture_run_suite(context, tsuite);
177         }
178
179         talloc_free(context->active_testname);
180         context->active_testname = old_testname;
181
182         if (context->ui_ops->suite_finish)
183                 context->ui_ops->suite_finish(context, suite);
184
185         context->level--;
186         
187         return ret;
188 }
189
190 void torture_ui_test_start(struct torture_context *context,
191                                                            struct torture_tcase *tcase,
192                                                            struct torture_test *test)
193 {
194         if (context->ui_ops->test_start)
195                 context->ui_ops->test_start(context, tcase, test);
196 }
197
198 int str_list_match(const char *name, char **list)
199 {
200         int i, ret = 0;
201         if (list == NULL)
202                 return 0;
203
204         for (i = 0; list[i]; i++) {
205                 if (gen_fnmatch(list[i], name) == 0)
206                         ret++;
207         }
208         return ret;
209 }
210
211 void torture_ui_test_result(struct torture_context *context,
212                                                                 enum torture_result result,
213                                                                 const char *comment)
214 {
215         if (context->ui_ops->test_result)
216                 context->ui_ops->test_result(context, result, comment);
217
218         if (result == TORTURE_ERROR || result == TORTURE_FAIL)
219                 context->returncode = false;
220 }
221
222 static BOOL internal_torture_run_test(struct torture_context *context, 
223                                           struct torture_tcase *tcase,
224                                           struct torture_test *test,
225                                           BOOL already_setup)
226 {
227         BOOL ret;
228         char *old_testname;
229
230         if (test->dangerous && !torture_setting_bool(context, "dangerous", False)) {
231                 torture_result(context, TORTURE_SKIP,
232                                 "disabled %s - enable dangerous tests to use", test->name);
233                 return True;
234         }
235
236         if (!already_setup && tcase->setup && 
237                 !tcase->setup(context, &(tcase->data)))
238                 return False;
239
240         if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
241                 old_testname = context->active_testname;
242                 context->active_testname = talloc_asprintf(context, "%s-%s", 
243                                                                                            old_testname, test->name);
244         }
245         context->active_tcase = tcase;
246         context->active_test = test;
247
248         torture_ui_test_start(context, tcase, test);
249
250
251         context->last_reason = NULL;
252         context->last_result = TORTURE_OK;
253
254         ret = test->run(context, tcase, test);
255         if (!ret && context->last_result == TORTURE_OK) {
256                 if (context->last_reason == NULL)
257                         context->last_reason = talloc_strdup(context, "Unknown error/failure");
258                 context->last_result = TORTURE_ERROR;
259         }
260
261         torture_ui_test_result(context, context->last_result, context->last_reason);
262         
263         talloc_free(context->last_reason);
264
265         if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
266                 talloc_free(context->active_testname);
267                 context->active_testname = old_testname;
268         }
269         context->active_test = NULL;
270         context->active_tcase = NULL;
271
272         if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data))
273                 return False;
274
275         return ret;
276 }
277
278 BOOL torture_run_tcase(struct torture_context *context, 
279                                            struct torture_tcase *tcase)
280 {
281         BOOL ret = True;
282         char *old_testname;
283         struct torture_test *test;
284
285         context->level++;
286
287         context->active_tcase = tcase;
288         if (context->ui_ops->tcase_start)
289                 context->ui_ops->tcase_start(context, tcase);
290
291         if (tcase->fixture_persistent && tcase->setup 
292                 && !tcase->setup(context, &tcase->data)) {
293                 ret = False;
294                 goto done;
295         }
296
297         old_testname = context->active_testname;
298         context->active_testname = talloc_asprintf(context, "%s-%s", 
299                                                                                            old_testname, tcase->name);
300         for (test = tcase->tests; test; test = test->next) {
301                 ret &= internal_torture_run_test(context, tcase, test, 
302                                 tcase->fixture_persistent);
303         }
304         talloc_free(context->active_testname);
305         context->active_testname = old_testname;
306
307         if (tcase->fixture_persistent && tcase->teardown &&
308                 !tcase->teardown(context, tcase->data))
309                 ret = False;
310
311 done:
312         context->active_tcase = NULL;
313
314         if (context->ui_ops->tcase_finish)
315                 context->ui_ops->tcase_finish(context, tcase);
316
317         context->level--;
318
319         return ret;
320 }
321
322 BOOL torture_run_test(struct torture_context *context, 
323                                           struct torture_tcase *tcase,
324                                           struct torture_test *test)
325 {
326         return internal_torture_run_test(context, tcase, test, False);
327 }
328
329 int torture_setting_int(struct torture_context *test, const char *name, 
330                                                         int default_value)
331 {
332         return lp_parm_int(-1, "torture", name, default_value);
333 }
334
335 double torture_setting_double(struct torture_context *test, const char *name, 
336                                                         double default_value)
337 {
338         return lp_parm_double(-1, "torture", name, default_value);
339 }
340
341 bool torture_setting_bool(struct torture_context *test, const char *name, 
342                                                         bool default_value)
343 {
344         return lp_parm_bool(-1, "torture", name, default_value);
345 }
346
347 const char *torture_setting_string(struct torture_context *test, const char *name, 
348                                                         const char *default_value)
349 {
350         const char *ret = lp_parm_string(-1, "torture", name);
351
352         if (ret == NULL)
353                 return default_value;
354
355         return ret;
356 }
357
358 static bool wrap_test_with_simple_tcase(struct torture_context *torture_ctx,
359                                                                         struct torture_tcase *tcase,
360                                                                         struct torture_test *test)
361 {
362         bool (*fn) (struct torture_context *, const void *tcase_data);
363
364         fn = test->fn;
365
366         return fn(torture_ctx, test->data);
367 }
368
369 struct torture_tcase *torture_suite_add_simple_tcase(
370                                         struct torture_suite *suite, 
371                                         const char *name,
372                                         bool (*run) (struct torture_context *test, const void *),
373                                         const void *data)
374 {
375         struct torture_tcase *tcase;
376         struct torture_test *test; 
377         
378         tcase = torture_suite_add_tcase(suite, name);
379
380         test = talloc(tcase, struct torture_test);
381
382         test->name = talloc_strdup(test, name);
383         test->description = NULL;
384         test->run = wrap_test_with_simple_tcase;
385         test->fn = run;
386         test->data = data;
387         test->dangerous = false;
388
389         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
390
391         return tcase;
392 }
393
394 static bool wrap_simple_test(struct torture_context *torture_ctx,
395                                                                         struct torture_tcase *tcase,
396                                                                         struct torture_test *test)
397 {
398         bool (*fn) (struct torture_context *);
399
400         fn = test->fn;
401
402         return fn(torture_ctx);
403 }
404
405 struct torture_tcase *torture_suite_add_simple_test(
406                                         struct torture_suite *suite, 
407                                         const char *name,
408                                         bool (*run) (struct torture_context *test))
409 {
410         struct torture_test *test; 
411         struct torture_tcase *tcase;
412         
413         tcase = torture_suite_add_tcase(suite, name);
414
415         test = talloc(tcase, struct torture_test);
416
417         test->name = talloc_strdup(test, name);
418         test->description = NULL;
419         test->run = wrap_simple_test;
420         test->fn = run;
421         test->dangerous = false;
422
423         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
424
425         return tcase;
426 }
427
428 bool torture_suite_add_suite(struct torture_suite *suite, 
429                                                          struct torture_suite *child)
430 {
431         if (child == NULL)
432                 return false;
433
434         DLIST_ADD_END(suite->children, child, struct torture_suite *);
435
436         /* FIXME: Check for duplicates and return false if the 
437          * added suite already exists as a child */
438
439         return true;
440 }
441
442
443 struct torture_suite *torture_find_suite(struct torture_suite *parent, 
444                                                                                  const char *name)
445 {
446         struct torture_suite *child;
447
448         for (child = parent->children; child; child = child->next) 
449                 if (!strcmp(child->name, name))
450                         return child;
451
452         return NULL;
453 }
454
455 static bool wrap_test_with_simple_test(struct torture_context *torture_ctx,
456                                                                         struct torture_tcase *tcase,
457                                                                         struct torture_test *test)
458 {
459         bool (*fn) (struct torture_context *, const void *tcase_data);
460
461         fn = test->fn;
462
463         return fn(torture_ctx, tcase->data);
464 }
465
466 struct torture_test *torture_tcase_add_simple_test(
467                 struct torture_tcase *tcase,
468                 const char *name,
469                 bool (*run) (struct torture_context *test, const void *tcase_data))
470 {
471         struct torture_test *test; 
472         
473         test = talloc(tcase, struct torture_test);
474
475         test->name = talloc_strdup(test, name);
476         test->description = NULL;
477         test->run = wrap_test_with_simple_test;
478         test->fn = run;
479         test->data = NULL;
480         test->dangerous = false;
481
482         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
483
484         return test;
485 }
486
487