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