Refactor the dns_open_connection code so that duplicate code is removed and ensure...
[sfrench/samba-autobuild/.git] / lib / torture / torture.c
index 0ef5f612e67b45ae21aa13262bc1bf43c875d0dc..40807d92a62151c22e688df12de16377e34a3ed6 100644 (file)
@@ -1,19 +1,19 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
    SMB torture UI functions
 
    Copyright (C) Jelmer Vernooij 2006-2008
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
@@ -23,6 +23,8 @@
 #include "../lib/util/dlinklist.h"
 #include "param/param.h"
 #include "system/filesys.h"
+#include "system/dir.h"
+
 
 struct torture_results *torture_results_init(TALLOC_CTX *mem_ctx, const struct torture_ui_ops *ui_ops)
 {
@@ -40,7 +42,7 @@ struct torture_results *torture_results_init(TALLOC_CTX *mem_ctx, const struct t
 /**
  * Initialize a torture context
  */
-struct torture_context *torture_context_init(struct event_context *event_ctx, 
+struct torture_context *torture_context_init(struct tevent_context *event_ctx, 
                                                                                         struct torture_results *results)
 {
        struct torture_context *torture = talloc_zero(event_ctx, 
@@ -65,35 +67,100 @@ struct torture_context *torture_context_child(struct torture_context *parent)
        if (subtorture == NULL)
                return NULL;
 
-       subtorture->level = parent->level+1;
        subtorture->ev = talloc_reference(subtorture, parent->ev);
        subtorture->lp_ctx = talloc_reference(subtorture, parent->lp_ctx);
        subtorture->outputdir = talloc_reference(subtorture, parent->outputdir);
        subtorture->results = talloc_reference(subtorture, parent->results);
 
        return subtorture;
-}      
+}
 
 /**
- create a temporary directory.
+ create a temporary directory under the output dir
 */
-_PUBLIC_ NTSTATUS torture_temp_dir(struct torture_context *tctx, 
-                                  const char *prefix, 
-                                  char **tempdir)
+_PUBLIC_ NTSTATUS torture_temp_dir(struct torture_context *tctx,
+                                  const char *prefix, char **tempdir)
 {
        SMB_ASSERT(tctx->outputdir != NULL);
 
-       *tempdir = talloc_asprintf(tctx, "%s/%s.XXXXXX", tctx->outputdir, 
+       *tempdir = talloc_asprintf(tctx, "%s/%s.XXXXXX", tctx->outputdir,
                                   prefix);
        NT_STATUS_HAVE_NO_MEMORY(*tempdir);
 
        if (mkdtemp(*tempdir) == NULL) {
-               return map_nt_error_from_unix(errno);
+               return map_nt_error_from_unix_common(errno);
        }
 
        return NT_STATUS_OK;
 }
 
+static int local_deltree(const char *path)
+{
+       int ret = 0;
+       struct dirent *dirent;
+       DIR *dir = opendir(path);
+       if (!dir) {
+               char *error = talloc_asprintf(NULL, "Could not open directory %s", path);
+               perror(error);
+               talloc_free(error);
+               return -1;
+       }
+       while ((dirent = readdir(dir))) {
+               char *name;
+               if ((strcmp(dirent->d_name, ".") == 0) || (strcmp(dirent->d_name, "..") == 0)) {
+                       continue;
+               }
+               name = talloc_asprintf(NULL, "%s/%s", path,
+                                      dirent->d_name);
+               if (name == NULL) {
+                       closedir(dir);
+                       return -1;
+               }
+               DEBUG(0, ("About to remove %s\n", name));
+               ret = remove(name);
+               if (ret == 0) {
+                       talloc_free(name);
+                       continue;
+               }
+
+               if (errno == ENOTEMPTY) {
+                       ret = local_deltree(name);
+                       if (ret == 0) {
+                               ret = remove(name);
+                       }
+               }
+               talloc_free(name);
+               if (ret != 0) {
+                       char *error = talloc_asprintf(NULL, "Could not remove %s", path);
+                       perror(error);
+                       talloc_free(error);
+                       break;
+               }
+       }
+       closedir(dir);
+       rmdir(path);
+       return ret;
+}
+
+_PUBLIC_ NTSTATUS torture_deltree_outputdir(struct torture_context *tctx)
+{
+       if (tctx->outputdir == NULL) {
+               return NT_STATUS_OK;
+       }
+       if ((strcmp(tctx->outputdir, "/") == 0)
+           || (strcmp(tctx->outputdir, "") == 0)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (local_deltree(tctx->outputdir) == -1) {
+               if (errno != 0) {
+                       return map_nt_error_from_unix_common(errno);
+               }
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       return NT_STATUS_OK;
+}
+
 /**
  * Comment on the status/progress of a test
  */
@@ -107,9 +174,10 @@ void torture_comment(struct torture_context *context, const char *comment, ...)
 
        va_start(ap, comment);
        tmp = talloc_vasprintf(context, comment, ap);
-               
+       va_end(ap);
+
        context->results->ui_ops->comment(context, tmp);
-       
+
        talloc_free(tmp);
 }
 
@@ -126,6 +194,7 @@ void torture_warning(struct torture_context *context, const char *comment, ...)
 
        va_start(ap, comment);
        tmp = talloc_vasprintf(context, comment, ap);
+       va_end(ap);
 
        context->results->ui_ops->warning(context, tmp);
 
@@ -208,7 +277,7 @@ struct torture_test *torture_tcase_add_test_const(struct torture_tcase *tcase,
        test->dangerous = false;
        test->data = data;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return test;
 }
@@ -227,7 +296,7 @@ bool torture_suite_init_tcase(struct torture_suite *suite,
        tcase->fixture_persistent = true;
        tcase->tests = NULL;
 
-       DLIST_ADD_END(suite->testcases, tcase, struct torture_tcase *);
+       DLIST_ADD_END(suite->testcases, tcase);
 
        return true;
 }
@@ -244,44 +313,59 @@ struct torture_tcase *torture_suite_add_tcase(struct torture_suite *suite,
        return tcase;
 }
 
+int torture_suite_children_count(const struct torture_suite *suite)
+{
+       int ret = 0;
+       struct torture_tcase *tcase;
+       struct torture_test *test;
+       struct torture_suite *tsuite;
+       for (tcase = suite->testcases; tcase; tcase = tcase->next) {
+               for (test = tcase->tests; test; test = test->next) {
+                       ret++;
+               }
+       }
+       for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
+               ret ++;
+       }
+       return ret;
+}
+
 /**
  * Run a torture test suite.
  */
 bool torture_run_suite(struct torture_context *context, 
                       struct torture_suite *suite)
+{
+       return torture_run_suite_restricted(context, suite, NULL);
+}
+
+bool torture_run_suite_restricted(struct torture_context *context, 
+                      struct torture_suite *suite, const char **restricted)
 {
        bool ret = true;
        struct torture_tcase *tcase;
        struct torture_suite *tsuite;
-       char *old_testname;
 
-       context->level++;
        if (context->results->ui_ops->suite_start)
                context->results->ui_ops->suite_start(context, suite);
 
-       old_testname = context->active_testname;
-       if (old_testname != NULL)
-               context->active_testname = talloc_asprintf(context, "%s-%s", 
-                                                          old_testname, suite->name);
-       else
-               context->active_testname = talloc_strdup(context, suite->name);
+       /* FIXME: Adjust torture_suite_children_count if restricted != NULL */
+       context->results->ui_ops->progress(context,
+               torture_suite_children_count(suite), TORTURE_PROGRESS_SET);
 
        for (tcase = suite->testcases; tcase; tcase = tcase->next) {
-               ret &= torture_run_tcase(context, tcase);
+               ret &= torture_run_tcase_restricted(context, tcase, restricted);
        }
 
        for (tsuite = suite->children; tsuite; tsuite = tsuite->next) {
-               ret &= torture_run_suite(context, tsuite);
+               context->results->ui_ops->progress(context, 0, TORTURE_PROGRESS_PUSH);
+               ret &= torture_run_suite_restricted(context, tsuite, restricted);
+               context->results->ui_ops->progress(context, 0, TORTURE_PROGRESS_POP);
        }
 
-       talloc_free(context->active_testname);
-       context->active_testname = old_testname;
-
        if (context->results->ui_ops->suite_finish)
                context->results->ui_ops->suite_finish(context, suite);
 
-       context->level--;
-       
        return ret;
 }
 
@@ -304,19 +388,36 @@ void torture_ui_test_result(struct torture_context *context,
                context->results->returncode = false;
 }
 
-static bool internal_torture_run_test(struct torture_context *context, 
+static bool test_needs_running(const char *name, const char **restricted)
+{
+       int i;
+       if (restricted == NULL)
+               return true;
+       for (i = 0; restricted[i]; i++) {
+               if (!strcmp(name, restricted[i]))
+                       return true;
+       }
+       return false;
+}
+
+static bool internal_torture_run_test(struct torture_context *context,
                                          struct torture_tcase *tcase,
                                          struct torture_test *test,
-                                         bool already_setup)
+                                         bool already_setup,
+                                         const char **restricted)
 {
        bool success;
-       char *old_testname;
+       char *subunit_testname = NULL;
 
-       if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
-               old_testname = context->active_testname;
-               context->active_testname = talloc_asprintf(context, "%s-%s", old_testname, test->name);
+       if (tcase == NULL || strcmp(test->name, tcase->name) != 0) {
+               subunit_testname = talloc_asprintf(context, "%s.%s", tcase->name, test->name);
+       } else {
+               subunit_testname = talloc_strdup(context, test->name);
        }
 
+       if (!test_needs_running(subunit_testname, restricted))
+               return true;
+
        context->active_tcase = tcase;
        context->active_test = test;
 
@@ -325,122 +426,147 @@ static bool internal_torture_run_test(struct torture_context *context,
        context->last_reason = NULL;
        context->last_result = TORTURE_OK;
 
-       if (!already_setup && tcase->setup && 
-               !tcase->setup(context, &(tcase->data))) {
-               if (context->last_reason == NULL)
+       if (!already_setup && tcase->setup &&
+           !tcase->setup(context, &(tcase->data))) {
+               if (context->last_reason == NULL)
                        context->last_reason = talloc_strdup(context, "Setup failure");
                context->last_result = TORTURE_ERROR;
                success = false;
-       } else if (test->dangerous && 
-           !torture_setting_bool(context, "dangerous", false)) {
-           context->last_result = TORTURE_SKIP;
-           context->last_reason = talloc_asprintf(context, 
-               "disabled %s - enable dangerous tests to use", test->name);
-           success = true;
+       } else if (test->dangerous &&
+                  !torture_setting_bool(context, "dangerous", false)) {
+               context->last_result = TORTURE_SKIP;
+               context->last_reason = talloc_asprintf(context,
+               "disabled %s - enable dangerous tests to use", test->name);
+               success = true;
        } else {
-           success = test->run(context, tcase, test);
-
-           if (!success && context->last_result == TORTURE_OK) {
-                   if (context->last_reason == NULL)
-                           context->last_reason = talloc_strdup(context, "Unknown error/failure");
-                   context->last_result = TORTURE_ERROR;
-           }
+               success = test->run(context, tcase, test);
+
+               if (!success && context->last_result == TORTURE_OK) {
+                       if (context->last_reason == NULL)
+                               context->last_reason = talloc_strdup(context,
+                                       "Unknown error/failure. Missing torture_fail() or torture_assert_*() call?");
+                       context->last_result = TORTURE_ERROR;
+               }
        }
 
        if (!already_setup && tcase->teardown && !tcase->teardown(context, tcase->data)) {
-               if (context->last_reason == NULL)
-                   context->last_reason = talloc_strdup(context, "Setup failure");
-               context->last_result = TORTURE_ERROR;
+               if (context->last_reason == NULL)
+                       context->last_reason = talloc_strdup(context, "Setup failure");
+               context->last_result = TORTURE_ERROR;
                success = false;
        }
 
-       torture_ui_test_result(context, context->last_result, 
+       torture_ui_test_result(context, context->last_result,
                               context->last_reason);
-       
+
        talloc_free(context->last_reason);
+       context->last_reason = NULL;
 
-       if (tcase == NULL || strcmp(test->name, tcase->name) != 0) { 
-               talloc_free(context->active_testname);
-               context->active_testname = old_testname;
-       }
        context->active_test = NULL;
        context->active_tcase = NULL;
 
        return success;
 }
 
-bool torture_run_tcase(struct torture_context *context, 
+bool torture_run_tcase(struct torture_context *context,
                       struct torture_tcase *tcase)
+{
+       return torture_run_tcase_restricted(context, tcase, NULL);
+}
+
+bool torture_run_tcase_restricted(struct torture_context *context,
+                      struct torture_tcase *tcase, const char **restricted)
 {
        bool ret = true;
-       char *old_testname;
        struct torture_test *test;
-
-       context->level++;
+       bool setup_succeeded = true;
+       const char * setup_reason = "Setup failed";
 
        context->active_tcase = tcase;
        if (context->results->ui_ops->tcase_start) 
                context->results->ui_ops->tcase_start(context, tcase);
 
-       if (tcase->fixture_persistent && tcase->setup 
-               && !tcase->setup(context, &tcase->data)) {
-               /* FIXME: Use torture ui ops for reporting this error */
-               fprintf(stderr, "Setup failed: ");
-               if (context->last_reason != NULL)
-                       fprintf(stderr, "%s", context->last_reason);
-               fprintf(stderr, "\n");
-               ret = false;
-               goto done;
+       if (tcase->fixture_persistent && tcase->setup) {
+               setup_succeeded = tcase->setup(context, &tcase->data);
+       }
+
+       if (!setup_succeeded) {
+               /* Uh-oh. The setup failed, so we can't run any of the tests
+                * in this testcase. The subunit format doesn't specify what
+                * to do here, so we keep the failure reason, and manually
+                * use it to fail every test.
+                */
+               if (context->last_reason != NULL) {
+                       setup_reason = talloc_asprintf(context,
+                               "Setup failed: %s", context->last_reason);
+               }
        }
 
-       old_testname = context->active_testname;
-       context->active_testname = talloc_asprintf(context, "%s-%s", 
-                                                  old_testname, tcase->name);
        for (test = tcase->tests; test; test = test->next) {
-               ret &= internal_torture_run_test(context, tcase, test, 
-                               tcase->fixture_persistent);
+               if (setup_succeeded) {
+                       ret &= internal_torture_run_test(context, tcase, test,
+                                       tcase->fixture_persistent, restricted);
+               } else {
+                       context->active_tcase = tcase;
+                       context->active_test = test;
+                       torture_ui_test_start(context, tcase, test);
+                       torture_ui_test_result(context, TORTURE_FAIL, setup_reason);
+               }
        }
-       talloc_free(context->active_testname);
-       context->active_testname = old_testname;
 
-       if (tcase->fixture_persistent && tcase->teardown &&
-               !tcase->teardown(context, tcase->data))
+       if (setup_succeeded && tcase->fixture_persistent && tcase->teardown &&
+               !tcase->teardown(context, tcase->data)) {
                ret = false;
+       }
 
-done:
        context->active_tcase = NULL;
+       context->active_test = NULL;
 
        if (context->results->ui_ops->tcase_finish)
                context->results->ui_ops->tcase_finish(context, tcase);
 
-       context->level--;
-
-       return ret;
+       return (!setup_succeeded) ? false : ret;
 }
 
 bool torture_run_test(struct torture_context *context, 
                                          struct torture_tcase *tcase,
                                          struct torture_test *test)
 {
-       return internal_torture_run_test(context, tcase, test, false);
+       return internal_torture_run_test(context, tcase, test, false, NULL);
+}
+
+bool torture_run_test_restricted(struct torture_context *context, 
+                                         struct torture_tcase *tcase,
+                                         struct torture_test *test,
+                                         const char **restricted)
+{
+       return internal_torture_run_test(context, tcase, test, false, restricted);
 }
 
 int torture_setting_int(struct torture_context *test, const char *name, 
                                                        int default_value)
 {
-       return lp_parm_int(test->lp_ctx, NULL, "torture", name, default_value);
+       return lpcfg_parm_int(test->lp_ctx, NULL, "torture", name, default_value);
+}
+
+unsigned long torture_setting_ulong(struct torture_context *test,
+                                   const char *name,
+                                   unsigned long default_value)
+{
+       return lpcfg_parm_ulong(test->lp_ctx, NULL, "torture", name,
+                            default_value);
 }
 
 double torture_setting_double(struct torture_context *test, const char *name, 
                                                        double default_value)
 {
-       return lp_parm_double(test->lp_ctx, NULL, "torture", name, default_value);
+       return lpcfg_parm_double(test->lp_ctx, NULL, "torture", name, default_value);
 }
 
 bool torture_setting_bool(struct torture_context *test, const char *name, 
                                                        bool default_value)
 {
-       return lp_parm_bool(test->lp_ctx, NULL, "torture", name, default_value);
+       return lpcfg_parm_bool(test->lp_ctx, NULL, "torture", name, default_value);
 }
 
 const char *torture_setting_string(struct torture_context *test, 
@@ -452,7 +578,7 @@ const char *torture_setting_string(struct torture_context *test,
        SMB_ASSERT(test != NULL);
        SMB_ASSERT(test->lp_ctx != NULL);
        
-       ret = lp_parm_string(test->lp_ctx, NULL, "torture", name);
+       ret = lpcfg_parm_string(test->lp_ctx, NULL, "torture", name);
 
        if (ret == NULL)
                return default_value;
@@ -491,7 +617,7 @@ struct torture_tcase *torture_suite_add_simple_tcase_const(
        test->data = data;
        test->dangerous = false;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return tcase;
 }
@@ -525,7 +651,7 @@ struct torture_tcase *torture_suite_add_simple_test(
        test->fn = run;
        test->dangerous = false;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return tcase;
 }
@@ -539,7 +665,7 @@ bool torture_suite_add_suite(struct torture_suite *suite,
        if (child == NULL)
                return false;
 
-       DLIST_ADD_END(suite->children, child, struct torture_suite *);
+       DLIST_ADD_END(suite->children, child);
 
        /* FIXME: Check for duplicates and return false if the 
         * added suite already exists as a child */
@@ -590,7 +716,7 @@ struct torture_test *torture_tcase_add_simple_test_const(
        test->data = NULL;
        test->dangerous = false;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return test;
 }
@@ -621,7 +747,13 @@ struct torture_test *torture_tcase_add_simple_test(struct torture_tcase *tcase,
        test->data = NULL;
        test->dangerous = false;
 
-       DLIST_ADD_END(tcase->tests, test, struct torture_test *);
+       DLIST_ADD_END(tcase->tests, test);
 
        return test;
 }
+
+void torture_ui_report_time(struct torture_context *context)
+{
+       if (context->results->ui_ops->report_time)
+               context->results->ui_ops->report_time(context);
+}