bd0fb7c2bb3962cac1b2130896f7670f14e92189
[kai/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 success;
228         char *old_testname;
229
230         if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
231                 old_testname = context->active_testname;
232                 context->active_testname = talloc_asprintf(context, "%s-%s", old_testname, test->name);
233         }
234
235         context->active_tcase = tcase;
236         context->active_test = test;
237
238         torture_ui_test_start(context, tcase, test);
239
240         context->last_reason = NULL;
241         context->last_result = TORTURE_OK;
242
243         if (!already_setup && tcase->setup && 
244                 !tcase->setup(context, &(tcase->data))) {
245                 if (context->last_reason == NULL)
246                         context->last_reason = talloc_strdup(context, "Setup failure");
247                 context->last_result = TORTURE_ERROR;
248                 success = false;
249         } else if (test->dangerous && 
250             !torture_setting_bool(context, "dangerous", false)) {
251             context->last_result = TORTURE_SKIP;
252             context->last_reason = talloc_asprintf(context, 
253                 "disabled %s - enable dangerous tests to use", test->name);
254             success = true;
255         } else {
256             success = test->run(context, tcase, test);
257
258             if (!success && context->last_result == TORTURE_OK) {
259                     if (context->last_reason == NULL)
260                             context->last_reason = talloc_strdup(context, "Unknown error/failure");
261                     context->last_result = TORTURE_ERROR;
262             }
263         }
264
265         if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data)) {
266                 if (context->last_reason == NULL)
267                     context->last_reason = talloc_strdup(context, "Setup failure");
268                 context->last_result = TORTURE_ERROR;
269                 success = false;
270         }
271
272         torture_ui_test_result(context, context->last_result, 
273                                context->last_reason);
274         
275         talloc_free(context->last_reason);
276
277         if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
278                 talloc_free(context->active_testname);
279                 context->active_testname = old_testname;
280         }
281         context->active_test = NULL;
282         context->active_tcase = NULL;
283
284         return success;
285 }
286
287 BOOL torture_run_tcase(struct torture_context *context, 
288                                            struct torture_tcase *tcase)
289 {
290         BOOL ret = True;
291         char *old_testname;
292         struct torture_test *test;
293
294         context->level++;
295
296         context->active_tcase = tcase;
297         if (context->ui_ops->tcase_start) 
298                 context->ui_ops->tcase_start(context, tcase);
299
300         if (tcase->fixture_persistent && tcase->setup 
301                 && !tcase->setup(context, &tcase->data)) {
302                 /* FIXME: Use torture ui ops for reporting this error */
303                 fprintf(stderr, "Setup failed: ");
304                 if (context->last_reason != NULL)
305                         fprintf(stderr, "%s", context->last_reason);
306                 fprintf(stderr, "\n");
307                 ret = false;
308                 goto done;
309         }
310
311         old_testname = context->active_testname;
312         context->active_testname = talloc_asprintf(context, "%s-%s", old_testname, tcase->name);
313         for (test = tcase->tests; test; test = test->next) {
314                 ret &= internal_torture_run_test(context, tcase, test, 
315                                 tcase->fixture_persistent);
316         }
317         talloc_free(context->active_testname);
318         context->active_testname = old_testname;
319
320         if (tcase->fixture_persistent && tcase->teardown &&
321                 !tcase->teardown(context, tcase->data))
322                 ret = false;
323
324 done:
325         context->active_tcase = NULL;
326
327         if (context->ui_ops->tcase_finish)
328                 context->ui_ops->tcase_finish(context, tcase);
329
330         context->level--;
331
332         return ret;
333 }
334
335 BOOL torture_run_test(struct torture_context *context, 
336                                           struct torture_tcase *tcase,
337                                           struct torture_test *test)
338 {
339         return internal_torture_run_test(context, tcase, test, false);
340 }
341
342 int torture_setting_int(struct torture_context *test, const char *name, 
343                                                         int default_value)
344 {
345         return lp_parm_int(-1, "torture", name, default_value);
346 }
347
348 double torture_setting_double(struct torture_context *test, const char *name, 
349                                                         double default_value)
350 {
351         return lp_parm_double(-1, "torture", name, default_value);
352 }
353
354 bool torture_setting_bool(struct torture_context *test, const char *name, 
355                                                         bool default_value)
356 {
357         return lp_parm_bool(-1, "torture", name, default_value);
358 }
359
360 const char *torture_setting_string(struct torture_context *test, const char *name, 
361                                                         const char *default_value)
362 {
363         const char *ret = lp_parm_string(-1, "torture", name);
364
365         if (ret == NULL)
366                 return default_value;
367
368         return ret;
369 }
370
371 static bool wrap_test_with_simple_tcase(struct torture_context *torture_ctx,
372                                                                         struct torture_tcase *tcase,
373                                                                         struct torture_test *test)
374 {
375         bool (*fn) (struct torture_context *, const void *tcase_data);
376
377         fn = test->fn;
378
379         return fn(torture_ctx, test->data);
380 }
381
382 struct torture_tcase *torture_suite_add_simple_tcase(
383                                         struct torture_suite *suite, 
384                                         const char *name,
385                                         bool (*run) (struct torture_context *test, const void *),
386                                         const void *data)
387 {
388         struct torture_tcase *tcase;
389         struct torture_test *test; 
390         
391         tcase = torture_suite_add_tcase(suite, name);
392
393         test = talloc(tcase, struct torture_test);
394
395         test->name = talloc_strdup(test, name);
396         test->description = NULL;
397         test->run = wrap_test_with_simple_tcase;
398         test->fn = run;
399         test->data = data;
400         test->dangerous = false;
401
402         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
403
404         return tcase;
405 }
406
407 static bool wrap_simple_test(struct torture_context *torture_ctx,
408                                                                         struct torture_tcase *tcase,
409                                                                         struct torture_test *test)
410 {
411         bool (*fn) (struct torture_context *);
412
413         fn = test->fn;
414
415         return fn(torture_ctx);
416 }
417
418 struct torture_tcase *torture_suite_add_simple_test(
419                                         struct torture_suite *suite, 
420                                         const char *name,
421                                         bool (*run) (struct torture_context *test))
422 {
423         struct torture_test *test; 
424         struct torture_tcase *tcase;
425         
426         tcase = torture_suite_add_tcase(suite, name);
427
428         test = talloc(tcase, struct torture_test);
429
430         test->name = talloc_strdup(test, name);
431         test->description = NULL;
432         test->run = wrap_simple_test;
433         test->fn = run;
434         test->dangerous = false;
435
436         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
437
438         return tcase;
439 }
440
441 bool torture_suite_add_suite(struct torture_suite *suite, 
442                                                          struct torture_suite *child)
443 {
444         if (child == NULL)
445                 return false;
446
447         DLIST_ADD_END(suite->children, child, struct torture_suite *);
448
449         /* FIXME: Check for duplicates and return false if the 
450          * added suite already exists as a child */
451
452         return true;
453 }
454
455
456 struct torture_suite *torture_find_suite(struct torture_suite *parent, 
457                                                                                  const char *name)
458 {
459         struct torture_suite *child;
460
461         for (child = parent->children; child; child = child->next) 
462                 if (!strcmp(child->name, name))
463                         return child;
464
465         return NULL;
466 }
467
468 static bool wrap_test_with_simple_test(struct torture_context *torture_ctx,
469                                                                         struct torture_tcase *tcase,
470                                                                         struct torture_test *test)
471 {
472         bool (*fn) (struct torture_context *, const void *tcase_data);
473
474         fn = test->fn;
475
476         return fn(torture_ctx, tcase->data);
477 }
478
479 struct torture_test *torture_tcase_add_simple_test(
480                 struct torture_tcase *tcase,
481                 const char *name,
482                 bool (*run) (struct torture_context *test, const void *tcase_data))
483 {
484         struct torture_test *test; 
485         
486         test = talloc(tcase, struct torture_test);
487
488         test->name = talloc_strdup(test, name);
489         test->description = NULL;
490         test->run = wrap_test_with_simple_test;
491         test->fn = run;
492         test->data = NULL;
493         test->dangerous = false;
494
495         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
496
497         return test;
498 }
499
500