r23792: convert Samba4 to GPLv3
[mdw/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
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 struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite, 
124                                                          const char *name)
125 {
126         struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
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 tcase;
138 }
139
140 BOOL torture_run_suite(struct torture_context *context, 
141                                            struct torture_suite *suite)
142 {
143         BOOL ret = True;
144         struct torture_tcase *tcase;
145         struct torture_suite *tsuite;
146         char *old_testname;
147
148         context->level++;
149         if (context->ui_ops->suite_start)
150                 context->ui_ops->suite_start(context, suite);
151
152         old_testname = context->active_testname;
153         if (old_testname != NULL)
154                 context->active_testname = talloc_asprintf(context, "%s-%s", 
155                                                                                            old_testname, suite->name);
156         else
157                 context->active_testname = talloc_strdup(context, suite->name);
158
159         for (tcase = suite->testcases; tcase; tcase = tcase->next) {
160                 ret &= torture_run_tcase(context, tcase);
161         }
162
163         for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
164                 ret &= torture_run_suite(context, tsuite);
165         }
166
167         talloc_free(context->active_testname);
168         context->active_testname = old_testname;
169
170         if (context->ui_ops->suite_finish)
171                 context->ui_ops->suite_finish(context, suite);
172
173         context->level--;
174         
175         return ret;
176 }
177
178 void torture_ui_test_start(struct torture_context *context,
179                                                            struct torture_tcase *tcase,
180                                                            struct torture_test *test)
181 {
182         if (context->ui_ops->test_start)
183                 context->ui_ops->test_start(context, tcase, test);
184 }
185
186 int str_list_match(const char *name, char **list)
187 {
188         int i, ret = 0;
189         if (list == NULL)
190                 return 0;
191
192         for (i = 0; list[i]; i++) {
193                 if (gen_fnmatch(list[i], name) == 0)
194                         ret++;
195         }
196         return ret;
197 }
198
199 void torture_ui_test_result(struct torture_context *context,
200                                                                 enum torture_result result,
201                                                                 const char *comment)
202 {
203         if (context->ui_ops->test_result)
204                 context->ui_ops->test_result(context, result, comment);
205
206         if (result == TORTURE_ERROR || result == TORTURE_FAIL)
207                 context->returncode = false;
208 }
209
210 static BOOL internal_torture_run_test(struct torture_context *context, 
211                                           struct torture_tcase *tcase,
212                                           struct torture_test *test,
213                                           BOOL already_setup)
214 {
215         BOOL ret;
216         char *old_testname;
217
218         if (test->dangerous && !torture_setting_bool(context, "dangerous", False)) {
219                 torture_result(context, TORTURE_SKIP,
220                                 "disabled %s - enable dangerous tests to use", test->name);
221                 return True;
222         }
223
224         if (!already_setup && tcase->setup && 
225                 !tcase->setup(context, &(tcase->data)))
226                 return False;
227
228         if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
229                 old_testname = context->active_testname;
230                 context->active_testname = talloc_asprintf(context, "%s-%s", 
231                                                                                            old_testname, test->name);
232         }
233         context->active_tcase = tcase;
234         context->active_test = test;
235
236         torture_ui_test_start(context, tcase, test);
237
238
239         context->last_reason = NULL;
240         context->last_result = TORTURE_OK;
241
242         ret = test->run(context, tcase, test);
243         if (!ret && context->last_result == TORTURE_OK) {
244                 if (context->last_reason == NULL)
245                         context->last_reason = talloc_strdup(context, "Unknown error/failure");
246                 context->last_result = TORTURE_ERROR;
247         }
248
249         torture_ui_test_result(context, context->last_result, context->last_reason);
250         
251         talloc_free(context->last_reason);
252
253         if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
254                 talloc_free(context->active_testname);
255                 context->active_testname = old_testname;
256         }
257         context->active_test = NULL;
258         context->active_tcase = NULL;
259
260         if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data))
261                 return False;
262
263         return ret;
264 }
265
266 BOOL torture_run_tcase(struct torture_context *context, 
267                                            struct torture_tcase *tcase)
268 {
269         BOOL ret = True;
270         char *old_testname;
271         struct torture_test *test;
272
273         context->level++;
274
275         context->active_tcase = tcase;
276         if (context->ui_ops->tcase_start)
277                 context->ui_ops->tcase_start(context, tcase);
278
279         if (tcase->fixture_persistent && tcase->setup 
280                 && !tcase->setup(context, &tcase->data)) {
281                 ret = False;
282                 goto done;
283         }
284
285         old_testname = context->active_testname;
286         context->active_testname = talloc_asprintf(context, "%s-%s", 
287                                                                                            old_testname, tcase->name);
288         for (test = tcase->tests; test; test = test->next) {
289                 ret &= internal_torture_run_test(context, tcase, test, 
290                                 tcase->fixture_persistent);
291         }
292         talloc_free(context->active_testname);
293         context->active_testname = old_testname;
294
295         if (tcase->fixture_persistent && tcase->teardown &&
296                 !tcase->teardown(context, tcase->data))
297                 ret = False;
298
299 done:
300         context->active_tcase = NULL;
301
302         if (context->ui_ops->tcase_finish)
303                 context->ui_ops->tcase_finish(context, tcase);
304
305         context->level--;
306
307         return ret;
308 }
309
310 BOOL torture_run_test(struct torture_context *context, 
311                                           struct torture_tcase *tcase,
312                                           struct torture_test *test)
313 {
314         return internal_torture_run_test(context, tcase, test, False);
315 }
316
317 int torture_setting_int(struct torture_context *test, const char *name, 
318                                                         int default_value)
319 {
320         return lp_parm_int(-1, "torture", name, default_value);
321 }
322
323 bool torture_setting_bool(struct torture_context *test, const char *name, 
324                                                         bool default_value)
325 {
326         return lp_parm_bool(-1, "torture", name, default_value);
327 }
328
329 const char *torture_setting_string(struct torture_context *test, const char *name, 
330                                                         const char *default_value)
331 {
332         const char *ret = lp_parm_string(-1, "torture", name);
333
334         if (ret == NULL)
335                 return default_value;
336
337         return ret;
338 }
339
340 static bool wrap_test_with_simple_tcase(struct torture_context *torture_ctx,
341                                                                         struct torture_tcase *tcase,
342                                                                         struct torture_test *test)
343 {
344         bool (*fn) (struct torture_context *, const void *tcase_data);
345
346         fn = test->fn;
347
348         return fn(torture_ctx, test->data);
349 }
350
351 struct torture_tcase *torture_suite_add_simple_tcase(
352                                         struct torture_suite *suite, 
353                                         const char *name,
354                                         bool (*run) (struct torture_context *test, const void *),
355                                         const void *data)
356 {
357         struct torture_tcase *tcase;
358         struct torture_test *test; 
359         
360         tcase = torture_suite_add_tcase(suite, name);
361
362         test = talloc(tcase, struct torture_test);
363
364         test->name = talloc_strdup(test, name);
365         test->description = NULL;
366         test->run = wrap_test_with_simple_tcase;
367         test->fn = run;
368         test->data = data;
369         test->dangerous = False;
370
371         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
372
373         return tcase;
374 }
375
376 static bool wrap_simple_test(struct torture_context *torture_ctx,
377                                                                         struct torture_tcase *tcase,
378                                                                         struct torture_test *test)
379 {
380         bool (*fn) (struct torture_context *);
381
382         fn = test->fn;
383
384         return fn(torture_ctx);
385 }
386
387 struct torture_tcase *torture_suite_add_simple_test(
388                                         struct torture_suite *suite, 
389                                         const char *name,
390                                         bool (*run) (struct torture_context *test))
391 {
392         struct torture_test *test; 
393         struct torture_tcase *tcase;
394         
395         tcase = torture_suite_add_tcase(suite, name);
396
397         test = talloc(tcase, struct torture_test);
398
399         test->name = talloc_strdup(test, name);
400         test->description = NULL;
401         test->run = wrap_simple_test;
402         test->fn = run;
403         test->dangerous = false;
404
405         DLIST_ADD_END(tcase->tests, test, struct torture_test *);
406
407         return tcase;
408 }
409
410 bool torture_suite_add_suite(struct torture_suite *suite, 
411                                                          struct torture_suite *child)
412 {
413         if (child == NULL)
414                 return false;
415
416         DLIST_ADD_END(suite->children, child, struct torture_suite *);
417
418         /* FIXME: Check for duplicates and return false if the 
419          * added suite already exists as a child */
420
421         return true;
422 }
423
424
425 struct torture_suite *torture_find_suite(struct torture_suite *parent, 
426                                                                                  const char *name)
427 {
428         struct torture_suite *child;
429
430         for (child = parent->children; child; child = child->next) 
431                 if (!strcmp(child->name, name))
432                         return child;
433
434         return NULL;
435 }