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