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