2 Unix SMB/CIFS implementation.
3 SMB torture UI functions
5 Copyright (C) Jelmer Vernooij 2006
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/>.
22 #include "torture/torture.h"
23 #include "../lib/util/dlinklist.h"
24 #include "param/param.h"
25 #include "system/filesys.h"
28 * Initialize a torture context
30 struct torture_context *torture_context_init(struct event_context *event_ctx,
31 const struct torture_ui_ops *ui_ops)
33 struct torture_context *torture = talloc_zero(event_ctx,
34 struct torture_context);
35 torture->ui_ops = ui_ops;
36 torture->returncode = true;
37 torture->ev = event_ctx;
40 ui_ops->init(torture);
46 create a temporary directory.
48 _PUBLIC_ NTSTATUS torture_temp_dir(struct torture_context *tctx,
52 SMB_ASSERT(tctx->outputdir != NULL);
54 *tempdir = talloc_asprintf(tctx, "%s/%s.XXXXXX", tctx->outputdir,
56 NT_STATUS_HAVE_NO_MEMORY(*tempdir);
58 if (mkdtemp(*tempdir) == NULL) {
59 return map_nt_error_from_unix(errno);
66 * Comment on the status/progress of a test
68 void torture_comment(struct torture_context *context, const char *comment, ...)
73 if (!context->ui_ops->comment)
76 va_start(ap, comment);
77 tmp = talloc_vasprintf(context, comment, ap);
79 context->ui_ops->comment(context, tmp);
85 * Print a warning about the current test
87 void torture_warning(struct torture_context *context, const char *comment, ...)
92 if (!context->ui_ops->warning)
95 va_start(ap, comment);
96 tmp = talloc_vasprintf(context, comment, ap);
98 context->ui_ops->warning(context, tmp);
104 * Store the result of a torture test.
106 void torture_result(struct torture_context *context,
107 enum torture_result result, const char *fmt, ...)
113 if (context->last_reason) {
114 torture_warning(context, "%s", context->last_reason);
115 talloc_free(context->last_reason);
118 context->last_result = result;
119 context->last_reason = talloc_vasprintf(context, fmt, ap);
124 * Create a new torture suite
126 struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name)
128 struct torture_suite *suite = talloc_zero(ctx, struct torture_suite);
130 suite->name = talloc_strdup(suite, name);
131 suite->testcases = NULL;
132 suite->children = NULL;
138 * Set the setup() and teardown() functions for a testcase.
140 void torture_tcase_set_fixture(struct torture_tcase *tcase,
141 bool (*setup) (struct torture_context *, void **),
142 bool (*teardown) (struct torture_context *, void *))
144 tcase->setup = setup;
145 tcase->teardown = teardown;
148 static bool wrap_test_with_testcase_const(struct torture_context *torture_ctx,
149 struct torture_tcase *tcase,
150 struct torture_test *test)
152 bool (*fn) (struct torture_context *,
153 const void *tcase_data,
154 const void *test_data);
158 return fn(torture_ctx, tcase->data, test->data);
162 * Add a test that uses const data to a testcase
164 struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase,
166 bool (*run) (struct torture_context *, const void *tcase_data,
167 const void *test_data),
170 struct torture_test *test = talloc(tcase, struct torture_test);
172 test->name = talloc_strdup(test, name);
173 test->description = NULL;
174 test->run = wrap_test_with_testcase_const;
176 test->dangerous = false;
179 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
187 bool torture_suite_init_tcase(struct torture_suite *suite,
188 struct torture_tcase *tcase,
191 tcase->name = talloc_strdup(tcase, name);
192 tcase->description = NULL;
194 tcase->teardown = NULL;
195 tcase->fixture_persistent = true;
198 DLIST_ADD_END(suite->testcases, tcase, struct torture_tcase *);
204 struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite,
207 struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
209 if (!torture_suite_init_tcase(suite, tcase, name))
216 * Run a torture test suite.
218 bool torture_run_suite(struct torture_context *context,
219 struct torture_suite *suite)
222 struct torture_tcase *tcase;
223 struct torture_suite *tsuite;
227 if (context->ui_ops->suite_start)
228 context->ui_ops->suite_start(context, suite);
230 old_testname = context->active_testname;
231 if (old_testname != NULL)
232 context->active_testname = talloc_asprintf(context, "%s-%s",
233 old_testname, suite->name);
235 context->active_testname = talloc_strdup(context, suite->name);
237 for (tcase = suite->testcases; tcase; tcase = tcase->next) {
238 ret &= torture_run_tcase(context, tcase);
241 for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
242 ret &= torture_run_suite(context, tsuite);
245 talloc_free(context->active_testname);
246 context->active_testname = old_testname;
248 if (context->ui_ops->suite_finish)
249 context->ui_ops->suite_finish(context, suite);
256 void torture_ui_test_start(struct torture_context *context,
257 struct torture_tcase *tcase,
258 struct torture_test *test)
260 if (context->ui_ops->test_start)
261 context->ui_ops->test_start(context, tcase, test);
264 void torture_ui_test_result(struct torture_context *context,
265 enum torture_result result,
268 if (context->ui_ops->test_result)
269 context->ui_ops->test_result(context, result, comment);
271 if (result == TORTURE_ERROR || result == TORTURE_FAIL)
272 context->returncode = false;
275 static bool internal_torture_run_test(struct torture_context *context,
276 struct torture_tcase *tcase,
277 struct torture_test *test,
283 if (tcase == NULL || strcmp(test->name, tcase->name) != 0) {
284 old_testname = context->active_testname;
285 context->active_testname = talloc_asprintf(context, "%s-%s", old_testname, test->name);
288 context->active_tcase = tcase;
289 context->active_test = test;
291 torture_ui_test_start(context, tcase, test);
293 context->last_reason = NULL;
294 context->last_result = TORTURE_OK;
296 if (!already_setup && tcase->setup &&
297 !tcase->setup(context, &(tcase->data))) {
298 if (context->last_reason == NULL)
299 context->last_reason = talloc_strdup(context, "Setup failure");
300 context->last_result = TORTURE_ERROR;
302 } else if (test->dangerous &&
303 !torture_setting_bool(context, "dangerous", false)) {
304 context->last_result = TORTURE_SKIP;
305 context->last_reason = talloc_asprintf(context,
306 "disabled %s - enable dangerous tests to use", test->name);
309 success = test->run(context, tcase, test);
311 if (!success && context->last_result == TORTURE_OK) {
312 if (context->last_reason == NULL)
313 context->last_reason = talloc_strdup(context, "Unknown error/failure");
314 context->last_result = TORTURE_ERROR;
318 if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data)) {
319 if (context->last_reason == NULL)
320 context->last_reason = talloc_strdup(context, "Setup failure");
321 context->last_result = TORTURE_ERROR;
325 torture_ui_test_result(context, context->last_result,
326 context->last_reason);
328 talloc_free(context->last_reason);
330 if (tcase == NULL || strcmp(test->name, tcase->name) != 0) {
331 talloc_free(context->active_testname);
332 context->active_testname = old_testname;
334 context->active_test = NULL;
335 context->active_tcase = NULL;
340 bool torture_run_tcase(struct torture_context *context,
341 struct torture_tcase *tcase)
345 struct torture_test *test;
349 context->active_tcase = tcase;
350 if (context->ui_ops->tcase_start)
351 context->ui_ops->tcase_start(context, tcase);
353 if (tcase->fixture_persistent && tcase->setup
354 && !tcase->setup(context, &tcase->data)) {
355 /* FIXME: Use torture ui ops for reporting this error */
356 fprintf(stderr, "Setup failed: ");
357 if (context->last_reason != NULL)
358 fprintf(stderr, "%s", context->last_reason);
359 fprintf(stderr, "\n");
364 old_testname = context->active_testname;
365 context->active_testname = talloc_asprintf(context, "%s-%s",
366 old_testname, tcase->name);
367 for (test = tcase->tests; test; test = test->next) {
368 ret &= internal_torture_run_test(context, tcase, test,
369 tcase->fixture_persistent);
371 talloc_free(context->active_testname);
372 context->active_testname = old_testname;
374 if (tcase->fixture_persistent && tcase->teardown &&
375 !tcase->teardown(context, tcase->data))
379 context->active_tcase = NULL;
381 if (context->ui_ops->tcase_finish)
382 context->ui_ops->tcase_finish(context, tcase);
389 bool torture_run_test(struct torture_context *context,
390 struct torture_tcase *tcase,
391 struct torture_test *test)
393 return internal_torture_run_test(context, tcase, test, false);
396 int torture_setting_int(struct torture_context *test, const char *name,
399 return lp_parm_int(test->lp_ctx, NULL, "torture", name, default_value);
402 double torture_setting_double(struct torture_context *test, const char *name,
403 double default_value)
405 return lp_parm_double(test->lp_ctx, NULL, "torture", name, default_value);
408 bool torture_setting_bool(struct torture_context *test, const char *name,
411 return lp_parm_bool(test->lp_ctx, NULL, "torture", name, default_value);
414 const char *torture_setting_string(struct torture_context *test,
416 const char *default_value)
420 SMB_ASSERT(test != NULL);
421 SMB_ASSERT(test->lp_ctx != NULL);
423 ret = lp_parm_string(test->lp_ctx, NULL, "torture", name);
426 return default_value;
431 static bool wrap_test_with_simple_tcase_const (
432 struct torture_context *torture_ctx,
433 struct torture_tcase *tcase,
434 struct torture_test *test)
436 bool (*fn) (struct torture_context *, const void *tcase_data);
440 return fn(torture_ctx, test->data);
443 struct torture_tcase *torture_suite_add_simple_tcase_const(
444 struct torture_suite *suite, const char *name,
445 bool (*run) (struct torture_context *test, const void *),
448 struct torture_tcase *tcase;
449 struct torture_test *test;
451 tcase = torture_suite_add_tcase(suite, name);
453 test = talloc(tcase, struct torture_test);
455 test->name = talloc_strdup(test, name);
456 test->description = NULL;
457 test->run = wrap_test_with_simple_tcase_const;
460 test->dangerous = false;
462 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
467 static bool wrap_simple_test(struct torture_context *torture_ctx,
468 struct torture_tcase *tcase,
469 struct torture_test *test)
471 bool (*fn) (struct torture_context *);
475 return fn(torture_ctx);
478 struct torture_tcase *torture_suite_add_simple_test(
479 struct torture_suite *suite,
481 bool (*run) (struct torture_context *test))
483 struct torture_test *test;
484 struct torture_tcase *tcase;
486 tcase = torture_suite_add_tcase(suite, name);
488 test = talloc(tcase, struct torture_test);
490 test->name = talloc_strdup(test, name);
491 test->description = NULL;
492 test->run = wrap_simple_test;
494 test->dangerous = false;
496 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
502 * Add a child testsuite to a testsuite.
504 bool torture_suite_add_suite(struct torture_suite *suite,
505 struct torture_suite *child)
510 DLIST_ADD_END(suite->children, child, struct torture_suite *);
512 /* FIXME: Check for duplicates and return false if the
513 * added suite already exists as a child */
519 * Find the child testsuite with the specified name.
521 struct torture_suite *torture_find_suite(struct torture_suite *parent,
524 struct torture_suite *child;
526 for (child = parent->children; child; child = child->next)
527 if (!strcmp(child->name, name))
533 static bool wrap_test_with_simple_test_const(struct torture_context *torture_ctx,
534 struct torture_tcase *tcase,
535 struct torture_test *test)
537 bool (*fn) (struct torture_context *, const void *tcase_data);
541 return fn(torture_ctx, tcase->data);
544 struct torture_test *torture_tcase_add_simple_test_const(
545 struct torture_tcase *tcase,
547 bool (*run) (struct torture_context *test,
548 const void *tcase_data))
550 struct torture_test *test;
552 test = talloc(tcase, struct torture_test);
554 test->name = talloc_strdup(test, name);
555 test->description = NULL;
556 test->run = wrap_test_with_simple_test_const;
559 test->dangerous = false;
561 DLIST_ADD_END(tcase->tests, test, struct torture_test *);
566 static bool wrap_test_with_simple_test(struct torture_context *torture_ctx,
567 struct torture_tcase *tcase,
568 struct torture_test *test)
570 bool (*fn) (struct torture_context *, void *tcase_data);
574 return fn(torture_ctx, tcase->data);
577 struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase,
579 bool (*run) (struct torture_context *test, void *tcase_data))
581 struct torture_test *test;
583 test = talloc(tcase, struct torture_test);
585 test->name = talloc_strdup(test, name);
586 test->description = NULL;
587 test->run = wrap_test_with_simple_test;
590 test->dangerous = false;
592 DLIST_ADD_END(tcase->tests, test, struct torture_test *);