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
);
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
);
130 context
->results
->ui_ops
->warning(context
, tmp
);
136 * Store the result of a torture test.
138 void torture_result(struct torture_context
*context
,
139 enum torture_result result
, const char *fmt
, ...)
145 if (context
->last_reason
) {
146 torture_warning(context
, "%s", context
->last_reason
);
147 talloc_free(context
->last_reason
);
150 context
->last_result
= result
;
151 context
->last_reason
= talloc_vasprintf(context
, fmt
, ap
);
156 * Create a new torture suite
158 struct torture_suite
*torture_suite_create(TALLOC_CTX
*ctx
, const char *name
)
160 struct torture_suite
*suite
= talloc_zero(ctx
, struct torture_suite
);
162 suite
->name
= talloc_strdup(suite
, name
);
163 suite
->testcases
= NULL
;
164 suite
->children
= NULL
;
170 * Set the setup() and teardown() functions for a testcase.
172 void torture_tcase_set_fixture(struct torture_tcase
*tcase
,
173 bool (*setup
) (struct torture_context
*, void **),
174 bool (*teardown
) (struct torture_context
*, void *))
176 tcase
->setup
= setup
;
177 tcase
->teardown
= teardown
;
180 static bool wrap_test_with_testcase_const(struct torture_context
*torture_ctx
,
181 struct torture_tcase
*tcase
,
182 struct torture_test
*test
)
184 bool (*fn
) (struct torture_context
*,
185 const void *tcase_data
,
186 const void *test_data
);
190 return fn(torture_ctx
, tcase
->data
, test
->data
);
194 * Add a test that uses const data to a testcase
196 struct torture_test
*torture_tcase_add_test_const(struct torture_tcase
*tcase
,
198 bool (*run
) (struct torture_context
*, const void *tcase_data
,
199 const void *test_data
),
202 struct torture_test
*test
= talloc(tcase
, struct torture_test
);
204 test
->name
= talloc_strdup(test
, name
);
205 test
->description
= NULL
;
206 test
->run
= wrap_test_with_testcase_const
;
208 test
->dangerous
= false;
211 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
219 bool torture_suite_init_tcase(struct torture_suite
*suite
,
220 struct torture_tcase
*tcase
,
223 tcase
->name
= talloc_strdup(tcase
, name
);
224 tcase
->description
= NULL
;
226 tcase
->teardown
= NULL
;
227 tcase
->fixture_persistent
= true;
230 DLIST_ADD_END(suite
->testcases
, tcase
, struct torture_tcase
*);
236 struct torture_tcase
*torture_suite_add_tcase(struct torture_suite
*suite
,
239 struct torture_tcase
*tcase
= talloc(suite
, struct torture_tcase
);
241 if (!torture_suite_init_tcase(suite
, tcase
, name
))
248 * Run a torture test suite.
250 bool torture_run_suite(struct torture_context
*context
,
251 struct torture_suite
*suite
)
254 struct torture_tcase
*tcase
;
255 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
);
288 void torture_ui_test_start(struct torture_context
*context
,
289 struct torture_tcase
*tcase
,
290 struct torture_test
*test
)
292 if (context
->results
->ui_ops
->test_start
)
293 context
->results
->ui_ops
->test_start(context
, tcase
, test
);
296 void torture_ui_test_result(struct torture_context
*context
,
297 enum torture_result result
,
300 if (context
->results
->ui_ops
->test_result
)
301 context
->results
->ui_ops
->test_result(context
, result
, comment
);
303 if (result
== TORTURE_ERROR
|| result
== TORTURE_FAIL
)
304 context
->results
->returncode
= false;
307 static bool internal_torture_run_test(struct torture_context
*context
,
308 struct torture_tcase
*tcase
,
309 struct torture_test
*test
,
313 char *old_testname
= NULL
;
315 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
316 old_testname
= context
->active_testname
;
317 context
->active_testname
= talloc_asprintf(context
, "%s-%s", old_testname
, test
->name
);
320 context
->active_tcase
= tcase
;
321 context
->active_test
= test
;
323 torture_ui_test_start(context
, tcase
, test
);
325 context
->last_reason
= NULL
;
326 context
->last_result
= TORTURE_OK
;
328 if (!already_setup
&& tcase
->setup
&&
329 !tcase
->setup(context
, &(tcase
->data
))) {
330 if (context
->last_reason
== NULL
)
331 context
->last_reason
= talloc_strdup(context
, "Setup failure");
332 context
->last_result
= TORTURE_ERROR
;
334 } else if (test
->dangerous
&&
335 !torture_setting_bool(context
, "dangerous", false)) {
336 context
->last_result
= TORTURE_SKIP
;
337 context
->last_reason
= talloc_asprintf(context
,
338 "disabled %s - enable dangerous tests to use", test
->name
);
341 success
= test
->run(context
, tcase
, test
);
343 if (!success
&& context
->last_result
== TORTURE_OK
) {
344 if (context
->last_reason
== NULL
)
345 context
->last_reason
= talloc_strdup(context
, "Unknown error/failure");
346 context
->last_result
= TORTURE_ERROR
;
350 if (!already_setup
&& tcase
->teardown
&& !tcase
->teardown(context
, tcase
->data
)) {
351 if (context
->last_reason
== NULL
)
352 context
->last_reason
= talloc_strdup(context
, "Setup failure");
353 context
->last_result
= TORTURE_ERROR
;
357 torture_ui_test_result(context
, context
->last_result
,
358 context
->last_reason
);
360 talloc_free(context
->last_reason
);
362 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
363 talloc_free(context
->active_testname
);
364 context
->active_testname
= old_testname
;
366 context
->active_test
= NULL
;
367 context
->active_tcase
= NULL
;
372 bool torture_run_tcase(struct torture_context
*context
,
373 struct torture_tcase
*tcase
)
377 struct torture_test
*test
;
381 context
->active_tcase
= tcase
;
382 if (context
->results
->ui_ops
->tcase_start
)
383 context
->results
->ui_ops
->tcase_start(context
, tcase
);
385 if (tcase
->fixture_persistent
&& tcase
->setup
386 && !tcase
->setup(context
, &tcase
->data
)) {
387 /* FIXME: Use torture ui ops for reporting this error */
388 fprintf(stderr
, "Setup failed: ");
389 if (context
->last_reason
!= NULL
)
390 fprintf(stderr
, "%s", context
->last_reason
);
391 fprintf(stderr
, "\n");
396 old_testname
= context
->active_testname
;
397 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
398 old_testname
, tcase
->name
);
399 for (test
= tcase
->tests
; test
; test
= test
->next
) {
400 ret
&= internal_torture_run_test(context
, tcase
, test
,
401 tcase
->fixture_persistent
);
403 talloc_free(context
->active_testname
);
404 context
->active_testname
= old_testname
;
406 if (tcase
->fixture_persistent
&& tcase
->teardown
&&
407 !tcase
->teardown(context
, tcase
->data
))
411 context
->active_tcase
= NULL
;
413 if (context
->results
->ui_ops
->tcase_finish
)
414 context
->results
->ui_ops
->tcase_finish(context
, tcase
);
421 bool torture_run_test(struct torture_context
*context
,
422 struct torture_tcase
*tcase
,
423 struct torture_test
*test
)
425 return internal_torture_run_test(context
, tcase
, test
, false);
428 int torture_setting_int(struct torture_context
*test
, const char *name
,
431 return lp_parm_int(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
434 double torture_setting_double(struct torture_context
*test
, const char *name
,
435 double default_value
)
437 return lp_parm_double(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
440 bool torture_setting_bool(struct torture_context
*test
, const char *name
,
443 return lp_parm_bool(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
446 const char *torture_setting_string(struct torture_context
*test
,
448 const char *default_value
)
452 SMB_ASSERT(test
!= NULL
);
453 SMB_ASSERT(test
->lp_ctx
!= NULL
);
455 ret
= lp_parm_string(test
->lp_ctx
, NULL
, "torture", name
);
458 return default_value
;
463 static bool wrap_test_with_simple_tcase_const (
464 struct torture_context
*torture_ctx
,
465 struct torture_tcase
*tcase
,
466 struct torture_test
*test
)
468 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
472 return fn(torture_ctx
, test
->data
);
475 struct torture_tcase
*torture_suite_add_simple_tcase_const(
476 struct torture_suite
*suite
, const char *name
,
477 bool (*run
) (struct torture_context
*test
, const void *),
480 struct torture_tcase
*tcase
;
481 struct torture_test
*test
;
483 tcase
= torture_suite_add_tcase(suite
, name
);
485 test
= talloc(tcase
, struct torture_test
);
487 test
->name
= talloc_strdup(test
, name
);
488 test
->description
= NULL
;
489 test
->run
= wrap_test_with_simple_tcase_const
;
492 test
->dangerous
= false;
494 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
499 static bool wrap_simple_test(struct torture_context
*torture_ctx
,
500 struct torture_tcase
*tcase
,
501 struct torture_test
*test
)
503 bool (*fn
) (struct torture_context
*);
507 return fn(torture_ctx
);
510 struct torture_tcase
*torture_suite_add_simple_test(
511 struct torture_suite
*suite
,
513 bool (*run
) (struct torture_context
*test
))
515 struct torture_test
*test
;
516 struct torture_tcase
*tcase
;
518 tcase
= torture_suite_add_tcase(suite
, name
);
520 test
= talloc(tcase
, struct torture_test
);
522 test
->name
= talloc_strdup(test
, name
);
523 test
->description
= NULL
;
524 test
->run
= wrap_simple_test
;
526 test
->dangerous
= false;
528 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
534 * Add a child testsuite to a testsuite.
536 bool torture_suite_add_suite(struct torture_suite
*suite
,
537 struct torture_suite
*child
)
542 DLIST_ADD_END(suite
->children
, child
, struct torture_suite
*);
544 /* FIXME: Check for duplicates and return false if the
545 * added suite already exists as a child */
551 * Find the child testsuite with the specified name.
553 struct torture_suite
*torture_find_suite(struct torture_suite
*parent
,
556 struct torture_suite
*child
;
558 for (child
= parent
->children
; child
; child
= child
->next
)
559 if (!strcmp(child
->name
, name
))
565 static bool wrap_test_with_simple_test_const(struct torture_context
*torture_ctx
,
566 struct torture_tcase
*tcase
,
567 struct torture_test
*test
)
569 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
573 return fn(torture_ctx
, tcase
->data
);
576 struct torture_test
*torture_tcase_add_simple_test_const(
577 struct torture_tcase
*tcase
,
579 bool (*run
) (struct torture_context
*test
,
580 const void *tcase_data
))
582 struct torture_test
*test
;
584 test
= talloc(tcase
, struct torture_test
);
586 test
->name
= talloc_strdup(test
, name
);
587 test
->description
= NULL
;
588 test
->run
= wrap_test_with_simple_test_const
;
591 test
->dangerous
= false;
593 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
598 static bool wrap_test_with_simple_test(struct torture_context
*torture_ctx
,
599 struct torture_tcase
*tcase
,
600 struct torture_test
*test
)
602 bool (*fn
) (struct torture_context
*, void *tcase_data
);
606 return fn(torture_ctx
, tcase
->data
);
609 struct torture_test
*torture_tcase_add_simple_test(struct torture_tcase
*tcase
,
611 bool (*run
) (struct torture_context
*test
, void *tcase_data
))
613 struct torture_test
*test
;
615 test
= talloc(tcase
, struct torture_test
);
617 test
->name
= talloc_strdup(test
, name
);
618 test
->description
= NULL
;
619 test
->run
= wrap_test_with_simple_test
;
622 test
->dangerous
= false;
624 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);