2 Unix SMB/CIFS implementation.
3 SMB torture UI functions
5 Copyright (C) Jelmer Vernooij 2006-2008
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.
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.
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/>.
21 #include "source4/include/includes.h"
22 #include "../torture/torture.h"
23 #include "../lib/util/dlinklist.h"
24 #include "param/param.h"
25 #include "system/filesys.h"
27 struct torture_results
*torture_results_init(TALLOC_CTX
*mem_ctx
, const struct torture_ui_ops
*ui_ops
)
29 struct torture_results
*results
= talloc_zero(mem_ctx
, struct torture_results
);
31 results
->ui_ops
= ui_ops
;
32 results
->returncode
= true;
35 ui_ops
->init(results
);
41 * Initialize a torture context
43 struct torture_context
*torture_context_init(struct tevent_context
*event_ctx
,
44 struct torture_results
*results
)
46 struct torture_context
*torture
= talloc_zero(event_ctx
,
47 struct torture_context
);
52 torture
->ev
= event_ctx
;
53 torture
->results
= talloc_reference(torture
, results
);
59 * Create a sub torture context
61 struct torture_context
*torture_context_child(struct torture_context
*parent
)
63 struct torture_context
*subtorture
= talloc_zero(parent
, struct torture_context
);
65 if (subtorture
== NULL
)
68 subtorture
->ev
= talloc_reference(subtorture
, parent
->ev
);
69 subtorture
->lp_ctx
= talloc_reference(subtorture
, parent
->lp_ctx
);
70 subtorture
->outputdir
= talloc_reference(subtorture
, parent
->outputdir
);
71 subtorture
->results
= talloc_reference(subtorture
, parent
->results
);
77 create a temporary directory.
79 _PUBLIC_ NTSTATUS
torture_temp_dir(struct torture_context
*tctx
,
83 SMB_ASSERT(tctx
->outputdir
!= NULL
);
85 *tempdir
= talloc_asprintf(tctx
, "%s/%s.XXXXXX", tctx
->outputdir
,
87 NT_STATUS_HAVE_NO_MEMORY(*tempdir
);
89 if (mkdtemp(*tempdir
) == NULL
) {
90 return map_nt_error_from_unix(errno
);
97 * Comment on the status/progress of a test
99 void torture_comment(struct torture_context
*context
, const char *comment
, ...)
104 if (!context
->results
->ui_ops
->comment
)
107 va_start(ap
, comment
);
108 tmp
= talloc_vasprintf(context
, comment
, ap
);
111 context
->results
->ui_ops
->comment(context
, tmp
);
117 * Print a warning about the current test
119 void torture_warning(struct torture_context
*context
, const char *comment
, ...)
124 if (!context
->results
->ui_ops
->warning
)
127 va_start(ap
, comment
);
128 tmp
= talloc_vasprintf(context
, comment
, ap
);
131 context
->results
->ui_ops
->warning(context
, tmp
);
137 * Store the result of a torture test.
139 void torture_result(struct torture_context
*context
,
140 enum torture_result result
, const char *fmt
, ...)
146 if (context
->last_reason
) {
147 torture_warning(context
, "%s", context
->last_reason
);
148 talloc_free(context
->last_reason
);
151 context
->last_result
= result
;
152 context
->last_reason
= talloc_vasprintf(context
, fmt
, ap
);
157 * Create a new torture suite
159 struct torture_suite
*torture_suite_create(TALLOC_CTX
*ctx
, const char *name
)
161 struct torture_suite
*suite
= talloc_zero(ctx
, struct torture_suite
);
163 suite
->name
= talloc_strdup(suite
, name
);
164 suite
->testcases
= NULL
;
165 suite
->children
= NULL
;
171 * Set the setup() and teardown() functions for a testcase.
173 void torture_tcase_set_fixture(struct torture_tcase
*tcase
,
174 bool (*setup
) (struct torture_context
*, void **),
175 bool (*teardown
) (struct torture_context
*, void *))
177 tcase
->setup
= setup
;
178 tcase
->teardown
= teardown
;
181 static bool wrap_test_with_testcase_const(struct torture_context
*torture_ctx
,
182 struct torture_tcase
*tcase
,
183 struct torture_test
*test
)
185 bool (*fn
) (struct torture_context
*,
186 const void *tcase_data
,
187 const void *test_data
);
191 return fn(torture_ctx
, tcase
->data
, test
->data
);
195 * Add a test that uses const data to a testcase
197 struct torture_test
*torture_tcase_add_test_const(struct torture_tcase
*tcase
,
199 bool (*run
) (struct torture_context
*, const void *tcase_data
,
200 const void *test_data
),
203 struct torture_test
*test
= talloc(tcase
, struct torture_test
);
205 test
->name
= talloc_strdup(test
, name
);
206 test
->description
= NULL
;
207 test
->run
= wrap_test_with_testcase_const
;
209 test
->dangerous
= false;
212 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
220 bool torture_suite_init_tcase(struct torture_suite
*suite
,
221 struct torture_tcase
*tcase
,
224 tcase
->name
= talloc_strdup(tcase
, name
);
225 tcase
->description
= NULL
;
227 tcase
->teardown
= NULL
;
228 tcase
->fixture_persistent
= true;
231 DLIST_ADD_END(suite
->testcases
, tcase
, struct torture_tcase
*);
237 struct torture_tcase
*torture_suite_add_tcase(struct torture_suite
*suite
,
240 struct torture_tcase
*tcase
= talloc(suite
, struct torture_tcase
);
242 if (!torture_suite_init_tcase(suite
, tcase
, name
))
248 int torture_suite_children_count(const struct torture_suite
*suite
)
251 struct torture_tcase
*tcase
;
252 struct torture_test
*test
;
253 struct torture_suite
*tsuite
;
254 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
255 for (test
= tcase
->tests
; test
; test
= test
->next
) {
259 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
266 * Run a torture test suite.
268 bool torture_run_suite(struct torture_context
*context
,
269 struct torture_suite
*suite
)
272 struct torture_tcase
*tcase
;
273 struct torture_suite
*tsuite
;
276 if (context
->results
->ui_ops
->suite_start
)
277 context
->results
->ui_ops
->suite_start(context
, suite
);
279 context
->results
->ui_ops
->progress(context
,
280 torture_suite_children_count(suite
), TORTURE_PROGRESS_SET
);
281 old_testname
= context
->active_testname
;
282 if (old_testname
!= NULL
)
283 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
284 old_testname
, suite
->name
);
286 context
->active_testname
= talloc_strdup(context
, suite
->name
);
288 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
289 ret
&= torture_run_tcase(context
, tcase
);
292 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
293 context
->results
->ui_ops
->progress(context
, 0, TORTURE_PROGRESS_PUSH
);
294 ret
&= torture_run_suite(context
, tsuite
);
295 context
->results
->ui_ops
->progress(context
, 0, TORTURE_PROGRESS_POP
);
298 talloc_free(context
->active_testname
);
299 context
->active_testname
= old_testname
;
301 if (context
->results
->ui_ops
->suite_finish
)
302 context
->results
->ui_ops
->suite_finish(context
, suite
);
307 bool torture_run_suite_restricted(struct torture_context
*context
,
308 struct torture_suite
*suite
, const char **restricted
)
314 void torture_ui_test_start(struct torture_context
*context
,
315 struct torture_tcase
*tcase
,
316 struct torture_test
*test
)
318 if (context
->results
->ui_ops
->test_start
)
319 context
->results
->ui_ops
->test_start(context
, tcase
, test
);
322 void torture_ui_test_result(struct torture_context
*context
,
323 enum torture_result result
,
326 if (context
->results
->ui_ops
->test_result
)
327 context
->results
->ui_ops
->test_result(context
, result
, comment
);
329 if (result
== TORTURE_ERROR
|| result
== TORTURE_FAIL
)
330 context
->results
->returncode
= false;
333 static bool internal_torture_run_test(struct torture_context
*context
,
334 struct torture_tcase
*tcase
,
335 struct torture_test
*test
,
339 char *old_testname
= NULL
;
341 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
342 old_testname
= context
->active_testname
;
343 context
->active_testname
= talloc_asprintf(context
, "%s-%s", old_testname
, test
->name
);
346 context
->active_tcase
= tcase
;
347 context
->active_test
= test
;
349 torture_ui_test_start(context
, tcase
, test
);
351 context
->last_reason
= NULL
;
352 context
->last_result
= TORTURE_OK
;
354 if (!already_setup
&& tcase
->setup
&&
355 !tcase
->setup(context
, &(tcase
->data
))) {
356 if (context
->last_reason
== NULL
)
357 context
->last_reason
= talloc_strdup(context
, "Setup failure");
358 context
->last_result
= TORTURE_ERROR
;
360 } else if (test
->dangerous
&&
361 !torture_setting_bool(context
, "dangerous", false)) {
362 context
->last_result
= TORTURE_SKIP
;
363 context
->last_reason
= talloc_asprintf(context
,
364 "disabled %s - enable dangerous tests to use", test
->name
);
367 success
= test
->run(context
, tcase
, test
);
369 if (!success
&& context
->last_result
== TORTURE_OK
) {
370 if (context
->last_reason
== NULL
)
371 context
->last_reason
= talloc_strdup(context
, "Unknown error/failure");
372 context
->last_result
= TORTURE_ERROR
;
376 if (!already_setup
&& tcase
->teardown
&& !tcase
->teardown(context
, tcase
->data
)) {
377 if (context
->last_reason
== NULL
)
378 context
->last_reason
= talloc_strdup(context
, "Setup failure");
379 context
->last_result
= TORTURE_ERROR
;
383 torture_ui_test_result(context
, context
->last_result
,
384 context
->last_reason
);
386 talloc_free(context
->last_reason
);
388 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
389 talloc_free(context
->active_testname
);
390 context
->active_testname
= old_testname
;
392 context
->active_test
= NULL
;
393 context
->active_tcase
= NULL
;
398 bool torture_run_tcase(struct torture_context
*context
,
399 struct torture_tcase
*tcase
)
403 struct torture_test
*test
;
405 context
->active_tcase
= tcase
;
406 if (context
->results
->ui_ops
->tcase_start
)
407 context
->results
->ui_ops
->tcase_start(context
, tcase
);
409 if (tcase
->fixture_persistent
&& tcase
->setup
410 && !tcase
->setup(context
, &tcase
->data
)) {
411 /* FIXME: Use torture ui ops for reporting this error */
412 fprintf(stderr
, "Setup failed: ");
413 if (context
->last_reason
!= NULL
)
414 fprintf(stderr
, "%s", context
->last_reason
);
415 fprintf(stderr
, "\n");
420 old_testname
= context
->active_testname
;
421 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
422 old_testname
, tcase
->name
);
423 for (test
= tcase
->tests
; test
; test
= test
->next
) {
424 ret
&= internal_torture_run_test(context
, tcase
, test
,
425 tcase
->fixture_persistent
);
427 talloc_free(context
->active_testname
);
428 context
->active_testname
= old_testname
;
430 if (tcase
->fixture_persistent
&& tcase
->teardown
&&
431 !tcase
->teardown(context
, tcase
->data
))
435 context
->active_tcase
= NULL
;
437 if (context
->results
->ui_ops
->tcase_finish
)
438 context
->results
->ui_ops
->tcase_finish(context
, tcase
);
443 bool torture_run_test(struct torture_context
*context
,
444 struct torture_tcase
*tcase
,
445 struct torture_test
*test
)
447 return internal_torture_run_test(context
, tcase
, test
, false);
450 int torture_setting_int(struct torture_context
*test
, const char *name
,
453 return lp_parm_int(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
456 unsigned long torture_setting_ulong(struct torture_context
*test
,
458 unsigned long default_value
)
460 return lp_parm_ulong(test
->lp_ctx
, NULL
, "torture", name
,
464 double torture_setting_double(struct torture_context
*test
, const char *name
,
465 double default_value
)
467 return lp_parm_double(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
470 bool torture_setting_bool(struct torture_context
*test
, const char *name
,
473 return lp_parm_bool(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
476 const char *torture_setting_string(struct torture_context
*test
,
478 const char *default_value
)
482 SMB_ASSERT(test
!= NULL
);
483 SMB_ASSERT(test
->lp_ctx
!= NULL
);
485 ret
= lp_parm_string(test
->lp_ctx
, NULL
, "torture", name
);
488 return default_value
;
493 static bool wrap_test_with_simple_tcase_const (
494 struct torture_context
*torture_ctx
,
495 struct torture_tcase
*tcase
,
496 struct torture_test
*test
)
498 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
502 return fn(torture_ctx
, test
->data
);
505 struct torture_tcase
*torture_suite_add_simple_tcase_const(
506 struct torture_suite
*suite
, const char *name
,
507 bool (*run
) (struct torture_context
*test
, const void *),
510 struct torture_tcase
*tcase
;
511 struct torture_test
*test
;
513 tcase
= torture_suite_add_tcase(suite
, name
);
515 test
= talloc(tcase
, struct torture_test
);
517 test
->name
= talloc_strdup(test
, name
);
518 test
->description
= NULL
;
519 test
->run
= wrap_test_with_simple_tcase_const
;
522 test
->dangerous
= false;
524 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
529 static bool wrap_simple_test(struct torture_context
*torture_ctx
,
530 struct torture_tcase
*tcase
,
531 struct torture_test
*test
)
533 bool (*fn
) (struct torture_context
*);
537 return fn(torture_ctx
);
540 struct torture_tcase
*torture_suite_add_simple_test(
541 struct torture_suite
*suite
,
543 bool (*run
) (struct torture_context
*test
))
545 struct torture_test
*test
;
546 struct torture_tcase
*tcase
;
548 tcase
= torture_suite_add_tcase(suite
, name
);
550 test
= talloc(tcase
, struct torture_test
);
552 test
->name
= talloc_strdup(test
, name
);
553 test
->description
= NULL
;
554 test
->run
= wrap_simple_test
;
556 test
->dangerous
= false;
558 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
564 * Add a child testsuite to a testsuite.
566 bool torture_suite_add_suite(struct torture_suite
*suite
,
567 struct torture_suite
*child
)
572 DLIST_ADD_END(suite
->children
, child
, struct torture_suite
*);
574 /* FIXME: Check for duplicates and return false if the
575 * added suite already exists as a child */
581 * Find the child testsuite with the specified name.
583 struct torture_suite
*torture_find_suite(struct torture_suite
*parent
,
586 struct torture_suite
*child
;
588 for (child
= parent
->children
; child
; child
= child
->next
)
589 if (!strcmp(child
->name
, name
))
595 static bool wrap_test_with_simple_test_const(struct torture_context
*torture_ctx
,
596 struct torture_tcase
*tcase
,
597 struct torture_test
*test
)
599 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
603 return fn(torture_ctx
, tcase
->data
);
606 struct torture_test
*torture_tcase_add_simple_test_const(
607 struct torture_tcase
*tcase
,
609 bool (*run
) (struct torture_context
*test
,
610 const void *tcase_data
))
612 struct torture_test
*test
;
614 test
= talloc(tcase
, struct torture_test
);
616 test
->name
= talloc_strdup(test
, name
);
617 test
->description
= NULL
;
618 test
->run
= wrap_test_with_simple_test_const
;
621 test
->dangerous
= false;
623 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
628 static bool wrap_test_with_simple_test(struct torture_context
*torture_ctx
,
629 struct torture_tcase
*tcase
,
630 struct torture_test
*test
)
632 bool (*fn
) (struct torture_context
*, void *tcase_data
);
636 return fn(torture_ctx
, tcase
->data
);
639 struct torture_test
*torture_tcase_add_simple_test(struct torture_tcase
*tcase
,
641 bool (*run
) (struct torture_context
*test
, void *tcase_data
))
643 struct torture_test
*test
;
645 test
= talloc(tcase
, struct torture_test
);
647 test
->name
= talloc_strdup(test
, name
);
648 test
->description
= NULL
;
649 test
->run
= wrap_test_with_simple_test
;
652 test
->dangerous
= false;
654 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);