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