diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /subversion/tests/svn_test_main.c | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/tests/svn_test_main.c')
-rw-r--r-- | subversion/tests/svn_test_main.c | 660 |
1 files changed, 570 insertions, 90 deletions
diff --git a/subversion/tests/svn_test_main.c b/subversion/tests/svn_test_main.c index 15d460c..46c0c45 100644 --- a/subversion/tests/svn_test_main.c +++ b/subversion/tests/svn_test_main.c @@ -45,16 +45,30 @@ #include "svn_path.h" #include "svn_ctype.h" #include "svn_utf.h" +#include "svn_version.h" #include "private/svn_cmdline_private.h" +#include "private/svn_atomic.h" +#include "private/svn_mutex.h" +#include "private/svn_sqlite.h" #include "svn_private_config.h" +#if APR_HAS_THREADS +# include <apr_thread_proc.h> +#endif + /* Some Subversion test programs may want to parse options in the argument list, so we remember it here. */ +extern int test_argc; +extern const char **test_argv; int test_argc; const char **test_argv; +/* Many tests write to disk. Instead of writing to the current + directory, they should use this path as the root of the test data + area. */ +static const char *data_path; /* Test option: Print more output */ static svn_boolean_t verbose_mode = FALSE; @@ -70,10 +84,13 @@ static svn_boolean_t allow_segfaults = FALSE; /* Test option: Limit testing to a given mode (i.e. XFail, Skip, Pass, All). */ -enum svn_test_mode_t mode_filter = svn_test_all; +static enum svn_test_mode_t mode_filter = svn_test_all; + +/* Test option: Allow concurrent execution of tests */ +static svn_boolean_t parallel = FALSE; /* Option parsing enums and structures */ -enum { +enum test_options_e { help_opt = SVN_OPT_FIRST_LONGOPT_ID, cleanup_opt, fstype_opt, @@ -84,7 +101,13 @@ enum { server_minor_version_opt, allow_segfault_opt, srcdir_opt, - mode_filter_opt + reposdir_opt, + reposurl_opt, + repostemplate_opt, + mode_filter_opt, + sqlite_log_opt, + parallel_opt, + fsfs_version_opt }; static const apr_getopt_option_t cl_options[] = @@ -97,6 +120,8 @@ static const apr_getopt_option_t cl_options[] = N_("specify test config file ARG")}, {"fs-type", fstype_opt, 1, N_("specify a filesystem backend type ARG")}, + {"fsfs-version", fsfs_version_opt, 1, + N_("specify the FSFS version ARG")}, {"list", list_opt, 0, N_("lists all the tests with their short description")}, {"mode-filter", mode_filter_opt, 1, @@ -112,7 +137,17 @@ static const apr_getopt_option_t cl_options[] = {"allow-segfaults", allow_segfault_opt, 0, N_("don't trap seg faults (useful for debugging)")}, {"srcdir", srcdir_opt, 1, - N_("source directory")}, + N_("directory which contains test's C source files")}, + {"repos-dir", reposdir_opt, 1, + N_("directory to create repositories in")}, + {"repos-url", reposurl_opt, 1, + N_("the url to access reposdir as")}, + {"repos-template",repostemplate_opt, 1, + N_("the repository to use as template")}, + {"sqlite-logging", sqlite_log_opt, 0, + N_("enable SQLite logging")}, + {"parallel", parallel_opt, 0, + N_("allow concurrent execution of tests")}, {0, 0, 0, 0} }; @@ -123,8 +158,50 @@ static const apr_getopt_option_t cl_options[] = /* When non-zero, don't remove test directories */ static svn_boolean_t skip_cleanup = FALSE; -/* All cleanup actions are registered as cleanups on this pool. */ +/* All cleanup actions are registered as cleanups on the cleanup_pool, + * which may be thread-specific. */ +#if APR_HAS_THREADS +/* The thread-local data key for the cleanup pool. */ +static apr_threadkey_t *cleanup_pool_key = NULL; + +/* No-op destructor for apr_threadkey_private_create(). */ +static void null_threadkey_dtor(void *stuff) {} + +/* Set the thread-specific cleanup pool. */ +static void set_cleanup_pool(apr_pool_t *pool) +{ + apr_status_t status = apr_threadkey_private_set(pool, cleanup_pool_key); + if (status) + { + printf("apr_threadkey_private_set() failed with code %ld.\n", + (long)status); + exit(1); + } +} + +/* Get the thread-specific cleanup pool. */ +static apr_pool_t *get_cleanup_pool() +{ + void *data; + apr_status_t status = apr_threadkey_private_get(&data, cleanup_pool_key); + if (status) + { + printf("apr_threadkey_private_get() failed with code %ld.\n", + (long)status); + exit(1); + } + return data; +} + +# define cleanup_pool (get_cleanup_pool()) +# define HAVE_PER_THREAD_CLEANUP +#else static apr_pool_t *cleanup_pool = NULL; +# define set_cleanup_pool(p) (cleanup_pool = (p)) +#endif + +/* Used by test_thread to serialize access to stdout. */ +static svn_mutex__t *log_mutex = NULL; static apr_status_t cleanup_rmtree(void *data) @@ -150,19 +227,41 @@ cleanup_rmtree(void *data) } + void svn_test_add_dir_cleanup(const char *path) { if (cleanup_mode) { const char *abspath; - svn_error_t *err = svn_path_get_absolute(&abspath, path, cleanup_pool); + svn_error_t *err; + + /* All cleanup functions use the *same* pool (not subpools of it). + Thus, we need to synchronize. */ + err = svn_mutex__lock(log_mutex); + if (err) + { + if (verbose_mode) + printf("FAILED svn_mutex__lock in svn_test_add_dir_cleanup.\n"); + svn_error_clear(err); + return; + } + + err = svn_path_get_absolute(&abspath, path, cleanup_pool); svn_error_clear(err); if (!err) apr_pool_cleanup_register(cleanup_pool, abspath, cleanup_rmtree, apr_pool_cleanup_null); else if (verbose_mode) printf("FAILED ABSPATH: %s\n", path); + + err = svn_mutex__unlock(log_mutex, NULL); + if (err) + { + if (verbose_mode) + printf("FAILED svn_mutex__unlock in svn_test_add_dir_cleanup.\n"); + svn_error_clear(err); + } } } @@ -183,7 +282,7 @@ svn_test_rand(apr_uint32_t *seed) /* Determine the array size of test_funcs[], the inelegant way. :) */ static int -get_array_size(void) +get_array_size(struct svn_test_descriptor_t *test_funcs) { int i; @@ -205,6 +304,91 @@ crash_handler(int signum) longjmp(jump_buffer, 1); } +/* Write the result of test number TEST_NUM to stdout. Pretty-print test + name and dots according to our test-suite spec, and return TRUE if there + has been a test failure. + + The parameters are basically the internal state of do_test_num() and + test_thread(). */ +/* */ +static svn_boolean_t +log_results(const char *progname, + int test_num, + svn_boolean_t msg_only, + svn_boolean_t run_this_test, + svn_boolean_t skip, + svn_boolean_t xfail, + svn_boolean_t wimp, + svn_error_t *err, + const char *msg, + const struct svn_test_descriptor_t *desc) +{ + svn_boolean_t test_failed; + + if (err && err->apr_err == SVN_ERR_TEST_SKIPPED) + { + svn_error_clear(err); + err = SVN_NO_ERROR; + skip = TRUE; + xfail = FALSE; /* Or all XFail tests reporting SKIP would be failing */ + } + + /* Failure means unexpected results -- FAIL or XPASS. */ + test_failed = (!wimp && ((err != SVN_NO_ERROR) != (xfail != 0))); + + /* If we got an error, print it out. */ + if (err) + { + svn_handle_error2(err, stdout, FALSE, "svn_tests: "); + svn_error_clear(err); + } + + if (msg_only) + { + const svn_boolean_t otoh = !!desc->predicate.description; + + if (run_this_test) + printf(" %3d %-5s %s%s%s%s%s%s\n", + test_num, + (xfail ? "XFAIL" : (skip ? "SKIP" : "")), + msg ? msg : "(test did not provide name)", + (wimp && verbose_mode) ? " [[" : "", + (wimp && verbose_mode) ? desc->wip : "", + (wimp && verbose_mode) ? "]]" : "", + (otoh ? " / " : ""), + (otoh ? desc->predicate.description : "")); + } + else if (run_this_test && ((! quiet_mode) || test_failed)) + { + printf("%s %s %d: %s%s%s%s\n", + (err + ? (xfail ? "XFAIL:" : "FAIL: ") + : (xfail ? "XPASS:" : (skip ? "SKIP: " : "PASS: "))), + progname, + test_num, + msg ? msg : "(test did not provide name)", + wimp ? " [[WIMP: " : "", + wimp ? desc->wip : "", + wimp ? "]]" : ""); + } + + if (msg) + { + size_t len = strlen(msg); + if (len > 50) + printf("WARNING: Test docstring exceeds 50 characters\n"); + if (msg[len - 1] == '.') + printf("WARNING: Test docstring ends in a period (.)\n"); + if (svn_ctype_isupper(msg[0])) + printf("WARNING: Test docstring is capitalized\n"); + } + if (desc->msg == NULL) + printf("WARNING: New-style test descriptor is missing a docstring.\n"); + + fflush(stdout); + + return test_failed; +} /* Execute a test number TEST_NUM. Pretty-print test name and dots according to our test-suite spec, and return the result code. @@ -213,6 +397,7 @@ crash_handler(int signum) static svn_boolean_t do_test_num(const char *progname, int test_num, + struct svn_test_descriptor_t *test_funcs, svn_boolean_t msg_only, svn_test_opts_t *opts, const char **header_msg, @@ -220,11 +405,11 @@ do_test_num(const char *progname, { svn_boolean_t skip, xfail, wimp; svn_error_t *err = NULL; - svn_boolean_t test_failed; const char *msg = NULL; /* the message this individual test prints out */ const struct svn_test_descriptor_t *desc; - const int array_size = get_array_size(); + const int array_size = get_array_size(test_funcs); svn_boolean_t run_this_test; /* This test's mode matches DESC->MODE. */ + enum svn_test_mode_t test_mode; /* Check our array bounds! */ if (test_num < 0) @@ -239,11 +424,18 @@ do_test_num(const char *progname, } desc = &test_funcs[test_num]; - skip = desc->mode == svn_test_skip; - xfail = desc->mode == svn_test_xfail; + /* Check the test predicate. */ + if (desc->predicate.func + && desc->predicate.func(opts, desc->predicate.value, pool)) + test_mode = desc->predicate.alternate_mode; + else + test_mode = desc->mode; + + skip = test_mode == svn_test_skip; + xfail = test_mode == svn_test_xfail; wimp = xfail && desc->wip; msg = desc->msg; - run_this_test = mode_filter == svn_test_all || mode_filter == desc->mode; + run_this_test = mode_filter == svn_test_all || mode_filter == test_mode; if (run_this_test && header_msg && *header_msg) { @@ -272,13 +464,6 @@ do_test_num(const char *progname, err = (*desc->func2)(pool); else err = (*desc->func_opts)(opts, pool); - - if (err && err->apr_err == SVN_ERR_TEST_SKIPPED) - { - svn_error_clear(err); - err = SVN_NO_ERROR; - skip = TRUE; - } } else err = svn_error_create(SVN_ERR_TEST_FAILED, NULL, @@ -292,60 +477,171 @@ do_test_num(const char *progname, } /* Failure means unexpected results -- FAIL or XPASS. */ - test_failed = (!wimp && ((err != SVN_NO_ERROR) != (xfail != 0))); + skip_cleanup = log_results(progname, test_num, msg_only, run_this_test, + skip, xfail, wimp, err, msg, desc); - /* If we got an error, print it out. */ - if (err) - { - svn_handle_error2(err, stdout, FALSE, "svn_tests: "); - svn_error_clear(err); - } + return skip_cleanup; +} - if (msg_only) +#if APR_HAS_THREADS + +/* Per-test parameters used by test_thread */ +typedef struct test_params_t +{ + /* Name of the application */ + const char *progname; + + /* Total number of tests to execute */ + svn_atomic_t test_count; + + /* Global test options as provided by main() */ + svn_test_opts_t *opts; + + /* Reference to the global failure flag. Set this if any test failed. */ + svn_atomic_t got_error; + + /* Test to execute next. */ + svn_atomic_t test_num; + + /* Test functions array. */ + struct svn_test_descriptor_t *test_funcs; +} test_params_t; + +/* Thread function similar to do_test_num() but with fewer options. We do + catch segfaults. All parameters are given as a test_params_t in DATA. + */ +static void * APR_THREAD_FUNC +test_thread(apr_thread_t *thread, void *data) +{ + svn_boolean_t skip, xfail, wimp; + svn_error_t *err; + const struct svn_test_descriptor_t *desc; + svn_boolean_t run_this_test; /* This test's mode matches DESC->MODE. */ + enum svn_test_mode_t test_mode; + test_params_t *params = data; + svn_atomic_t test_num; + apr_pool_t *pool; + apr_pool_t *thread_root + = apr_allocator_owner_get(svn_pool_create_allocator(FALSE)); + +#ifdef HAVE_PER_THREAD_CLEANUP + set_cleanup_pool(svn_pool_create(thread_root)); +#endif + + pool = svn_pool_create(thread_root); + + for (test_num = svn_atomic_inc(¶ms->test_num); + test_num <= params->test_count; + test_num = svn_atomic_inc(¶ms->test_num)) { - if (run_this_test) - printf(" %3d %-5s %s%s%s%s\n", - test_num, - (xfail ? "XFAIL" : (skip ? "SKIP" : "")), - msg ? msg : "(test did not provide name)", - (wimp && verbose_mode) ? " [[" : "", - (wimp && verbose_mode) ? desc->wip : "", - (wimp && verbose_mode) ? "]]" : ""); + svn_pool_clear(pool); +#ifdef HAVE_PER_THREAD_CLEANUP + svn_pool_clear(cleanup_pool); /* after clearing pool*/ +#endif + + desc = ¶ms->test_funcs[test_num]; + /* Check the test predicate. */ + if (desc->predicate.func + && desc->predicate.func(params->opts, desc->predicate.value, pool)) + test_mode = desc->predicate.alternate_mode; + else + test_mode = desc->mode; + + skip = test_mode == svn_test_skip; + xfail = test_mode == svn_test_xfail; + wimp = xfail && desc->wip; + run_this_test = mode_filter == svn_test_all + || mode_filter == test_mode; + + /* Do test */ + if (skip || !run_this_test) + err = NULL; /* pass */ + else if (desc->func2) + err = (*desc->func2)(pool); + else + err = (*desc->func_opts)(params->opts, pool); + + /* Write results to console */ + svn_error_clear(svn_mutex__lock(log_mutex)); + if (log_results(params->progname, test_num, FALSE, run_this_test, + skip, xfail, wimp, err, desc->msg, desc)) + svn_atomic_set(¶ms->got_error, TRUE); + svn_error_clear(svn_mutex__unlock(log_mutex, NULL)); } - else if (run_this_test && ((! quiet_mode) || test_failed)) + + svn_pool_clear(pool); /* Make sure this is cleared before cleanup_pool*/ + + /* Release all test memory. Possibly includes cleanup_pool */ + svn_pool_destroy(thread_root); + + /* End thread explicitly to prevent APR_INCOMPLETE return codes in + apr_thread_join(). */ + apr_thread_exit(thread, 0); + return NULL; +} + +/* Log an error with message MSG if the APR status of EXPR is not 0. + */ +#define CHECK_STATUS(expr,msg) \ + do { \ + apr_status_t rv = (expr); \ + if (rv) \ + { \ + svn_error_t *svn_err__temp = svn_error_wrap_apr(rv, msg); \ + svn_handle_error2(svn_err__temp, stdout, FALSE, "svn_tests: "); \ + svn_error_clear(svn_err__temp); \ + } \ + } while (0); + +/* Execute all ARRAY_SIZE tests concurrently using MAX_THREADS threads. + Pass PROGNAME and OPTS to the individual tests. Return TRUE if at least + one of the tests failed. Allocate all data in POOL. + + Note that cleanups are delayed until all tests have been completed. + */ +static svn_boolean_t +do_tests_concurrently(const char *progname, + struct svn_test_descriptor_t *test_funcs, + int array_size, + int max_threads, + svn_test_opts_t *opts, + apr_pool_t *pool) +{ + int i; + apr_thread_t **threads; + + /* Prepare thread parameters. */ + test_params_t params; + params.got_error = FALSE; + params.opts = opts; + params.progname = progname; + params.test_num = 1; + params.test_funcs = test_funcs; + params.test_count = array_size; + + /* Start all threads. */ + threads = apr_pcalloc(pool, max_threads * sizeof(*threads)); + for (i = 0; i < max_threads; ++i) { - printf("%s %s %d: %s%s%s%s\n", - (err - ? (xfail ? "XFAIL:" : "FAIL: ") - : (xfail ? "XPASS:" : (skip ? "SKIP: " : "PASS: "))), - progname, - test_num, - msg ? msg : "(test did not provide name)", - wimp ? " [[WIMP: " : "", - wimp ? desc->wip : "", - wimp ? "]]" : ""); + CHECK_STATUS(apr_thread_create(&threads[i], NULL, test_thread, ¶ms, + pool), + "creating test thread failed.\n"); } - if (msg) + /* Wait for all tasks (tests) to complete. */ + for (i = 0; i < max_threads; ++i) { - size_t len = strlen(msg); - if (len > 50) - printf("WARNING: Test docstring exceeds 50 characters\n"); - if (msg[len - 1] == '.') - printf("WARNING: Test docstring ends in a period (.)\n"); - if (svn_ctype_isupper(msg[0])) - printf("WARNING: Test docstring is capitalized\n"); + apr_status_t result = 0; + CHECK_STATUS(apr_thread_join(&result, threads[i]), + "Waiting for test thread to finish failed."); + CHECK_STATUS(result, + "Test thread returned an error."); } - if (desc->msg == NULL) - printf("WARNING: New-style test descriptor is missing a docstring.\n"); - fflush(stdout); - - skip_cleanup = test_failed; - - return test_failed; + return params.got_error != FALSE; } +#endif static void help(const char *progname, apr_pool_t *pool) { @@ -366,12 +662,106 @@ static void help(const char *progname, apr_pool_t *pool) svn_error_clear(svn_cmdline_fprintf(stdout, pool, "\n")); } +static svn_error_t *init_test_data(const char *argv0, apr_pool_t *pool) +{ + const char *temp_path; + const char *base_name; + + /* Convert the program path to an absolute path. */ + SVN_ERR(svn_utf_cstring_to_utf8(&temp_path, argv0, pool)); + temp_path = svn_dirent_internal_style(temp_path, pool); + SVN_ERR(svn_dirent_get_absolute(&temp_path, temp_path, pool)); + SVN_ERR_ASSERT(!svn_dirent_is_root(temp_path, strlen(temp_path))); + + /* Extract the interesting bits of the path. */ + temp_path = svn_dirent_dirname(temp_path, pool); + base_name = svn_dirent_basename(temp_path, pool); + if (0 == strcmp(base_name, ".libs")) + { + /* This is a libtoolized binary, skip the .libs directory. */ + temp_path = svn_dirent_dirname(temp_path, pool); + base_name = svn_dirent_basename(temp_path, pool); + } + temp_path = svn_dirent_dirname(temp_path, pool); + + /* temp_path should now point to the root of the test + builddir. Construct the path to the transient dir. Note that we + put the path insinde the cmdline/svn-test-work area. This is + because trying to get the cmdline tests to use a different work + area is unprintable; so we put the C test transient dir in the + cmdline tests area, as the lesser of evils ... */ + temp_path = svn_dirent_join_many(pool, temp_path, + "cmdline", "svn-test-work", + base_name, SVN_VA_NULL); + + /* Finally, create the transient directory. */ + SVN_ERR(svn_io_make_dir_recursively(temp_path, pool)); + + data_path = temp_path; + return SVN_NO_ERROR; +} + +const char * +svn_test_data_path(const char *base_name, apr_pool_t *result_pool) +{ + return svn_dirent_join(data_path, base_name, result_pool); +} + +svn_error_t * +svn_test_get_srcdir(const char **srcdir, + const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + const char *cwd; + + if (opts->srcdir) + { + *srcdir = opts->srcdir; + return SVN_NO_ERROR; + } + + fprintf(stderr, "WARNING: missing '--srcdir' option"); + SVN_ERR(svn_dirent_get_absolute(&cwd, ".", pool)); + fprintf(stderr, ", assuming '%s'\n", cwd); + *srcdir = cwd; + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_test__init_auth_baton(svn_auth_baton_t **ab, + apr_pool_t *result_pool) +{ + svn_config_t *cfg_config; + + SVN_ERR(svn_config_create2(&cfg_config, FALSE, FALSE, result_pool)); + + /* Disable the crypto backends that might not be entirely + threadsafe and/or compatible with running headless. + + The windows system is just our own files, but then with user-key + encrypted data inside. */ + svn_config_set(cfg_config, + SVN_CONFIG_SECTION_AUTH, + SVN_CONFIG_OPTION_PASSWORD_STORES, + "windows-cryptoapi"); + + SVN_ERR(svn_cmdline_create_auth_baton(ab, + TRUE /* non_interactive */, + "jrandom", "rayjandom", + NULL, + TRUE /* no_auth_cache */, + FALSE /* trust_server_cert */, + cfg_config, NULL, NULL, result_pool)); + + return SVN_NO_ERROR; +} /* Standard svn test program */ int -main(int argc, const char *argv[]) +svn_test_main(int argc, const char *argv[], int max_threads, + struct svn_test_descriptor_t *test_funcs) { - const char *prog_name; int i; svn_boolean_t got_error = FALSE; apr_pool_t *pool, *test_pool; @@ -383,7 +773,7 @@ main(int argc, const char *argv[]) svn_error_t *err; char errmsg[200]; /* How many tests are there? */ - int array_size = get_array_size(); + int array_size = get_array_size(test_funcs); svn_test_opts_t opts = { NULL }; @@ -400,31 +790,61 @@ main(int argc, const char *argv[]) * usage but make it thread-safe to allow for multi-threaded tests. */ pool = apr_allocator_owner_get(svn_pool_create_allocator(TRUE)); + err = svn_mutex__init(&log_mutex, TRUE, pool); + if (err) + { + svn_handle_error2(err, stderr, TRUE, "svn_tests: "); + svn_error_clear(err); + } + + /* Set up the thread-local storage key for the cleanup pool. */ +#ifdef HAVE_PER_THREAD_CLEANUP + apr_err = apr_threadkey_private_create(&cleanup_pool_key, + null_threadkey_dtor, + pool); + if (apr_err) + { + printf("apr_threadkey_private_create() failed with code %ld.\n", + (long)apr_err); + exit(1); + } +#endif /* HAVE_PER_THREAD_CLEANUP */ /* Remember the command line */ test_argc = argc; test_argv = argv; + err = init_test_data(argv[0], pool); + if (err) + { + svn_handle_error2(err, stderr, TRUE, "svn_tests: "); + svn_error_clear(err); + } + err = svn_cmdline__getopt_init(&os, argc, argv, pool); + if (err) + { + svn_handle_error2(err, stderr, TRUE, "svn_tests: "); + svn_error_clear(err); + } + os->interleave = TRUE; /* Let options and arguments be interleaved */ /* Strip off any leading path components from the program name. */ - prog_name = strrchr(argv[0], '/'); - if (prog_name) - prog_name++; - else - { - /* Just check if this is that weird platform that uses \ instead - of / for the path separator. */ - prog_name = strrchr(argv[0], '\\'); - if (prog_name) - prog_name++; - else - prog_name = argv[0]; - } + opts.prog_name = svn_dirent_internal_style(argv[0], pool); + opts.prog_name = svn_dirent_basename(opts.prog_name, NULL); #ifdef WIN32 + /* Abuse cast in strstr() to remove .exe extension. + Value is allocated in pool by svn_dirent_internal_style() */ + { + char *exe_ext = strstr(opts.prog_name, ".exe"); + + if (exe_ext) + *exe_ext = '\0'; + } + #if _MSC_VER >= 1400 /* ### This should work for VC++ 2002 (=1300) and later */ /* Show the abort message on STDERR instead of a dialog to allow @@ -446,7 +866,7 @@ main(int argc, const char *argv[]) #endif if (err) - return svn_cmdline_handle_exit_error(err, pool, prog_name); + return svn_cmdline_handle_exit_error(err, pool, opts.prog_name); while (1) { const char *opt_arg; @@ -457,7 +877,7 @@ main(int argc, const char *argv[]) break; else if (apr_err && (apr_err != APR_BADCH)) { - /* Ignore invalid option error to allow passing arbitary options */ + /* Ignore invalid option error to allow passing arbitrary options */ fprintf(stderr, "apr_getopt_long failed : [%d] %s\n", apr_err, apr_strerror(apr_err, errmsg, sizeof(errmsg))); exit(1); @@ -465,7 +885,7 @@ main(int argc, const char *argv[]) switch (opt_id) { case help_opt: - help(prog_name, pool); + help(opts.prog_name, pool); exit(0); case cleanup_opt: cleanup_mode = TRUE; @@ -480,6 +900,20 @@ main(int argc, const char *argv[]) SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.srcdir, opt_arg, pool)); opts.srcdir = svn_dirent_internal_style(opts.srcdir, pool); break; + case reposdir_opt: + SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.repos_dir, opt_arg, pool)); + opts.repos_dir = svn_dirent_internal_style(opts.repos_dir, pool); + break; + case reposurl_opt: + SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.repos_url, opt_arg, pool)); + opts.repos_url = svn_uri_canonicalize(opts.repos_url, pool); + break; + case repostemplate_opt: + SVN_INT_ERR(svn_utf_cstring_to_utf8(&opts.repos_template, opt_arg, + pool)); + opts.repos_template = svn_dirent_internal_style(opts.repos_template, + pool); + break; case list_opt: list_mode = TRUE; break; @@ -518,14 +952,24 @@ main(int argc, const char *argv[]) exit(1); } if ((opts.server_minor_version < 3) - || (opts.server_minor_version > 6)) + || (opts.server_minor_version > SVN_VER_MINOR)) { fprintf(stderr, "FAIL: Invalid minor version given\n"); exit(1); } + break; } + case sqlite_log_opt: + svn_sqlite__dbg_enable_errorlog(); + break; +#if APR_HAS_THREADS + case parallel_opt: + parallel = TRUE; + break; +#endif } } + opts.verbose = verbose_mode; /* Disable sleeping for timestamps, to speed up the tests. */ apr_env_set( @@ -540,7 +984,7 @@ main(int argc, const char *argv[]) } /* Create an iteration pool for the tests */ - cleanup_pool = svn_pool_create(pool); + set_cleanup_pool(svn_pool_create(pool)); test_pool = svn_pool_create(pool); if (!allow_segfaults) @@ -558,8 +1002,8 @@ main(int argc, const char *argv[]) "------ ----- ----------------\n"; for (i = 1; i <= array_size; i++) { - if (do_test_num(prog_name, i, TRUE, &opts, &header_msg, - test_pool)) + if (do_test_num(opts.prog_name, i, test_funcs, + TRUE, &opts, &header_msg, test_pool)) got_error = TRUE; /* Clear the per-function pool */ @@ -579,8 +1023,8 @@ main(int argc, const char *argv[]) continue; ran_a_test = TRUE; - if (do_test_num(prog_name, test_num, FALSE, &opts, NULL, - test_pool)) + if (do_test_num(opts.prog_name, test_num, test_funcs, + FALSE, &opts, NULL, test_pool)) got_error = TRUE; /* Clear the per-function pool */ @@ -594,15 +1038,34 @@ main(int argc, const char *argv[]) if (! ran_a_test) { /* just run all tests */ - for (i = 1; i <= array_size; i++) + if (max_threads < 1) + max_threads = array_size; + + if (max_threads == 1 || !parallel) { - if (do_test_num(prog_name, i, FALSE, &opts, NULL, test_pool)) - got_error = TRUE; + for (i = 1; i <= array_size; i++) + { + if (do_test_num(opts.prog_name, i, test_funcs, + FALSE, &opts, NULL, test_pool)) + got_error = TRUE; - /* Clear the per-function pool */ + /* Clear the per-function pool */ + svn_pool_clear(test_pool); + svn_pool_clear(cleanup_pool); + } + } +#if APR_HAS_THREADS + else + { + got_error = do_tests_concurrently(opts.prog_name, test_funcs, + array_size, max_threads, + &opts, test_pool); + + /* Execute all cleanups */ svn_pool_clear(test_pool); svn_pool_clear(cleanup_pool); } +#endif } /* Clean up APR */ @@ -611,3 +1074,20 @@ main(int argc, const char *argv[]) return got_error; } + + +svn_boolean_t +svn_test__fs_type_is(const svn_test_opts_t *opts, + const char *predicate_value, + apr_pool_t *pool) +{ + return (0 == strcmp(predicate_value, opts->fs_type)); +} + +svn_boolean_t +svn_test__fs_type_not(const svn_test_opts_t *opts, + const char *predicate_value, + apr_pool_t *pool) +{ + return (0 != strcmp(predicate_value, opts->fs_type)); +} |