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"
26 #include "system/dir.h"
29 struct torture_results
*torture_results_init(TALLOC_CTX
*mem_ctx
, const struct torture_ui_ops
*ui_ops
)
31 struct torture_results
*results
= talloc_zero(mem_ctx
, struct torture_results
);
33 results
->ui_ops
= ui_ops
;
34 results
->returncode
= true;
37 ui_ops
->init(results
);
43 * Initialize a torture context
45 struct torture_context
*torture_context_init(struct tevent_context
*event_ctx
,
46 struct torture_results
*results
)
48 struct torture_context
*torture
= talloc_zero(event_ctx
,
49 struct torture_context
);
54 torture
->ev
= event_ctx
;
55 torture
->results
= talloc_reference(torture
, results
);
58 * We start with an empty subunit prefix
60 torture_subunit_prefix_reset(torture
, NULL
);
66 * Create a sub torture context
68 struct torture_context
*torture_context_child(struct torture_context
*parent
)
70 struct torture_context
*subtorture
= talloc_zero(parent
, struct torture_context
);
72 if (subtorture
== NULL
)
75 subtorture
->ev
= talloc_reference(subtorture
, parent
->ev
);
76 subtorture
->lp_ctx
= talloc_reference(subtorture
, parent
->lp_ctx
);
77 subtorture
->outputdir
= talloc_reference(subtorture
, parent
->outputdir
);
78 subtorture
->results
= talloc_reference(subtorture
, parent
->results
);
84 create a temporary directory under the output dir
86 _PUBLIC_ NTSTATUS
torture_temp_dir(struct torture_context
*tctx
,
87 const char *prefix
, char **tempdir
)
89 SMB_ASSERT(tctx
->outputdir
!= NULL
);
91 *tempdir
= talloc_asprintf(tctx
, "%s/%s.XXXXXX", tctx
->outputdir
,
93 NT_STATUS_HAVE_NO_MEMORY(*tempdir
);
95 if (mkdtemp(*tempdir
) == NULL
) {
96 return map_nt_error_from_unix_common(errno
);
102 static int local_deltree(const char *path
)
105 struct dirent
*dirent
;
106 DIR *dir
= opendir(path
);
108 char *error
= talloc_asprintf(NULL
, "Could not open directory %s", path
);
113 while ((dirent
= readdir(dir
))) {
115 if ((strcmp(dirent
->d_name
, ".") == 0) || (strcmp(dirent
->d_name
, "..") == 0)) {
118 name
= talloc_asprintf(NULL
, "%s/%s", path
,
124 DEBUG(0, ("About to remove %s\n", name
));
131 if (errno
== ENOTEMPTY
) {
132 ret
= local_deltree(name
);
139 char *error
= talloc_asprintf(NULL
, "Could not remove %s", path
);
150 _PUBLIC_ NTSTATUS
torture_deltree_outputdir(struct torture_context
*tctx
)
152 if (tctx
->outputdir
== NULL
) {
155 if ((strcmp(tctx
->outputdir
, "/") == 0)
156 || (strcmp(tctx
->outputdir
, "") == 0)) {
157 return NT_STATUS_INVALID_PARAMETER
;
160 if (local_deltree(tctx
->outputdir
) == -1) {
162 return map_nt_error_from_unix_common(errno
);
164 return NT_STATUS_UNSUCCESSFUL
;
170 * Comment on the status/progress of a test
172 void torture_comment(struct torture_context
*context
, const char *comment
, ...)
177 if (!context
->results
->ui_ops
->comment
)
180 va_start(ap
, comment
);
181 tmp
= talloc_vasprintf(context
, comment
, ap
);
184 context
->results
->ui_ops
->comment(context
, tmp
);
190 * Print a warning about the current test
192 void torture_warning(struct torture_context
*context
, const char *comment
, ...)
197 if (!context
->results
->ui_ops
->warning
)
200 va_start(ap
, comment
);
201 tmp
= talloc_vasprintf(context
, comment
, ap
);
204 context
->results
->ui_ops
->warning(context
, tmp
);
210 * Store the result of a torture test.
212 void torture_result(struct torture_context
*context
,
213 enum torture_result result
, const char *fmt
, ...)
215 /* Of the two outcomes, keep that with the higher priority. */
216 if (result
>= context
->last_result
) {
221 if (context
->last_reason
) {
222 torture_warning(context
, "%s", context
->last_reason
);
223 talloc_free(context
->last_reason
);
226 context
->last_result
= result
;
227 context
->last_reason
= talloc_vasprintf(context
, fmt
, ap
);
234 * Create a new torture suite
236 struct torture_suite
*torture_suite_create(TALLOC_CTX
*ctx
, const char *name
)
238 struct torture_suite
*suite
= talloc_zero(ctx
, struct torture_suite
);
240 suite
->name
= talloc_strdup(suite
, name
);
241 suite
->testcases
= NULL
;
242 suite
->children
= NULL
;
248 * Set the setup() and teardown() functions for a testcase.
250 void torture_tcase_set_fixture(struct torture_tcase
*tcase
,
251 bool (*setup
) (struct torture_context
*, void **),
252 bool (*teardown
) (struct torture_context
*, void *))
254 tcase
->setup
= setup
;
255 tcase
->teardown
= teardown
;
258 static bool wrap_test_with_testcase_const(struct torture_context
*torture_ctx
,
259 struct torture_tcase
*tcase
,
260 struct torture_test
*test
)
262 bool (*fn
) (struct torture_context
*,
263 const void *tcase_data
,
264 const void *test_data
);
268 return fn(torture_ctx
, tcase
->data
, test
->data
);
272 * Add a test that uses const data to a testcase
274 struct torture_test
*torture_tcase_add_test_const(struct torture_tcase
*tcase
,
276 bool (*run
) (struct torture_context
*, const void *tcase_data
,
277 const void *test_data
),
280 struct torture_test
*test
= talloc(tcase
, struct torture_test
);
282 test
->name
= talloc_strdup(test
, name
);
283 test
->description
= NULL
;
284 test
->run
= wrap_test_with_testcase_const
;
286 test
->dangerous
= false;
289 DLIST_ADD_END(tcase
->tests
, test
);
297 bool torture_suite_init_tcase(struct torture_suite
*suite
,
298 struct torture_tcase
*tcase
,
301 tcase
->name
= talloc_strdup(tcase
, name
);
302 tcase
->description
= NULL
;
304 tcase
->teardown
= NULL
;
305 tcase
->fixture_persistent
= true;
308 DLIST_ADD_END(suite
->testcases
, tcase
);
309 tcase
->suite
= suite
;
315 struct torture_tcase
*torture_suite_add_tcase(struct torture_suite
*suite
,
318 struct torture_tcase
*tcase
= talloc(suite
, struct torture_tcase
);
320 if (!torture_suite_init_tcase(suite
, tcase
, name
))
326 char *torture_subunit_test_name(struct torture_context
*ctx
,
327 struct torture_tcase
*tcase
,
328 struct torture_test
*test
)
330 if (!strcmp(tcase
->name
, test
->name
)) {
331 return talloc_asprintf(ctx
, "%s%s",
332 ctx
->active_prefix
->subunit_prefix
,
335 return talloc_asprintf(ctx
, "%s%s.%s",
336 ctx
->active_prefix
->subunit_prefix
,
337 tcase
->name
, test
->name
);
341 void torture_subunit_prefix_reset(struct torture_context
*ctx
,
344 struct torture_subunit_prefix
*prefix
= &ctx
->_initial_prefix
;
346 ZERO_STRUCTP(prefix
);
351 ret
= snprintf(prefix
->subunit_prefix
,
352 sizeof(prefix
->subunit_prefix
),
359 ctx
->active_prefix
= prefix
;
362 static void torture_subunit_prefix_push(struct torture_context
*ctx
,
363 struct torture_subunit_prefix
*prefix
,
366 *prefix
= (struct torture_subunit_prefix
) {
367 .parent
= ctx
->active_prefix
,
370 if (ctx
->active_prefix
->parent
!= NULL
||
371 ctx
->active_prefix
->subunit_prefix
[0] != '\0') {
373 * We need a new component for the prefix.
377 ret
= snprintf(prefix
->subunit_prefix
,
378 sizeof(prefix
->subunit_prefix
),
380 ctx
->active_prefix
->subunit_prefix
,
387 ctx
->active_prefix
= prefix
;
390 static void torture_subunit_prefix_pop(struct torture_context
*ctx
)
392 ctx
->active_prefix
= ctx
->active_prefix
->parent
;
395 int torture_suite_children_count(const struct torture_suite
*suite
)
398 struct torture_tcase
*tcase
;
399 struct torture_test
*test
;
400 struct torture_suite
*tsuite
;
401 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
402 for (test
= tcase
->tests
; test
; test
= test
->next
) {
406 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
413 * Run a torture test suite.
415 bool torture_run_suite(struct torture_context
*context
,
416 struct torture_suite
*suite
)
418 return torture_run_suite_restricted(context
, suite
, NULL
);
421 bool torture_run_suite_restricted(struct torture_context
*context
,
422 struct torture_suite
*suite
, const char **restricted
)
424 struct torture_subunit_prefix _prefix_stack
;
426 struct torture_tcase
*tcase
;
427 struct torture_suite
*tsuite
;
429 torture_subunit_prefix_push(context
, &_prefix_stack
, suite
->name
);
431 if (context
->results
->ui_ops
->suite_start
)
432 context
->results
->ui_ops
->suite_start(context
, suite
);
434 /* FIXME: Adjust torture_suite_children_count if restricted != NULL */
435 context
->results
->ui_ops
->progress(context
,
436 torture_suite_children_count(suite
), TORTURE_PROGRESS_SET
);
438 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
439 ret
&= torture_run_tcase_restricted(context
, tcase
, restricted
);
442 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
443 context
->results
->ui_ops
->progress(context
, 0, TORTURE_PROGRESS_PUSH
);
444 ret
&= torture_run_suite_restricted(context
, tsuite
, restricted
);
445 context
->results
->ui_ops
->progress(context
, 0, TORTURE_PROGRESS_POP
);
448 if (context
->results
->ui_ops
->suite_finish
)
449 context
->results
->ui_ops
->suite_finish(context
, suite
);
451 torture_subunit_prefix_pop(context
);
456 void torture_ui_test_start(struct torture_context
*context
,
457 struct torture_tcase
*tcase
,
458 struct torture_test
*test
)
460 if (context
->results
->ui_ops
->test_start
)
461 context
->results
->ui_ops
->test_start(context
, tcase
, test
);
464 void torture_ui_test_result(struct torture_context
*context
,
465 enum torture_result result
,
468 if (context
->results
->ui_ops
->test_result
)
469 context
->results
->ui_ops
->test_result(context
, result
, comment
);
471 if (result
== TORTURE_ERROR
|| result
== TORTURE_FAIL
)
472 context
->results
->returncode
= false;
475 static bool test_needs_running(const char *name
, const char **restricted
)
478 if (restricted
== NULL
)
480 for (i
= 0; restricted
[i
]; i
++) {
481 if (!strcmp(name
, restricted
[i
]))
487 static bool internal_torture_run_test(struct torture_context
*context
,
488 struct torture_tcase
*tcase
,
489 struct torture_test
*test
,
491 const char **restricted
)
494 char *subunit_testname
= torture_subunit_test_name(context
, tcase
, test
);
496 if (!test_needs_running(subunit_testname
, restricted
))
499 context
->active_tcase
= tcase
;
500 context
->active_test
= test
;
502 torture_ui_test_start(context
, tcase
, test
);
504 context
->last_reason
= NULL
;
505 context
->last_result
= TORTURE_OK
;
507 if (!already_setup
&& tcase
->setup
&&
508 !tcase
->setup(context
, &(tcase
->data
))) {
509 if (context
->last_reason
== NULL
)
510 context
->last_reason
= talloc_strdup(context
, "Setup failure");
511 context
->last_result
= TORTURE_ERROR
;
513 } else if (test
->dangerous
&&
514 !torture_setting_bool(context
, "dangerous", false)) {
515 context
->last_result
= TORTURE_SKIP
;
516 context
->last_reason
= talloc_asprintf(context
,
517 "disabled %s - enable dangerous tests to use", test
->name
);
520 success
= test
->run(context
, tcase
, test
);
522 if (!success
&& context
->last_result
== TORTURE_OK
) {
523 if (context
->last_reason
== NULL
)
524 context
->last_reason
= talloc_strdup(context
,
525 "Unknown error/failure. Missing torture_fail() or torture_assert_*() call?");
526 context
->last_result
= TORTURE_ERROR
;
530 if (!already_setup
&& tcase
->teardown
&& !tcase
->teardown(context
, tcase
->data
)) {
531 if (context
->last_reason
== NULL
)
532 context
->last_reason
= talloc_strdup(context
, "Setup failure");
533 context
->last_result
= TORTURE_ERROR
;
537 torture_ui_test_result(context
, context
->last_result
,
538 context
->last_reason
);
540 talloc_free(context
->last_reason
);
541 context
->last_reason
= NULL
;
543 context
->active_test
= NULL
;
544 context
->active_tcase
= NULL
;
549 bool torture_run_tcase(struct torture_context
*context
,
550 struct torture_tcase
*tcase
)
552 return torture_run_tcase_restricted(context
, tcase
, NULL
);
555 bool torture_run_tcase_restricted(struct torture_context
*context
,
556 struct torture_tcase
*tcase
, const char **restricted
)
559 struct torture_test
*test
;
560 bool setup_succeeded
= true;
561 const char * setup_reason
= "Setup failed";
563 context
->active_tcase
= tcase
;
564 if (context
->results
->ui_ops
->tcase_start
)
565 context
->results
->ui_ops
->tcase_start(context
, tcase
);
567 if (tcase
->fixture_persistent
&& tcase
->setup
) {
568 setup_succeeded
= tcase
->setup(context
, &tcase
->data
);
571 if (!setup_succeeded
) {
572 /* Uh-oh. The setup failed, so we can't run any of the tests
573 * in this testcase. The subunit format doesn't specify what
574 * to do here, so we keep the failure reason, and manually
575 * use it to fail every test.
577 if (context
->last_reason
!= NULL
) {
578 setup_reason
= talloc_asprintf(context
,
579 "Setup failed: %s", context
->last_reason
);
583 for (test
= tcase
->tests
; test
; test
= test
->next
) {
584 if (setup_succeeded
) {
585 ret
&= internal_torture_run_test(context
, tcase
, test
,
586 tcase
->fixture_persistent
, restricted
);
588 context
->active_tcase
= tcase
;
589 context
->active_test
= test
;
590 torture_ui_test_start(context
, tcase
, test
);
591 torture_ui_test_result(context
, TORTURE_FAIL
, setup_reason
);
595 if (setup_succeeded
&& tcase
->fixture_persistent
&& tcase
->teardown
&&
596 !tcase
->teardown(context
, tcase
->data
)) {
600 context
->active_tcase
= NULL
;
601 context
->active_test
= NULL
;
603 if (context
->results
->ui_ops
->tcase_finish
)
604 context
->results
->ui_ops
->tcase_finish(context
, tcase
);
606 return (!setup_succeeded
) ? false : ret
;
609 bool torture_run_test(struct torture_context
*context
,
610 struct torture_tcase
*tcase
,
611 struct torture_test
*test
)
613 return internal_torture_run_test(context
, tcase
, test
, false, NULL
);
616 bool torture_run_test_restricted(struct torture_context
*context
,
617 struct torture_tcase
*tcase
,
618 struct torture_test
*test
,
619 const char **restricted
)
621 return internal_torture_run_test(context
, tcase
, test
, false, restricted
);
624 int torture_setting_int(struct torture_context
*test
, const char *name
,
627 return lpcfg_parm_int(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
630 unsigned long torture_setting_ulong(struct torture_context
*test
,
632 unsigned long default_value
)
634 return lpcfg_parm_ulong(test
->lp_ctx
, NULL
, "torture", name
,
638 double torture_setting_double(struct torture_context
*test
, const char *name
,
639 double default_value
)
641 return lpcfg_parm_double(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
644 bool torture_setting_bool(struct torture_context
*test
, const char *name
,
647 return lpcfg_parm_bool(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
650 const char *torture_setting_string(struct torture_context
*test
,
652 const char *default_value
)
656 SMB_ASSERT(test
!= NULL
);
657 SMB_ASSERT(test
->lp_ctx
!= NULL
);
659 ret
= lpcfg_parm_string(test
->lp_ctx
, NULL
, "torture", name
);
662 return default_value
;
667 static bool wrap_test_with_simple_tcase_const (
668 struct torture_context
*torture_ctx
,
669 struct torture_tcase
*tcase
,
670 struct torture_test
*test
)
672 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
676 return fn(torture_ctx
, test
->data
);
679 struct torture_tcase
*torture_suite_add_simple_tcase_const(
680 struct torture_suite
*suite
, const char *name
,
681 bool (*run
) (struct torture_context
*test
, const void *),
684 struct torture_tcase
*tcase
;
685 struct torture_test
*test
;
687 tcase
= torture_suite_add_tcase(suite
, name
);
689 test
= talloc(tcase
, struct torture_test
);
691 test
->name
= talloc_strdup(test
, name
);
692 test
->description
= NULL
;
693 test
->run
= wrap_test_with_simple_tcase_const
;
696 test
->dangerous
= false;
698 DLIST_ADD_END(tcase
->tests
, test
);
704 static bool wrap_simple_test(struct torture_context
*torture_ctx
,
705 struct torture_tcase
*tcase
,
706 struct torture_test
*test
)
708 bool (*fn
) (struct torture_context
*);
712 return fn(torture_ctx
);
715 struct torture_tcase
*torture_suite_add_simple_test(
716 struct torture_suite
*suite
,
718 bool (*run
) (struct torture_context
*test
))
720 struct torture_test
*test
;
721 struct torture_tcase
*tcase
;
723 tcase
= torture_suite_add_tcase(suite
, name
);
725 test
= talloc(tcase
, struct torture_test
);
727 test
->name
= talloc_strdup(test
, name
);
728 test
->description
= NULL
;
729 test
->run
= wrap_simple_test
;
731 test
->dangerous
= false;
733 DLIST_ADD_END(tcase
->tests
, test
);
739 * Add a child testsuite to a testsuite.
741 bool torture_suite_add_suite(struct torture_suite
*suite
,
742 struct torture_suite
*child
)
747 DLIST_ADD_END(suite
->children
, child
);
748 child
->parent
= suite
;
750 /* FIXME: Check for duplicates and return false if the
751 * added suite already exists as a child */
757 * Find the child testsuite with the specified name.
759 struct torture_suite
*torture_find_suite(struct torture_suite
*parent
,
762 struct torture_suite
*child
;
764 for (child
= parent
->children
; child
; child
= child
->next
)
765 if (!strcmp(child
->name
, name
))
771 static bool wrap_test_with_simple_test_const(struct torture_context
*torture_ctx
,
772 struct torture_tcase
*tcase
,
773 struct torture_test
*test
)
775 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
779 return fn(torture_ctx
, tcase
->data
);
782 struct torture_test
*torture_tcase_add_simple_test_const(
783 struct torture_tcase
*tcase
,
785 bool (*run
) (struct torture_context
*test
,
786 const void *tcase_data
))
788 struct torture_test
*test
;
790 test
= talloc(tcase
, struct torture_test
);
792 test
->name
= talloc_strdup(test
, name
);
793 test
->description
= NULL
;
794 test
->run
= wrap_test_with_simple_test_const
;
797 test
->dangerous
= false;
799 DLIST_ADD_END(tcase
->tests
, test
);
804 static bool wrap_test_with_simple_test(struct torture_context
*torture_ctx
,
805 struct torture_tcase
*tcase
,
806 struct torture_test
*test
)
808 bool (*fn
) (struct torture_context
*, void *tcase_data
);
812 return fn(torture_ctx
, tcase
->data
);
815 struct torture_test
*torture_tcase_add_simple_test(struct torture_tcase
*tcase
,
817 bool (*run
) (struct torture_context
*test
, void *tcase_data
))
819 struct torture_test
*test
;
821 test
= talloc(tcase
, struct torture_test
);
823 test
->name
= talloc_strdup(test
, name
);
824 test
->description
= NULL
;
825 test
->run
= wrap_test_with_simple_test
;
828 test
->dangerous
= false;
830 DLIST_ADD_END(tcase
->tests
, test
);
835 void torture_ui_report_time(struct torture_context
*context
)
837 if (context
->results
->ui_ops
->report_time
)
838 context
->results
->ui_ops
->report_time(context
);