s3:printing: Allow to run samba-bgqd as a standalone systemd service
[Samba.git] / lib / torture / torture.c
blob41226ef75047ebc0de3a4cc5cedfafa318ca155a
1 /*
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;
36 if (ui_ops->init)
37 ui_ops->init(results);
39 return results;
42 /**
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);
51 if (torture == NULL)
52 return NULL;
54 torture->ev = event_ctx;
55 torture->results = talloc_reference(torture, results);
58 * We start with an empty subunit prefix
60 torture_subunit_prefix_reset(torture, NULL);
62 return torture;
65 /**
66 * Create a sub torture context
68 struct torture_context *torture_context_child(struct torture_context *parent)
70 struct torture_context *subtorture = talloc_zero(parent, struct torture_context);
72 if (subtorture == NULL)
73 return NULL;
75 subtorture->ev = talloc_reference(subtorture, parent->ev);
76 subtorture->lp_ctx = talloc_reference(subtorture, parent->lp_ctx);
77 subtorture->outputdir = talloc_reference(subtorture, parent->outputdir);
78 subtorture->results = talloc_reference(subtorture, parent->results);
80 return subtorture;
83 /**
84 create a temporary directory under the output dir
86 _PUBLIC_ NTSTATUS torture_temp_dir(struct torture_context *tctx,
87 const char *prefix, char **tempdir)
89 SMB_ASSERT(tctx->outputdir != NULL);
91 *tempdir = talloc_asprintf(tctx, "%s/%s.XXXXXX", tctx->outputdir,
92 prefix);
93 NT_STATUS_HAVE_NO_MEMORY(*tempdir);
95 if (mkdtemp(*tempdir) == NULL) {
96 return map_nt_error_from_unix_common(errno);
99 return NT_STATUS_OK;
102 static int local_deltree(const char *path)
104 int ret = 0;
105 struct dirent *dirent;
106 DIR *dir = opendir(path);
107 if (!dir) {
108 char *error = talloc_asprintf(NULL, "Could not open directory %s", path);
109 perror(error);
110 talloc_free(error);
111 return -1;
113 while ((dirent = readdir(dir))) {
114 char *name;
115 if ((strcmp(dirent->d_name, ".") == 0) || (strcmp(dirent->d_name, "..") == 0)) {
116 continue;
118 name = talloc_asprintf(NULL, "%s/%s", path,
119 dirent->d_name);
120 if (name == NULL) {
121 closedir(dir);
122 return -1;
124 DEBUG(0, ("About to remove %s\n", name));
125 ret = remove(name);
126 if (ret == 0) {
127 talloc_free(name);
128 continue;
131 if (errno == ENOTEMPTY) {
132 ret = local_deltree(name);
133 if (ret == 0) {
134 ret = remove(name);
137 talloc_free(name);
138 if (ret != 0) {
139 char *error = talloc_asprintf(NULL, "Could not remove %s", path);
140 perror(error);
141 talloc_free(error);
142 break;
145 closedir(dir);
146 rmdir(path);
147 return ret;
150 _PUBLIC_ NTSTATUS torture_deltree_outputdir(struct torture_context *tctx)
152 if (tctx->outputdir == NULL) {
153 return NT_STATUS_OK;
155 if ((strcmp(tctx->outputdir, "/") == 0)
156 || (strcmp(tctx->outputdir, "") == 0)) {
157 return NT_STATUS_INVALID_PARAMETER;
160 if (local_deltree(tctx->outputdir) == -1) {
161 if (errno != 0) {
162 return map_nt_error_from_unix_common(errno);
164 return NT_STATUS_UNSUCCESSFUL;
166 return NT_STATUS_OK;
170 * Comment on the status/progress of a test
172 void torture_comment(struct torture_context *context, const char *comment, ...)
174 va_list ap;
175 char *tmp;
177 if (!context->results->ui_ops->comment)
178 return;
180 va_start(ap, comment);
181 tmp = talloc_vasprintf(context, comment, ap);
182 va_end(ap);
184 context->results->ui_ops->comment(context, tmp);
186 talloc_free(tmp);
190 * Print a warning about the current test
192 void torture_warning(struct torture_context *context, const char *comment, ...)
194 va_list ap;
195 char *tmp;
197 if (!context->results->ui_ops->warning)
198 return;
200 va_start(ap, comment);
201 tmp = talloc_vasprintf(context, comment, ap);
202 va_end(ap);
204 context->results->ui_ops->warning(context, tmp);
206 talloc_free(tmp);
210 * Store the result of a torture test.
212 void torture_result(struct torture_context *context,
213 enum torture_result result, const char *fmt, ...)
215 /* Of the two outcomes, keep that with the higher priority. */
216 if (result >= context->last_result) {
217 va_list ap;
219 va_start(ap, fmt);
221 if (context->last_reason) {
222 torture_warning(context, "%s", context->last_reason);
223 talloc_free(context->last_reason);
226 context->last_result = result;
227 context->last_reason = talloc_vasprintf(context, fmt, ap);
229 va_end(ap);
234 * Create a new torture suite
236 struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name)
238 struct torture_suite *suite = talloc_zero(ctx, struct torture_suite);
240 suite->name = talloc_strdup(suite, name);
241 suite->testcases = NULL;
242 suite->children = NULL;
244 return suite;
248 * Set the setup() and teardown() functions for a testcase.
250 void torture_tcase_set_fixture(struct torture_tcase *tcase,
251 bool (*setup) (struct torture_context *, void **),
252 bool (*teardown) (struct torture_context *, void *))
254 tcase->setup = setup;
255 tcase->teardown = teardown;
258 static bool wrap_test_with_testcase_const(struct torture_context *torture_ctx,
259 struct torture_tcase *tcase,
260 struct torture_test *test)
262 bool (*fn) (struct torture_context *,
263 const void *tcase_data,
264 const void *test_data);
266 fn = test->fn;
268 return fn(torture_ctx, tcase->data, test->data);
272 * Add a test that uses const data to a testcase
274 struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase,
275 const char *name,
276 bool (*run) (struct torture_context *, const void *tcase_data,
277 const void *test_data),
278 const void *data)
280 struct torture_test *test = talloc(tcase, struct torture_test);
282 test->name = talloc_strdup(test, name);
283 test->description = NULL;
284 test->run = wrap_test_with_testcase_const;
285 test->fn = run;
286 test->dangerous = false;
287 test->data = data;
289 DLIST_ADD_END(tcase->tests, test);
291 return test;
295 * Add a new testcase
297 bool torture_suite_init_tcase(struct torture_suite *suite,
298 struct torture_tcase *tcase,
299 const char *name)
301 tcase->name = talloc_strdup(tcase, name);
302 tcase->description = NULL;
303 tcase->setup = NULL;
304 tcase->teardown = NULL;
305 tcase->fixture_persistent = true;
306 tcase->tests = NULL;
308 DLIST_ADD_END(suite->testcases, tcase);
309 tcase->suite = suite;
311 return true;
315 struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite,
316 const char *name)
318 struct torture_tcase *tcase = talloc(suite, struct torture_tcase);
320 if (!torture_suite_init_tcase(suite, tcase, name))
321 return NULL;
323 return tcase;
326 char *torture_subunit_test_name(struct torture_context *ctx,
327 struct torture_tcase *tcase,
328 struct torture_test *test)
330 if (!strcmp(tcase->name, test->name)) {
331 return talloc_asprintf(ctx, "%s%s",
332 ctx->active_prefix->subunit_prefix,
333 test->name);
334 } else {
335 return talloc_asprintf(ctx, "%s%s.%s",
336 ctx->active_prefix->subunit_prefix,
337 tcase->name, test->name);
341 void torture_subunit_prefix_reset(struct torture_context *ctx,
342 const char *name)
344 struct torture_subunit_prefix *prefix = &ctx->_initial_prefix;
346 ZERO_STRUCTP(prefix);
348 if (name != NULL) {
349 int ret;
351 ret = snprintf(prefix->subunit_prefix,
352 sizeof(prefix->subunit_prefix),
353 "%s.", name);
354 if (ret < 0) {
355 abort();
359 ctx->active_prefix = prefix;
362 static void torture_subunit_prefix_push(struct torture_context *ctx,
363 struct torture_subunit_prefix *prefix,
364 const char *name)
366 *prefix = (struct torture_subunit_prefix) {
367 .parent = ctx->active_prefix,
370 if (ctx->active_prefix->parent != NULL ||
371 ctx->active_prefix->subunit_prefix[0] != '\0') {
373 * We need a new component for the prefix.
375 int ret;
377 ret = snprintf(prefix->subunit_prefix,
378 sizeof(prefix->subunit_prefix),
379 "%s%s.",
380 ctx->active_prefix->subunit_prefix,
381 name);
382 if (ret < 0) {
383 abort();
387 ctx->active_prefix = prefix;
390 static void torture_subunit_prefix_pop(struct torture_context *ctx)
392 ctx->active_prefix = ctx->active_prefix->parent;
395 int torture_suite_children_count(const struct torture_suite *suite)
397 int ret = 0;
398 struct torture_tcase *tcase;
399 struct torture_test *test;
400 struct torture_suite *tsuite;
401 for (tcase = suite->testcases; tcase; tcase = tcase->next) {
402 for (test = tcase->tests; test; test = test->next) {
403 ret++;
406 for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
407 ret ++;
409 return ret;
413 * Run a torture test suite.
415 bool torture_run_suite(struct torture_context *context,
416 struct torture_suite *suite)
418 return torture_run_suite_restricted(context, suite, NULL);
421 bool torture_run_suite_restricted(struct torture_context *context,
422 struct torture_suite *suite, const char **restricted)
424 struct torture_subunit_prefix _prefix_stack;
425 bool ret = true;
426 struct torture_tcase *tcase;
427 struct torture_suite *tsuite;
429 torture_subunit_prefix_push(context, &_prefix_stack, suite->name);
431 if (context->results->ui_ops->suite_start)
432 context->results->ui_ops->suite_start(context, suite);
434 /* FIXME: Adjust torture_suite_children_count if restricted != NULL */
435 context->results->ui_ops->progress(context,
436 torture_suite_children_count(suite), TORTURE_PROGRESS_SET);
438 for (tcase = suite->testcases; tcase; tcase = tcase->next) {
439 ret &= torture_run_tcase_restricted(context, tcase, restricted);
442 for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
443 context->results->ui_ops->progress(context, 0, TORTURE_PROGRESS_PUSH);
444 ret &= torture_run_suite_restricted(context, tsuite, restricted);
445 context->results->ui_ops->progress(context, 0, TORTURE_PROGRESS_POP);
448 if (context->results->ui_ops->suite_finish)
449 context->results->ui_ops->suite_finish(context, suite);
451 torture_subunit_prefix_pop(context);
453 return ret;
456 void torture_ui_test_start(struct torture_context *context,
457 struct torture_tcase *tcase,
458 struct torture_test *test)
460 if (context->results->ui_ops->test_start)
461 context->results->ui_ops->test_start(context, tcase, test);
464 void torture_ui_test_result(struct torture_context *context,
465 enum torture_result result,
466 const char *comment)
468 if (context->results->ui_ops->test_result)
469 context->results->ui_ops->test_result(context, result, comment);
471 if (result == TORTURE_ERROR || result == TORTURE_FAIL)
472 context->results->returncode = false;
475 static bool test_needs_running(const char *name, const char **restricted)
477 int i;
478 if (restricted == NULL)
479 return true;
480 for (i = 0; restricted[i]; i++) {
481 if (!strcmp(name, restricted[i]))
482 return true;
484 return false;
487 static bool internal_torture_run_test(struct torture_context *context,
488 struct torture_tcase *tcase,
489 struct torture_test *test,
490 bool already_setup,
491 const char **restricted)
493 bool success;
494 char *subunit_testname = torture_subunit_test_name(context, tcase, test);
496 if (!test_needs_running(subunit_testname, restricted))
497 return true;
499 context->active_tcase = tcase;
500 context->active_test = test;
502 torture_ui_test_start(context, tcase, test);
504 context->last_reason = NULL;
505 context->last_result = TORTURE_OK;
507 if (!already_setup && tcase->setup &&
508 !tcase->setup(context, &(tcase->data))) {
509 if (context->last_reason == NULL)
510 context->last_reason = talloc_strdup(context, "Setup failure");
511 context->last_result = TORTURE_ERROR;
512 success = false;
513 } else if (test->dangerous &&
514 !torture_setting_bool(context, "dangerous", false)) {
515 context->last_result = TORTURE_SKIP;
516 context->last_reason = talloc_asprintf(context,
517 "disabled %s - enable dangerous tests to use", test->name);
518 success = true;
519 } else {
520 success = test->run(context, tcase, test);
522 if (!success && context->last_result == TORTURE_OK) {
523 if (context->last_reason == NULL)
524 context->last_reason = talloc_strdup(context,
525 "Unknown error/failure. Missing torture_fail() or torture_assert_*() call?");
526 context->last_result = TORTURE_ERROR;
530 if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data)) {
531 if (context->last_reason == NULL)
532 context->last_reason = talloc_strdup(context, "Setup failure");
533 context->last_result = TORTURE_ERROR;
534 success = false;
537 torture_ui_test_result(context, context->last_result,
538 context->last_reason);
540 talloc_free(context->last_reason);
541 context->last_reason = NULL;
543 context->active_test = NULL;
544 context->active_tcase = NULL;
546 return success;
549 bool torture_run_tcase(struct torture_context *context,
550 struct torture_tcase *tcase)
552 return torture_run_tcase_restricted(context, tcase, NULL);
555 bool torture_run_tcase_restricted(struct torture_context *context,
556 struct torture_tcase *tcase, const char **restricted)
558 bool ret = true;
559 struct torture_test *test;
560 bool setup_succeeded = true;
561 const char * setup_reason = "Setup failed";
563 context->active_tcase = tcase;
564 if (context->results->ui_ops->tcase_start)
565 context->results->ui_ops->tcase_start(context, tcase);
567 if (tcase->fixture_persistent && tcase->setup) {
568 setup_succeeded = tcase->setup(context, &tcase->data);
571 if (!setup_succeeded) {
572 /* Uh-oh. The setup failed, so we can't run any of the tests
573 * in this testcase. The subunit format doesn't specify what
574 * to do here, so we keep the failure reason, and manually
575 * use it to fail every test.
577 if (context->last_reason != NULL) {
578 setup_reason = talloc_asprintf(context,
579 "Setup failed: %s", context->last_reason);
583 for (test = tcase->tests; test; test = test->next) {
584 if (setup_succeeded) {
585 ret &= internal_torture_run_test(context, tcase, test,
586 tcase->fixture_persistent, restricted);
587 } else {
588 context->active_tcase = tcase;
589 context->active_test = test;
590 torture_ui_test_start(context, tcase, test);
591 torture_ui_test_result(context, TORTURE_FAIL, setup_reason);
595 if (setup_succeeded && tcase->fixture_persistent && tcase->teardown &&
596 !tcase->teardown(context, tcase->data)) {
597 ret = false;
600 context->active_tcase = NULL;
601 context->active_test = NULL;
603 if (context->results->ui_ops->tcase_finish)
604 context->results->ui_ops->tcase_finish(context, tcase);
606 return (!setup_succeeded) ? false : ret;
609 bool torture_run_test(struct torture_context *context,
610 struct torture_tcase *tcase,
611 struct torture_test *test)
613 return internal_torture_run_test(context, tcase, test, false, NULL);
616 bool torture_run_test_restricted(struct torture_context *context,
617 struct torture_tcase *tcase,
618 struct torture_test *test,
619 const char **restricted)
621 return internal_torture_run_test(context, tcase, test, false, restricted);
624 int torture_setting_int(struct torture_context *test, const char *name,
625 int default_value)
627 return lpcfg_parm_int(test->lp_ctx, NULL, "torture", name, default_value);
630 unsigned long torture_setting_ulong(struct torture_context *test,
631 const char *name,
632 unsigned long default_value)
634 return lpcfg_parm_ulong(test->lp_ctx, NULL, "torture", name,
635 default_value);
638 double torture_setting_double(struct torture_context *test, const char *name,
639 double default_value)
641 return lpcfg_parm_double(test->lp_ctx, NULL, "torture", name, default_value);
644 bool torture_setting_bool(struct torture_context *test, const char *name,
645 bool default_value)
647 return lpcfg_parm_bool(test->lp_ctx, NULL, "torture", name, default_value);
650 const char *torture_setting_string(struct torture_context *test,
651 const char *name,
652 const char *default_value)
654 const char *ret;
656 SMB_ASSERT(test != NULL);
657 SMB_ASSERT(test->lp_ctx != NULL);
659 ret = lpcfg_parm_string(test->lp_ctx, NULL, "torture", name);
661 if (ret == NULL)
662 return default_value;
664 return ret;
667 static bool wrap_test_with_simple_tcase_const (
668 struct torture_context *torture_ctx,
669 struct torture_tcase *tcase,
670 struct torture_test *test)
672 bool (*fn) (struct torture_context *, const void *tcase_data);
674 fn = test->fn;
676 return fn(torture_ctx, test->data);
679 struct torture_tcase *torture_suite_add_simple_tcase_const(
680 struct torture_suite *suite, const char *name,
681 bool (*run) (struct torture_context *test, const void *),
682 const void *data)
684 struct torture_tcase *tcase;
685 struct torture_test *test;
687 tcase = torture_suite_add_tcase(suite, name);
689 test = talloc(tcase, struct torture_test);
691 test->name = talloc_strdup(test, name);
692 test->description = NULL;
693 test->run = wrap_test_with_simple_tcase_const;
694 test->fn = run;
695 test->data = data;
696 test->dangerous = false;
698 DLIST_ADD_END(tcase->tests, test);
699 test->tcase = tcase;
701 return tcase;
704 static bool wrap_simple_test(struct torture_context *torture_ctx,
705 struct torture_tcase *tcase,
706 struct torture_test *test)
708 bool (*fn) (struct torture_context *);
710 fn = test->fn;
712 return fn(torture_ctx);
715 struct torture_tcase *torture_suite_add_simple_test(
716 struct torture_suite *suite,
717 const char *name,
718 bool (*run) (struct torture_context *test))
720 struct torture_test *test;
721 struct torture_tcase *tcase;
723 tcase = torture_suite_add_tcase(suite, name);
725 test = talloc(tcase, struct torture_test);
727 test->name = talloc_strdup(test, name);
728 test->description = NULL;
729 test->run = wrap_simple_test;
730 test->fn = run;
731 test->dangerous = false;
733 DLIST_ADD_END(tcase->tests, test);
735 return tcase;
739 * Add a child testsuite to a testsuite.
741 bool torture_suite_add_suite(struct torture_suite *suite,
742 struct torture_suite *child)
744 if (child == NULL)
745 return false;
747 DLIST_ADD_END(suite->children, child);
748 child->parent = suite;
750 /* FIXME: Check for duplicates and return false if the
751 * added suite already exists as a child */
753 return true;
757 * Find the child testsuite with the specified name.
759 struct torture_suite *torture_find_suite(struct torture_suite *parent,
760 const char *name)
762 struct torture_suite *child;
764 for (child = parent->children; child; child = child->next)
765 if (!strcmp(child->name, name))
766 return child;
768 return NULL;
771 static bool wrap_test_with_simple_test_const(struct torture_context *torture_ctx,
772 struct torture_tcase *tcase,
773 struct torture_test *test)
775 bool (*fn) (struct torture_context *, const void *tcase_data);
777 fn = test->fn;
779 return fn(torture_ctx, tcase->data);
782 struct torture_test *torture_tcase_add_simple_test_const(
783 struct torture_tcase *tcase,
784 const char *name,
785 bool (*run) (struct torture_context *test,
786 const void *tcase_data))
788 struct torture_test *test;
790 test = talloc(tcase, struct torture_test);
792 test->name = talloc_strdup(test, name);
793 test->description = NULL;
794 test->run = wrap_test_with_simple_test_const;
795 test->fn = run;
796 test->data = NULL;
797 test->dangerous = false;
799 DLIST_ADD_END(tcase->tests, test);
801 return test;
804 static bool wrap_test_with_simple_test(struct torture_context *torture_ctx,
805 struct torture_tcase *tcase,
806 struct torture_test *test)
808 bool (*fn) (struct torture_context *, void *tcase_data);
810 fn = test->fn;
812 return fn(torture_ctx, tcase->data);
815 struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase,
816 const char *name,
817 bool (*run) (struct torture_context *test, void *tcase_data))
819 struct torture_test *test;
821 test = talloc(tcase, struct torture_test);
823 test->name = talloc_strdup(test, name);
824 test->description = NULL;
825 test->run = wrap_test_with_simple_test;
826 test->fn = run;
827 test->data = NULL;
828 test->dangerous = false;
830 DLIST_ADD_END(tcase->tests, test);
832 return test;
835 void torture_ui_report_time(struct torture_context *context)
837 if (context->results->ui_ops->report_time)
838 context->results->ui_ops->report_time(context);