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
);
61 * Create a sub torture context
63 struct torture_context
*torture_context_child(struct torture_context
*parent
)
65 struct torture_context
*subtorture
= talloc_zero(parent
, struct torture_context
);
67 if (subtorture
== NULL
)
70 subtorture
->ev
= talloc_reference(subtorture
, parent
->ev
);
71 subtorture
->lp_ctx
= talloc_reference(subtorture
, parent
->lp_ctx
);
72 subtorture
->outputdir
= talloc_reference(subtorture
, parent
->outputdir
);
73 subtorture
->results
= talloc_reference(subtorture
, parent
->results
);
79 create a temporary directory under the output dir
81 _PUBLIC_ NTSTATUS
torture_temp_dir(struct torture_context
*tctx
,
82 const char *prefix
, char **tempdir
)
84 SMB_ASSERT(tctx
->outputdir
!= NULL
);
86 *tempdir
= talloc_asprintf(tctx
, "%s/%s.XXXXXX", tctx
->outputdir
,
88 NT_STATUS_HAVE_NO_MEMORY(*tempdir
);
90 if (mkdtemp(*tempdir
) == NULL
) {
91 return map_nt_error_from_unix_common(errno
);
97 static int local_deltree(const char *path
)
100 struct dirent
*dirent
;
101 DIR *dir
= opendir(path
);
103 char *error
= talloc_asprintf(NULL
, "Could not open directory %s", path
);
108 while ((dirent
= readdir(dir
))) {
110 if ((strcmp(dirent
->d_name
, ".") == 0) || (strcmp(dirent
->d_name
, "..") == 0)) {
113 name
= talloc_asprintf(NULL
, "%s/%s", path
,
119 DEBUG(0, ("About to remove %s\n", name
));
126 if (errno
== ENOTEMPTY
) {
127 ret
= local_deltree(name
);
134 char *error
= talloc_asprintf(NULL
, "Could not remove %s", path
);
145 _PUBLIC_ NTSTATUS
torture_deltree_outputdir(struct torture_context
*tctx
)
147 if (tctx
->outputdir
== NULL
) {
150 if ((strcmp(tctx
->outputdir
, "/") == 0)
151 || (strcmp(tctx
->outputdir
, "") == 0)) {
152 return NT_STATUS_INVALID_PARAMETER
;
155 if (local_deltree(tctx
->outputdir
) == -1) {
157 return map_nt_error_from_unix_common(errno
);
159 return NT_STATUS_UNSUCCESSFUL
;
165 * Comment on the status/progress of a test
167 void torture_comment(struct torture_context
*context
, const char *comment
, ...)
172 if (!context
->results
->ui_ops
->comment
)
175 va_start(ap
, comment
);
176 tmp
= talloc_vasprintf(context
, comment
, ap
);
179 context
->results
->ui_ops
->comment(context
, tmp
);
185 * Print a warning about the current test
187 void torture_warning(struct torture_context
*context
, const char *comment
, ...)
192 if (!context
->results
->ui_ops
->warning
)
195 va_start(ap
, comment
);
196 tmp
= talloc_vasprintf(context
, comment
, ap
);
199 context
->results
->ui_ops
->warning(context
, tmp
);
205 * Store the result of a torture test.
207 void torture_result(struct torture_context
*context
,
208 enum torture_result result
, const char *fmt
, ...)
214 if (context
->last_reason
) {
215 torture_warning(context
, "%s", context
->last_reason
);
216 talloc_free(context
->last_reason
);
219 context
->last_result
= result
;
220 context
->last_reason
= talloc_vasprintf(context
, fmt
, ap
);
225 * Create a new torture suite
227 struct torture_suite
*torture_suite_create(TALLOC_CTX
*ctx
, const char *name
)
229 struct torture_suite
*suite
= talloc_zero(ctx
, struct torture_suite
);
231 suite
->name
= talloc_strdup(suite
, name
);
232 suite
->testcases
= NULL
;
233 suite
->children
= NULL
;
239 * Set the setup() and teardown() functions for a testcase.
241 void torture_tcase_set_fixture(struct torture_tcase
*tcase
,
242 bool (*setup
) (struct torture_context
*, void **),
243 bool (*teardown
) (struct torture_context
*, void *))
245 tcase
->setup
= setup
;
246 tcase
->teardown
= teardown
;
249 static bool wrap_test_with_testcase_const(struct torture_context
*torture_ctx
,
250 struct torture_tcase
*tcase
,
251 struct torture_test
*test
)
253 bool (*fn
) (struct torture_context
*,
254 const void *tcase_data
,
255 const void *test_data
);
259 return fn(torture_ctx
, tcase
->data
, test
->data
);
263 * Add a test that uses const data to a testcase
265 struct torture_test
*torture_tcase_add_test_const(struct torture_tcase
*tcase
,
267 bool (*run
) (struct torture_context
*, const void *tcase_data
,
268 const void *test_data
),
271 struct torture_test
*test
= talloc(tcase
, struct torture_test
);
273 test
->name
= talloc_strdup(test
, name
);
274 test
->description
= NULL
;
275 test
->run
= wrap_test_with_testcase_const
;
277 test
->dangerous
= false;
280 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
288 bool torture_suite_init_tcase(struct torture_suite
*suite
,
289 struct torture_tcase
*tcase
,
292 tcase
->name
= talloc_strdup(tcase
, name
);
293 tcase
->description
= NULL
;
295 tcase
->teardown
= NULL
;
296 tcase
->fixture_persistent
= true;
299 DLIST_ADD_END(suite
->testcases
, tcase
, struct torture_tcase
*);
305 struct torture_tcase
*torture_suite_add_tcase(struct torture_suite
*suite
,
308 struct torture_tcase
*tcase
= talloc(suite
, struct torture_tcase
);
310 if (!torture_suite_init_tcase(suite
, tcase
, name
))
316 int torture_suite_children_count(const struct torture_suite
*suite
)
319 struct torture_tcase
*tcase
;
320 struct torture_test
*test
;
321 struct torture_suite
*tsuite
;
322 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
323 for (test
= tcase
->tests
; test
; test
= test
->next
) {
327 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
334 * Run a torture test suite.
336 bool torture_run_suite(struct torture_context
*context
,
337 struct torture_suite
*suite
)
339 return torture_run_suite_restricted(context
, suite
, NULL
);
342 bool torture_run_suite_restricted(struct torture_context
*context
,
343 struct torture_suite
*suite
, const char **restricted
)
346 struct torture_tcase
*tcase
;
347 struct torture_suite
*tsuite
;
349 if (context
->results
->ui_ops
->suite_start
)
350 context
->results
->ui_ops
->suite_start(context
, suite
);
352 /* FIXME: Adjust torture_suite_children_count if restricted != NULL */
353 context
->results
->ui_ops
->progress(context
,
354 torture_suite_children_count(suite
), TORTURE_PROGRESS_SET
);
356 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
357 ret
&= torture_run_tcase_restricted(context
, tcase
, restricted
);
360 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
361 context
->results
->ui_ops
->progress(context
, 0, TORTURE_PROGRESS_PUSH
);
362 ret
&= torture_run_suite_restricted(context
, tsuite
, restricted
);
363 context
->results
->ui_ops
->progress(context
, 0, TORTURE_PROGRESS_POP
);
366 if (context
->results
->ui_ops
->suite_finish
)
367 context
->results
->ui_ops
->suite_finish(context
, suite
);
372 void torture_ui_test_start(struct torture_context
*context
,
373 struct torture_tcase
*tcase
,
374 struct torture_test
*test
)
376 if (context
->results
->ui_ops
->test_start
)
377 context
->results
->ui_ops
->test_start(context
, tcase
, test
);
380 void torture_ui_test_result(struct torture_context
*context
,
381 enum torture_result result
,
384 if (context
->results
->ui_ops
->test_result
)
385 context
->results
->ui_ops
->test_result(context
, result
, comment
);
387 if (result
== TORTURE_ERROR
|| result
== TORTURE_FAIL
)
388 context
->results
->returncode
= false;
391 static bool test_needs_running(const char *name
, const char **restricted
)
394 if (restricted
== NULL
)
396 for (i
= 0; restricted
[i
]; i
++) {
397 if (!strcmp(name
, restricted
[i
]))
403 static bool internal_torture_run_test(struct torture_context
*context
,
404 struct torture_tcase
*tcase
,
405 struct torture_test
*test
,
407 const char **restricted
)
410 char *subunit_testname
= NULL
;
412 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
413 subunit_testname
= talloc_asprintf(context
, "%s.%s", tcase
->name
, test
->name
);
415 subunit_testname
= talloc_strdup(context
, test
->name
);
418 if (!test_needs_running(subunit_testname
, restricted
))
421 context
->active_tcase
= tcase
;
422 context
->active_test
= test
;
424 torture_ui_test_start(context
, tcase
, test
);
426 context
->last_reason
= NULL
;
427 context
->last_result
= TORTURE_OK
;
429 if (!already_setup
&& tcase
->setup
&&
430 !tcase
->setup(context
, &(tcase
->data
))) {
431 if (context
->last_reason
== NULL
)
432 context
->last_reason
= talloc_strdup(context
, "Setup failure");
433 context
->last_result
= TORTURE_ERROR
;
435 } else if (test
->dangerous
&&
436 !torture_setting_bool(context
, "dangerous", false)) {
437 context
->last_result
= TORTURE_SKIP
;
438 context
->last_reason
= talloc_asprintf(context
,
439 "disabled %s - enable dangerous tests to use", test
->name
);
442 success
= test
->run(context
, tcase
, test
);
444 if (!success
&& context
->last_result
== TORTURE_OK
) {
445 if (context
->last_reason
== NULL
)
446 context
->last_reason
= talloc_strdup(context
,
447 "Unknown error/failure. Missing torture_fail() or torture_assert_*() call?");
448 context
->last_result
= TORTURE_ERROR
;
452 if (!already_setup
&& tcase
->teardown
&& !tcase
->teardown(context
, tcase
->data
)) {
453 if (context
->last_reason
== NULL
)
454 context
->last_reason
= talloc_strdup(context
, "Setup failure");
455 context
->last_result
= TORTURE_ERROR
;
459 torture_ui_test_result(context
, context
->last_result
,
460 context
->last_reason
);
462 talloc_free(context
->last_reason
);
464 context
->active_test
= NULL
;
465 context
->active_tcase
= NULL
;
470 bool torture_run_tcase(struct torture_context
*context
,
471 struct torture_tcase
*tcase
)
473 return torture_run_tcase_restricted(context
, tcase
, NULL
);
476 bool torture_run_tcase_restricted(struct torture_context
*context
,
477 struct torture_tcase
*tcase
, const char **restricted
)
480 struct torture_test
*test
;
481 bool setup_succeeded
= true;
482 const char * setup_reason
= "Setup failed";
484 context
->active_tcase
= tcase
;
485 if (context
->results
->ui_ops
->tcase_start
)
486 context
->results
->ui_ops
->tcase_start(context
, tcase
);
488 if (tcase
->fixture_persistent
&& tcase
->setup
) {
489 setup_succeeded
= tcase
->setup(context
, &tcase
->data
);
492 if (!setup_succeeded
) {
493 /* Uh-oh. The setup failed, so we can't run any of the tests
494 * in this testcase. The subunit format doesn't specify what
495 * to do here, so we keep the failure reason, and manually
496 * use it to fail every test.
498 if (context
->last_reason
!= NULL
) {
499 setup_reason
= talloc_asprintf(context
,
500 "Setup failed: %s", context
->last_reason
);
504 for (test
= tcase
->tests
; test
; test
= test
->next
) {
505 if (setup_succeeded
) {
506 ret
&= internal_torture_run_test(context
, tcase
, test
,
507 tcase
->fixture_persistent
, restricted
);
509 context
->active_tcase
= tcase
;
510 context
->active_test
= test
;
511 torture_ui_test_start(context
, tcase
, test
);
512 torture_ui_test_result(context
, TORTURE_FAIL
, setup_reason
);
516 if (setup_succeeded
&& tcase
->fixture_persistent
&& tcase
->teardown
&&
517 !tcase
->teardown(context
, tcase
->data
)) {
521 context
->active_tcase
= NULL
;
522 context
->active_test
= NULL
;
524 if (context
->results
->ui_ops
->tcase_finish
)
525 context
->results
->ui_ops
->tcase_finish(context
, tcase
);
527 return (!setup_succeeded
) ? false : ret
;
530 bool torture_run_test(struct torture_context
*context
,
531 struct torture_tcase
*tcase
,
532 struct torture_test
*test
)
534 return internal_torture_run_test(context
, tcase
, test
, false, NULL
);
537 bool torture_run_test_restricted(struct torture_context
*context
,
538 struct torture_tcase
*tcase
,
539 struct torture_test
*test
,
540 const char **restricted
)
542 return internal_torture_run_test(context
, tcase
, test
, false, restricted
);
545 int torture_setting_int(struct torture_context
*test
, const char *name
,
548 return lpcfg_parm_int(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
551 unsigned long torture_setting_ulong(struct torture_context
*test
,
553 unsigned long default_value
)
555 return lpcfg_parm_ulong(test
->lp_ctx
, NULL
, "torture", name
,
559 double torture_setting_double(struct torture_context
*test
, const char *name
,
560 double default_value
)
562 return lpcfg_parm_double(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
565 bool torture_setting_bool(struct torture_context
*test
, const char *name
,
568 return lpcfg_parm_bool(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
571 const char *torture_setting_string(struct torture_context
*test
,
573 const char *default_value
)
577 SMB_ASSERT(test
!= NULL
);
578 SMB_ASSERT(test
->lp_ctx
!= NULL
);
580 ret
= lpcfg_parm_string(test
->lp_ctx
, NULL
, "torture", name
);
583 return default_value
;
588 static bool wrap_test_with_simple_tcase_const (
589 struct torture_context
*torture_ctx
,
590 struct torture_tcase
*tcase
,
591 struct torture_test
*test
)
593 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
597 return fn(torture_ctx
, test
->data
);
600 struct torture_tcase
*torture_suite_add_simple_tcase_const(
601 struct torture_suite
*suite
, const char *name
,
602 bool (*run
) (struct torture_context
*test
, const void *),
605 struct torture_tcase
*tcase
;
606 struct torture_test
*test
;
608 tcase
= torture_suite_add_tcase(suite
, name
);
610 test
= talloc(tcase
, struct torture_test
);
612 test
->name
= talloc_strdup(test
, name
);
613 test
->description
= NULL
;
614 test
->run
= wrap_test_with_simple_tcase_const
;
617 test
->dangerous
= false;
619 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
624 static bool wrap_simple_test(struct torture_context
*torture_ctx
,
625 struct torture_tcase
*tcase
,
626 struct torture_test
*test
)
628 bool (*fn
) (struct torture_context
*);
632 return fn(torture_ctx
);
635 struct torture_tcase
*torture_suite_add_simple_test(
636 struct torture_suite
*suite
,
638 bool (*run
) (struct torture_context
*test
))
640 struct torture_test
*test
;
641 struct torture_tcase
*tcase
;
643 tcase
= torture_suite_add_tcase(suite
, name
);
645 test
= talloc(tcase
, struct torture_test
);
647 test
->name
= talloc_strdup(test
, name
);
648 test
->description
= NULL
;
649 test
->run
= wrap_simple_test
;
651 test
->dangerous
= false;
653 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
659 * Add a child testsuite to a testsuite.
661 bool torture_suite_add_suite(struct torture_suite
*suite
,
662 struct torture_suite
*child
)
667 DLIST_ADD_END(suite
->children
, child
, struct torture_suite
*);
669 /* FIXME: Check for duplicates and return false if the
670 * added suite already exists as a child */
676 * Find the child testsuite with the specified name.
678 struct torture_suite
*torture_find_suite(struct torture_suite
*parent
,
681 struct torture_suite
*child
;
683 for (child
= parent
->children
; child
; child
= child
->next
)
684 if (!strcmp(child
->name
, name
))
690 static bool wrap_test_with_simple_test_const(struct torture_context
*torture_ctx
,
691 struct torture_tcase
*tcase
,
692 struct torture_test
*test
)
694 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
698 return fn(torture_ctx
, tcase
->data
);
701 struct torture_test
*torture_tcase_add_simple_test_const(
702 struct torture_tcase
*tcase
,
704 bool (*run
) (struct torture_context
*test
,
705 const void *tcase_data
))
707 struct torture_test
*test
;
709 test
= talloc(tcase
, struct torture_test
);
711 test
->name
= talloc_strdup(test
, name
);
712 test
->description
= NULL
;
713 test
->run
= wrap_test_with_simple_test_const
;
716 test
->dangerous
= false;
718 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
723 static bool wrap_test_with_simple_test(struct torture_context
*torture_ctx
,
724 struct torture_tcase
*tcase
,
725 struct torture_test
*test
)
727 bool (*fn
) (struct torture_context
*, void *tcase_data
);
731 return fn(torture_ctx
, tcase
->data
);
734 struct torture_test
*torture_tcase_add_simple_test(struct torture_tcase
*tcase
,
736 bool (*run
) (struct torture_context
*test
, void *tcase_data
))
738 struct torture_test
*test
;
740 test
= talloc(tcase
, struct torture_test
);
742 test
->name
= talloc_strdup(test
, name
);
743 test
->description
= NULL
;
744 test
->run
= wrap_test_with_simple_test
;
747 test
->dangerous
= false;
749 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
754 void torture_ui_report_time(struct torture_context
*context
)
756 if (context
->results
->ui_ops
->report_time
)
757 context
->results
->ui_ops
->report_time(context
);