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
))
249 * Run a torture test suite.
251 bool torture_run_suite(struct torture_context
*context
,
252 struct torture_suite
*suite
)
255 struct torture_tcase
*tcase
;
256 struct torture_suite
*tsuite
;
259 if (context
->results
->ui_ops
->suite_start
)
260 context
->results
->ui_ops
->suite_start(context
, suite
);
262 old_testname
= context
->active_testname
;
263 if (old_testname
!= NULL
)
264 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
265 old_testname
, suite
->name
);
267 context
->active_testname
= talloc_strdup(context
, suite
->name
);
269 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
270 ret
&= torture_run_tcase(context
, tcase
);
273 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
274 ret
&= torture_run_suite(context
, tsuite
);
277 talloc_free(context
->active_testname
);
278 context
->active_testname
= old_testname
;
280 if (context
->results
->ui_ops
->suite_finish
)
281 context
->results
->ui_ops
->suite_finish(context
, suite
);
286 void torture_ui_test_start(struct torture_context
*context
,
287 struct torture_tcase
*tcase
,
288 struct torture_test
*test
)
290 if (context
->results
->ui_ops
->test_start
)
291 context
->results
->ui_ops
->test_start(context
, tcase
, test
);
294 void torture_ui_test_result(struct torture_context
*context
,
295 enum torture_result result
,
298 if (context
->results
->ui_ops
->test_result
)
299 context
->results
->ui_ops
->test_result(context
, result
, comment
);
301 if (result
== TORTURE_ERROR
|| result
== TORTURE_FAIL
)
302 context
->results
->returncode
= false;
305 static bool internal_torture_run_test(struct torture_context
*context
,
306 struct torture_tcase
*tcase
,
307 struct torture_test
*test
,
311 char *old_testname
= NULL
;
313 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
314 old_testname
= context
->active_testname
;
315 context
->active_testname
= talloc_asprintf(context
, "%s-%s", old_testname
, test
->name
);
318 context
->active_tcase
= tcase
;
319 context
->active_test
= test
;
321 torture_ui_test_start(context
, tcase
, test
);
323 context
->last_reason
= NULL
;
324 context
->last_result
= TORTURE_OK
;
326 if (!already_setup
&& tcase
->setup
&&
327 !tcase
->setup(context
, &(tcase
->data
))) {
328 if (context
->last_reason
== NULL
)
329 context
->last_reason
= talloc_strdup(context
, "Setup failure");
330 context
->last_result
= TORTURE_ERROR
;
332 } else if (test
->dangerous
&&
333 !torture_setting_bool(context
, "dangerous", false)) {
334 context
->last_result
= TORTURE_SKIP
;
335 context
->last_reason
= talloc_asprintf(context
,
336 "disabled %s - enable dangerous tests to use", test
->name
);
339 success
= test
->run(context
, tcase
, test
);
341 if (!success
&& context
->last_result
== TORTURE_OK
) {
342 if (context
->last_reason
== NULL
)
343 context
->last_reason
= talloc_strdup(context
, "Unknown error/failure");
344 context
->last_result
= TORTURE_ERROR
;
348 if (!already_setup
&& tcase
->teardown
&& !tcase
->teardown(context
, tcase
->data
)) {
349 if (context
->last_reason
== NULL
)
350 context
->last_reason
= talloc_strdup(context
, "Setup failure");
351 context
->last_result
= TORTURE_ERROR
;
355 torture_ui_test_result(context
, context
->last_result
,
356 context
->last_reason
);
358 talloc_free(context
->last_reason
);
360 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
361 talloc_free(context
->active_testname
);
362 context
->active_testname
= old_testname
;
364 context
->active_test
= NULL
;
365 context
->active_tcase
= NULL
;
370 bool torture_run_tcase(struct torture_context
*context
,
371 struct torture_tcase
*tcase
)
375 struct torture_test
*test
;
377 context
->active_tcase
= tcase
;
378 if (context
->results
->ui_ops
->tcase_start
)
379 context
->results
->ui_ops
->tcase_start(context
, tcase
);
381 if (tcase
->fixture_persistent
&& tcase
->setup
382 && !tcase
->setup(context
, &tcase
->data
)) {
383 /* FIXME: Use torture ui ops for reporting this error */
384 fprintf(stderr
, "Setup failed: ");
385 if (context
->last_reason
!= NULL
)
386 fprintf(stderr
, "%s", context
->last_reason
);
387 fprintf(stderr
, "\n");
392 old_testname
= context
->active_testname
;
393 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
394 old_testname
, tcase
->name
);
395 for (test
= tcase
->tests
; test
; test
= test
->next
) {
396 ret
&= internal_torture_run_test(context
, tcase
, test
,
397 tcase
->fixture_persistent
);
399 talloc_free(context
->active_testname
);
400 context
->active_testname
= old_testname
;
402 if (tcase
->fixture_persistent
&& tcase
->teardown
&&
403 !tcase
->teardown(context
, tcase
->data
))
407 context
->active_tcase
= NULL
;
409 if (context
->results
->ui_ops
->tcase_finish
)
410 context
->results
->ui_ops
->tcase_finish(context
, tcase
);
415 bool torture_run_test(struct torture_context
*context
,
416 struct torture_tcase
*tcase
,
417 struct torture_test
*test
)
419 return internal_torture_run_test(context
, tcase
, test
, false);
422 int torture_setting_int(struct torture_context
*test
, const char *name
,
425 return lp_parm_int(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
428 unsigned long torture_setting_ulong(struct torture_context
*test
,
430 unsigned long default_value
)
432 return lp_parm_ulong(test
->lp_ctx
, NULL
, "torture", name
,
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
*);