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
->level
= parent
->level
+1;
69 subtorture
->ev
= talloc_reference(subtorture
, parent
->ev
);
70 subtorture
->lp_ctx
= talloc_reference(subtorture
, parent
->lp_ctx
);
71 subtorture
->outputdir
= talloc_reference(subtorture
, parent
->outputdir
);
72 subtorture
->results
= talloc_reference(subtorture
, parent
->results
);
78 create a temporary directory.
80 _PUBLIC_ NTSTATUS
torture_temp_dir(struct torture_context
*tctx
,
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(errno
);
98 * Comment on the status/progress of a test
100 void torture_comment(struct torture_context
*context
, const char *comment
, ...)
105 if (!context
->results
->ui_ops
->comment
)
108 va_start(ap
, comment
);
109 tmp
= talloc_vasprintf(context
, comment
, ap
);
112 context
->results
->ui_ops
->comment(context
, tmp
);
118 * Print a warning about the current test
120 void torture_warning(struct torture_context
*context
, const char *comment
, ...)
125 if (!context
->results
->ui_ops
->warning
)
128 va_start(ap
, comment
);
129 tmp
= talloc_vasprintf(context
, comment
, ap
);
132 context
->results
->ui_ops
->warning(context
, tmp
);
138 * Store the result of a torture test.
140 void torture_result(struct torture_context
*context
,
141 enum torture_result result
, const char *fmt
, ...)
147 if (context
->last_reason
) {
148 torture_warning(context
, "%s", context
->last_reason
);
149 talloc_free(context
->last_reason
);
152 context
->last_result
= result
;
153 context
->last_reason
= talloc_vasprintf(context
, fmt
, ap
);
158 * Create a new torture suite
160 struct torture_suite
*torture_suite_create(TALLOC_CTX
*ctx
, const char *name
)
162 struct torture_suite
*suite
= talloc_zero(ctx
, struct torture_suite
);
164 suite
->name
= talloc_strdup(suite
, name
);
165 suite
->testcases
= NULL
;
166 suite
->children
= NULL
;
172 * Set the setup() and teardown() functions for a testcase.
174 void torture_tcase_set_fixture(struct torture_tcase
*tcase
,
175 bool (*setup
) (struct torture_context
*, void **),
176 bool (*teardown
) (struct torture_context
*, void *))
178 tcase
->setup
= setup
;
179 tcase
->teardown
= teardown
;
182 static bool wrap_test_with_testcase_const(struct torture_context
*torture_ctx
,
183 struct torture_tcase
*tcase
,
184 struct torture_test
*test
)
186 bool (*fn
) (struct torture_context
*,
187 const void *tcase_data
,
188 const void *test_data
);
192 return fn(torture_ctx
, tcase
->data
, test
->data
);
196 * Add a test that uses const data to a testcase
198 struct torture_test
*torture_tcase_add_test_const(struct torture_tcase
*tcase
,
200 bool (*run
) (struct torture_context
*, const void *tcase_data
,
201 const void *test_data
),
204 struct torture_test
*test
= talloc(tcase
, struct torture_test
);
206 test
->name
= talloc_strdup(test
, name
);
207 test
->description
= NULL
;
208 test
->run
= wrap_test_with_testcase_const
;
210 test
->dangerous
= false;
213 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
221 bool torture_suite_init_tcase(struct torture_suite
*suite
,
222 struct torture_tcase
*tcase
,
225 tcase
->name
= talloc_strdup(tcase
, name
);
226 tcase
->description
= NULL
;
228 tcase
->teardown
= NULL
;
229 tcase
->fixture_persistent
= true;
232 DLIST_ADD_END(suite
->testcases
, tcase
, struct torture_tcase
*);
238 struct torture_tcase
*torture_suite_add_tcase(struct torture_suite
*suite
,
241 struct torture_tcase
*tcase
= talloc(suite
, struct torture_tcase
);
243 if (!torture_suite_init_tcase(suite
, tcase
, name
))
250 * Run a torture test suite.
252 bool torture_run_suite(struct torture_context
*context
,
253 struct torture_suite
*suite
)
256 struct torture_tcase
*tcase
;
257 struct torture_suite
*tsuite
;
261 if (context
->results
->ui_ops
->suite_start
)
262 context
->results
->ui_ops
->suite_start(context
, suite
);
264 old_testname
= context
->active_testname
;
265 if (old_testname
!= NULL
)
266 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
267 old_testname
, suite
->name
);
269 context
->active_testname
= talloc_strdup(context
, suite
->name
);
271 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
272 ret
&= torture_run_tcase(context
, tcase
);
275 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
276 ret
&= torture_run_suite(context
, tsuite
);
279 talloc_free(context
->active_testname
);
280 context
->active_testname
= old_testname
;
282 if (context
->results
->ui_ops
->suite_finish
)
283 context
->results
->ui_ops
->suite_finish(context
, suite
);
290 void torture_ui_test_start(struct torture_context
*context
,
291 struct torture_tcase
*tcase
,
292 struct torture_test
*test
)
294 if (context
->results
->ui_ops
->test_start
)
295 context
->results
->ui_ops
->test_start(context
, tcase
, test
);
298 void torture_ui_test_result(struct torture_context
*context
,
299 enum torture_result result
,
302 if (context
->results
->ui_ops
->test_result
)
303 context
->results
->ui_ops
->test_result(context
, result
, comment
);
305 if (result
== TORTURE_ERROR
|| result
== TORTURE_FAIL
)
306 context
->results
->returncode
= false;
309 static bool internal_torture_run_test(struct torture_context
*context
,
310 struct torture_tcase
*tcase
,
311 struct torture_test
*test
,
315 char *old_testname
= NULL
;
317 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
318 old_testname
= context
->active_testname
;
319 context
->active_testname
= talloc_asprintf(context
, "%s-%s", old_testname
, test
->name
);
322 context
->active_tcase
= tcase
;
323 context
->active_test
= test
;
325 torture_ui_test_start(context
, tcase
, test
);
327 context
->last_reason
= NULL
;
328 context
->last_result
= TORTURE_OK
;
330 if (!already_setup
&& tcase
->setup
&&
331 !tcase
->setup(context
, &(tcase
->data
))) {
332 if (context
->last_reason
== NULL
)
333 context
->last_reason
= talloc_strdup(context
, "Setup failure");
334 context
->last_result
= TORTURE_ERROR
;
336 } else if (test
->dangerous
&&
337 !torture_setting_bool(context
, "dangerous", false)) {
338 context
->last_result
= TORTURE_SKIP
;
339 context
->last_reason
= talloc_asprintf(context
,
340 "disabled %s - enable dangerous tests to use", test
->name
);
343 success
= test
->run(context
, tcase
, test
);
345 if (!success
&& context
->last_result
== TORTURE_OK
) {
346 if (context
->last_reason
== NULL
)
347 context
->last_reason
= talloc_strdup(context
, "Unknown error/failure");
348 context
->last_result
= TORTURE_ERROR
;
352 if (!already_setup
&& tcase
->teardown
&& !tcase
->teardown(context
, tcase
->data
)) {
353 if (context
->last_reason
== NULL
)
354 context
->last_reason
= talloc_strdup(context
, "Setup failure");
355 context
->last_result
= TORTURE_ERROR
;
359 torture_ui_test_result(context
, context
->last_result
,
360 context
->last_reason
);
362 talloc_free(context
->last_reason
);
364 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
365 talloc_free(context
->active_testname
);
366 context
->active_testname
= old_testname
;
368 context
->active_test
= NULL
;
369 context
->active_tcase
= NULL
;
374 bool torture_run_tcase(struct torture_context
*context
,
375 struct torture_tcase
*tcase
)
379 struct torture_test
*test
;
383 context
->active_tcase
= tcase
;
384 if (context
->results
->ui_ops
->tcase_start
)
385 context
->results
->ui_ops
->tcase_start(context
, tcase
);
387 if (tcase
->fixture_persistent
&& tcase
->setup
388 && !tcase
->setup(context
, &tcase
->data
)) {
389 /* FIXME: Use torture ui ops for reporting this error */
390 fprintf(stderr
, "Setup failed: ");
391 if (context
->last_reason
!= NULL
)
392 fprintf(stderr
, "%s", context
->last_reason
);
393 fprintf(stderr
, "\n");
398 old_testname
= context
->active_testname
;
399 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
400 old_testname
, tcase
->name
);
401 for (test
= tcase
->tests
; test
; test
= test
->next
) {
402 ret
&= internal_torture_run_test(context
, tcase
, test
,
403 tcase
->fixture_persistent
);
405 talloc_free(context
->active_testname
);
406 context
->active_testname
= old_testname
;
408 if (tcase
->fixture_persistent
&& tcase
->teardown
&&
409 !tcase
->teardown(context
, tcase
->data
))
413 context
->active_tcase
= NULL
;
415 if (context
->results
->ui_ops
->tcase_finish
)
416 context
->results
->ui_ops
->tcase_finish(context
, tcase
);
423 bool torture_run_test(struct torture_context
*context
,
424 struct torture_tcase
*tcase
,
425 struct torture_test
*test
)
427 return internal_torture_run_test(context
, tcase
, test
, false);
430 int torture_setting_int(struct torture_context
*test
, const char *name
,
433 return lp_parm_int(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
436 double torture_setting_double(struct torture_context
*test
, const char *name
,
437 double default_value
)
439 return lp_parm_double(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
442 bool torture_setting_bool(struct torture_context
*test
, const char *name
,
445 return lp_parm_bool(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
448 const char *torture_setting_string(struct torture_context
*test
,
450 const char *default_value
)
454 SMB_ASSERT(test
!= NULL
);
455 SMB_ASSERT(test
->lp_ctx
!= NULL
);
457 ret
= lp_parm_string(test
->lp_ctx
, NULL
, "torture", name
);
460 return default_value
;
465 static bool wrap_test_with_simple_tcase_const (
466 struct torture_context
*torture_ctx
,
467 struct torture_tcase
*tcase
,
468 struct torture_test
*test
)
470 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
474 return fn(torture_ctx
, test
->data
);
477 struct torture_tcase
*torture_suite_add_simple_tcase_const(
478 struct torture_suite
*suite
, const char *name
,
479 bool (*run
) (struct torture_context
*test
, const void *),
482 struct torture_tcase
*tcase
;
483 struct torture_test
*test
;
485 tcase
= torture_suite_add_tcase(suite
, name
);
487 test
= talloc(tcase
, struct torture_test
);
489 test
->name
= talloc_strdup(test
, name
);
490 test
->description
= NULL
;
491 test
->run
= wrap_test_with_simple_tcase_const
;
494 test
->dangerous
= false;
496 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
501 static bool wrap_simple_test(struct torture_context
*torture_ctx
,
502 struct torture_tcase
*tcase
,
503 struct torture_test
*test
)
505 bool (*fn
) (struct torture_context
*);
509 return fn(torture_ctx
);
512 struct torture_tcase
*torture_suite_add_simple_test(
513 struct torture_suite
*suite
,
515 bool (*run
) (struct torture_context
*test
))
517 struct torture_test
*test
;
518 struct torture_tcase
*tcase
;
520 tcase
= torture_suite_add_tcase(suite
, name
);
522 test
= talloc(tcase
, struct torture_test
);
524 test
->name
= talloc_strdup(test
, name
);
525 test
->description
= NULL
;
526 test
->run
= wrap_simple_test
;
528 test
->dangerous
= false;
530 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
536 * Add a child testsuite to a testsuite.
538 bool torture_suite_add_suite(struct torture_suite
*suite
,
539 struct torture_suite
*child
)
544 DLIST_ADD_END(suite
->children
, child
, struct torture_suite
*);
546 /* FIXME: Check for duplicates and return false if the
547 * added suite already exists as a child */
553 * Find the child testsuite with the specified name.
555 struct torture_suite
*torture_find_suite(struct torture_suite
*parent
,
558 struct torture_suite
*child
;
560 for (child
= parent
->children
; child
; child
= child
->next
)
561 if (!strcmp(child
->name
, name
))
567 static bool wrap_test_with_simple_test_const(struct torture_context
*torture_ctx
,
568 struct torture_tcase
*tcase
,
569 struct torture_test
*test
)
571 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
575 return fn(torture_ctx
, tcase
->data
);
578 struct torture_test
*torture_tcase_add_simple_test_const(
579 struct torture_tcase
*tcase
,
581 bool (*run
) (struct torture_context
*test
,
582 const void *tcase_data
))
584 struct torture_test
*test
;
586 test
= talloc(tcase
, struct torture_test
);
588 test
->name
= talloc_strdup(test
, name
);
589 test
->description
= NULL
;
590 test
->run
= wrap_test_with_simple_test_const
;
593 test
->dangerous
= false;
595 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
600 static bool wrap_test_with_simple_test(struct torture_context
*torture_ctx
,
601 struct torture_tcase
*tcase
,
602 struct torture_test
*test
)
604 bool (*fn
) (struct torture_context
*, void *tcase_data
);
608 return fn(torture_ctx
, tcase
->data
);
611 struct torture_test
*torture_tcase_add_simple_test(struct torture_tcase
*tcase
,
613 bool (*run
) (struct torture_context
*test
, void *tcase_data
))
615 struct torture_test
*test
;
617 test
= talloc(tcase
, struct torture_test
);
619 test
->name
= talloc_strdup(test
, name
);
620 test
->description
= NULL
;
621 test
->run
= wrap_test_with_simple_test
;
624 test
->dangerous
= false;
626 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);