You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2018/11/07 12:30:11 UTC

svn commit: r1846002 [40/44] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ build/generator/util/ build/win32/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contr...

Modified: subversion/branches/ra-git/subversion/tests/libsvn_client/mtcc-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_client/mtcc-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_client/mtcc-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_client/mtcc-test.c Wed Nov  7 12:30:06 2018
@@ -783,6 +783,35 @@ test_iprops_path_format(const svn_test_o
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_move_and_delete_ancestor(const svn_test_opts_t *opts,
+                              apr_pool_t *pool)
+{
+  svn_client__mtcc_t *mtcc;
+  svn_client_ctx_t *ctx;
+  const char *repos_url;
+
+  SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-move-and-delete",
+                                  opts, pool, pool));
+
+  SVN_ERR(make_greek_tree(repos_url, pool));
+
+  SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
+  SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
+
+  SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
+
+  SVN_ERR(svn_client__mtcc_add_move("A/B", "B", mtcc, pool));
+  SVN_ERR(svn_client__mtcc_add_move("A/mu", "mu", mtcc, pool));
+  SVN_ERR(svn_client__mtcc_add_delete("A", mtcc, pool));
+
+  SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
+
+  return SVN_NO_ERROR;
+
+}
+
+
 /* ========================================================================== */
 
 
@@ -811,6 +840,8 @@ static struct svn_test_descriptor_t test
                        "test ra_get_file_revs2 both ways"),
     SVN_TEST_OPTS_PASS(test_iprops_path_format,
                        "test iprops url format"),
+    SVN_TEST_OPTS_PASS(test_move_and_delete_ancestor,
+                       "test move and delete ancestor (issue 4666)"),
     SVN_TEST_NULL
   };
 

Propchange: subversion/branches/ra-git/subversion/tests/libsvn_delta/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Nov  7 12:30:06 2018
@@ -8,6 +8,7 @@ vdelta-test
 random-test
 xml-output-test
 svndiff-test
+svndiff-stream-test
 window-test
 editor-test
 combined

Modified: subversion/branches/ra-git/subversion/tests/libsvn_delta/random-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_delta/random-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_delta/random-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_delta/random-test.c Wed Nov  7 12:30:06 2018
@@ -41,7 +41,7 @@
 #include "delta-window-test.h"
 
 
-#define DEFAULT_ITERATIONS 30
+#define DEFAULT_ITERATIONS 60
 #define DEFAULT_MAXLEN (100 * 1024)
 #define DEFAULT_DUMP_FILES 0
 #define DEFAULT_PRINT_WINDOWS 0
@@ -329,9 +329,9 @@ do_random_test(apr_pool_t *pool,
                                          delta_pool);
 
       /* Make stage 2: encode the text delta in svndiff format using
-                       varying compression levels. */
-      svn_txdelta_to_svndiff3(&handler, &handler_baton, stream, 1, i % 10,
-                              delta_pool);
+                       varying svndiff versions and compression levels. */
+      svn_txdelta_to_svndiff3(&handler, &handler_baton, stream, i % 3,
+                              i % 10, delta_pool);
 
       /* Make stage 1: create the text delta.  */
       svn_txdelta2(&txdelta_stream,
@@ -425,9 +425,9 @@ do_random_combine_test(apr_pool_t *pool,
                                          delta_pool);
 
       /* Make stage 2: encode the text delta in svndiff format using
-                       varying compression levels. */
-      svn_txdelta_to_svndiff3(&handler, &handler_baton, stream, 1, i % 10,
-                              delta_pool);
+                       varying svndiff versions and compression levels. */
+      svn_txdelta_to_svndiff3(&handler, &handler_baton, stream, i % 3,
+                              i % 10, delta_pool);
 
       /* Make stage 1: create the text deltas.  */
 
@@ -515,6 +515,96 @@ random_combine_test(apr_pool_t *pool)
 }
 
 
+/* (Note: *LAST_SEED is an output parameter.) */
+static svn_error_t *
+do_random_txdelta_to_svndiff_stream_test(apr_pool_t *pool,
+                                         apr_uint32_t *last_seed)
+{
+  apr_uint32_t seed;
+  apr_uint32_t maxlen;
+  apr_size_t bytes_range;
+  int i;
+  int iterations;
+  int dump_files;
+  int print_windows;
+  const char *random_bytes;
+  apr_pool_t *iterpool;
+
+  /* Initialize parameters and print out the seed in case we dump core
+     or something. */
+  init_params(&seed, &maxlen, &iterations, &dump_files, &print_windows,
+              &random_bytes, &bytes_range, pool);
+
+  iterpool = svn_pool_create(pool);
+  for (i = 0; i < iterations; i++)
+    {
+      apr_uint32_t subseed_base;
+      apr_file_t *source;
+      apr_file_t *target;
+      apr_file_t *source_copy;
+      apr_file_t *new_target;
+      svn_txdelta_stream_t *txstream;
+      svn_stream_t *delta_stream;
+      svn_txdelta_window_handler_t handler;
+      void *handler_baton;
+      svn_stream_t *push_stream;
+
+      svn_pool_clear(iterpool);
+
+      /* Generate source and target for the delta and its application. */
+      *last_seed = seed;
+      subseed_base = svn_test_rand(&seed);
+      source = generate_random_file(maxlen, subseed_base, &seed,
+                                    random_bytes, bytes_range,
+                                    dump_files, iterpool);
+      target = generate_random_file(maxlen, subseed_base, &seed,
+                                    random_bytes, bytes_range,
+                                    dump_files, iterpool);
+      source_copy = copy_tempfile(source, iterpool);
+      new_target = open_tempfile(NULL, iterpool);
+
+      /* Create a txdelta stream that turns the source into target;
+         turn it into a generic readable svn_stream_t. */
+      svn_txdelta2(&txstream,
+                   svn_stream_from_aprfile2(source, TRUE, iterpool),
+                   svn_stream_from_aprfile2(target, TRUE, iterpool),
+                   FALSE, iterpool);
+      delta_stream = svn_txdelta_to_svndiff_stream(txstream, i % 3, i % 10,
+                                                   iterpool);
+
+      /* Apply it to a copy of the source file to see if we get the
+         same target back. */
+      svn_txdelta_apply(svn_stream_from_aprfile2(source_copy, TRUE, iterpool),
+                        svn_stream_from_aprfile2(new_target, TRUE, iterpool),
+                        NULL, NULL, iterpool, &handler, &handler_baton);
+      push_stream = svn_txdelta_parse_svndiff(handler, handler_baton, TRUE,
+                                              iterpool);
+      SVN_ERR(svn_stream_copy3(delta_stream, push_stream, NULL, NULL,
+                               iterpool));
+
+      SVN_ERR(compare_files(target, new_target, dump_files));
+
+      apr_file_close(source);
+      apr_file_close(target);
+      apr_file_close(source_copy);
+      apr_file_close(new_target);
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements svn_test_driver_t. */
+static svn_error_t *
+random_txdelta_to_svndiff_stream_test(apr_pool_t *pool)
+{
+  apr_uint32_t seed;
+  svn_error_t *err = do_random_txdelta_to_svndiff_stream_test(pool, &seed);
+  if (err)
+    fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
+  return err;
+}
+
 /* Change to 1 to enable the unit test for the delta combiner's range index: */
 #if 0
 #include "range-index-test.h"
@@ -533,6 +623,8 @@ static struct svn_test_descriptor_t test
                    "random delta test"),
     SVN_TEST_PASS2(random_combine_test,
                    "random combine delta test"),
+    SVN_TEST_PASS2(random_txdelta_to_svndiff_stream_test,
+                   "random txdelta to svndiff stream test"),
 #ifdef SVN_RANGE_INDEX_TEST_H
     SVN_TEST_PASS2(random_range_index_test,
                    "random range index test"),

Modified: subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c Wed Nov  7 12:30:06 2018
@@ -2407,8 +2407,6 @@ merge_with_part_already_present(apr_pool
 /* Merge is more "aggressive" about resolving conflicts than traditional
  * patch or diff3.  Some people consider this behaviour to be a bug, see
  * http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=35014
- *
- * The original behavior of this test (added in 2003) was tweaked in 2016.
  */
 static svn_error_t *
 merge_adjacent_changes(apr_pool_t *pool)
@@ -2430,13 +2428,8 @@ merge_adjacent_changes(apr_pool_t *pool)
 
                           "zig\n"
                           "foo\n"
-                          "<<<<<<< adj2\n"
                           "new_bar\n"
-                          "baz\n"
-                          "=======\n"
-                          "bar\n"
-                          "new_baz\n"
-                          ">>>>>>> adj3\n",
+                          "new_baz\n",
 
                           NULL,
                           svn_diff_conflict_display_modified_latest,
@@ -3003,8 +2996,6 @@ three_way_double_add(apr_pool_t *pool)
                           "D\n" /* New line 1a */
                           "E\n" /* New line 2a */
                           "F\n" /* New line 3a*/
-                          "||||||| doubleadd1\n"
-                          "C\n"
                           "=======\n"
                           "O\n"
                           "P\n" /* New line 1b */
@@ -3018,7 +3009,7 @@ three_way_double_add(apr_pool_t *pool)
                           svn_diff_conflict_display_modified_original_latest,
                           pool));
 
-  SVN_ERR(three_way_merge("doubleadd4", "doubleadd5", "doubleadd6",
+  SVN_ERR(three_way_merge("doubleadd1", "doubleadd2", "doubleadd3",
                           "A\n"
                           "B\n"
                           "C\n"
@@ -3053,21 +3044,18 @@ three_way_double_add(apr_pool_t *pool)
                           will be a PASS. */
                           "A\n"
                           "B\n"
-                          "<<<<<<< doubleadd5\n"
+                          "<<<<<<< doubleadd2\n"
                           "C\n"
                           "D\n" /* New line 1a */
                           "E\n" /* New line 2a */
                           "F\n" /* New line 3a*/
-                          "||||||| doubleadd4\n"
-                          "C\n"
-                          "J\n"
                           "=======\n"
                           "O\n"
                           "P\n" /* New line 1b */
                           "Q\n" /* New line 2b */
                           "R\n" /* New line 3b */
                           "J\n"
-                          ">>>>>>> doubleadd6\n"
+                          ">>>>>>> doubleadd3\n"
                           "K\n"
                           "L",
                           NULL,
@@ -3119,7 +3107,7 @@ static struct svn_test_descriptor_t test
                    "2-way issue #3362 test v1"),
     SVN_TEST_PASS2(two_way_issue_3362_v2,
                    "2-way issue #3362 test v2"),
-    SVN_TEST_PASS2(three_way_double_add,
+    SVN_TEST_XFAIL2(three_way_double_add,
                    "3-way merge, double add"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c Wed Nov  7 12:30:06 2018
@@ -40,6 +40,7 @@
 #include "svn_version.h"
 
 #include "svn_private_config.h"
+#include "private/svn_cache.h"
 #include "private/svn_fs_util.h"
 #include "private/svn_fs_private.h"
 #include "private/svn_fspath.h"
@@ -7187,6 +7188,187 @@ commit_with_locked_rep_cache(const svn_t
   return SVN_NO_ERROR;
 }
 
+
+static svn_error_t *
+test_cache_clear_during_stream(const svn_test_opts_t *opts,
+                               apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root, *rev_root;
+  svn_revnum_t new_rev;
+  const char *fs_path;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_pool_t *subpool = svn_pool_create(pool);
+  svn_txdelta_window_handler_t consumer_func;
+  void *consumer_baton;
+  int i;
+  svn_stream_t *stream;
+  svn_stringbuf_t *buf;
+
+
+  fs_path = "test-repo-cache_clear_during_stream";
+  SVN_ERR(svn_test__create_fs(&fs, fs_path, opts, pool));
+
+  /* r1: Add a file. */
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, 0, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_file(txn_root, "/foo", pool));
+
+  /* Make the file large enough to span multiple txdelta windows.
+   * Just to be sure, make it not too uniform to keep self-txdelta at bay. */
+  SVN_ERR(svn_fs_apply_textdelta(&consumer_func, &consumer_baton,
+                                 txn_root, "/foo", NULL, NULL, subpool));
+  stream = svn_txdelta_target_push(consumer_func, consumer_baton, 
+                                   svn_stream_empty(subpool), subpool);
+  for (i = 0; i < 10000; ++ i)
+    {
+      svn_string_t *text;
+
+      svn_pool_clear(iterpool);
+      text = svn_string_createf(iterpool, "some dummy text - %d\n", i);
+      SVN_ERR(svn_stream_write(stream, text->data, &text->len));
+    }
+
+  SVN_ERR(svn_stream_close(stream));
+  svn_pool_destroy(subpool);
+
+  SVN_ERR(test_commit_txn(&new_rev, txn, NULL, pool));
+  SVN_TEST_INT_ASSERT(new_rev, 1);
+
+  /* Read the file once to populate the fulltext cache. */
+  SVN_ERR(svn_fs_revision_root(&rev_root, fs, 1, pool));
+  SVN_ERR(svn_fs_file_contents(&stream, rev_root, "/foo", pool));
+  SVN_ERR(svn_test__stream_to_string(&buf, stream, pool));
+
+  /* Start reading it again from cache, clear the cache and continue.
+   * Make sure we read more than one txdelta window before clearing
+   * the cache.  That gives the FS backend a chance to skip windows
+   * when continuing the read from disk. */
+  SVN_ERR(svn_fs_file_contents(&stream, rev_root, "/foo", pool));
+  buf->len = 2 * SVN_STREAM_CHUNK_SIZE;
+  SVN_ERR(svn_stream_read_full(stream, buf->data, &buf->len));
+  SVN_ERR(svn_cache__membuffer_clear(svn_cache__get_global_membuffer_cache()));
+  SVN_ERR(svn_test__stream_to_string(&buf, stream, pool));
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_rep_sharing_strict_content_check(const svn_test_opts_t *opts,
+                                      apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  svn_revnum_t new_rev;
+  const char *fs_path, *fs_path2;
+  apr_pool_t *subpool = svn_pool_create(pool);
+  svn_error_t *err;
+
+  /* Bail (with success) on known-untestable scenarios */
+  if (strcmp(opts->fs_type, SVN_FS_TYPE_BDB) == 0)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+                            "BDB repositories don't support rep-sharing");
+
+  /* Create 2 repos with same structure & size but different contents */
+  fs_path = "test-rep-sharing-strict-content-check1";
+  fs_path2 = "test-rep-sharing-strict-content-check2";
+
+  SVN_ERR(svn_test__create_fs(&fs, fs_path, opts, subpool));
+
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, 0, 0, subpool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
+  SVN_ERR(svn_fs_make_file(txn_root, "/foo", subpool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "foo", "quite bad", subpool));
+  SVN_ERR(test_commit_txn(&new_rev, txn, NULL, subpool));
+  SVN_TEST_INT_ASSERT(new_rev, 1);
+
+  SVN_ERR(svn_test__create_fs(&fs, fs_path2, opts, subpool));
+
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, 0, 0, subpool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
+  SVN_ERR(svn_fs_make_file(txn_root, "foo", subpool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "foo", "very good", subpool));
+  SVN_ERR(test_commit_txn(&new_rev, txn, NULL, subpool));
+  SVN_TEST_INT_ASSERT(new_rev, 1);
+
+  /* Close both repositories. */
+  svn_pool_clear(subpool);
+
+  /* Doctor the first repo such that it uses the wrong rep-cache. */
+  SVN_ERR(svn_io_copy_file(svn_relpath_join(fs_path2, "rep-cache.db", pool),
+                           svn_relpath_join(fs_path, "rep-cache.db", pool),
+                           FALSE, pool));
+
+  /* Changing the file contents such that rep-sharing would kick in if
+     the file contents was not properly compared. */
+  SVN_ERR(svn_fs_open2(&fs, fs_path, NULL, subpool, subpool));
+
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, 1, 0, subpool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
+  err = svn_test__set_file_contents(txn_root, "foo", "very good", subpool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_AMBIGUOUS_CHECKSUM_REP);
+
+  svn_pool_destroy(subpool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+closest_copy_test_svn_4677(const svn_test_opts_t *opts,
+                           apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root, *rev_root, *croot;
+  svn_revnum_t after_rev;
+  const char *cpath;
+  apr_pool_t *spool = svn_pool_create(pool);
+
+  /* Prepare a filesystem. */
+  SVN_ERR(svn_test__create_fs(&fs, "test-repo-svn-4677",
+                              opts, pool));
+
+  /* In first txn, create file A/foo. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, spool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, spool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "A", spool));
+  SVN_ERR(svn_fs_make_file(txn_root, "A/foo", spool));
+  SVN_ERR(test_commit_txn(&after_rev, txn, NULL, spool));
+  svn_pool_clear(spool);
+  SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, spool));
+
+  /* Move A to B, and commit. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, spool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, spool));
+  SVN_ERR(svn_fs_copy(rev_root, "A", txn_root, "B", spool));
+  SVN_ERR(svn_fs_delete(txn_root, "A", spool));
+  SVN_ERR(test_commit_txn(&after_rev, txn, NULL, spool));
+  svn_pool_clear(spool);
+  SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, spool));
+
+  /* Replace file B/foo with directory B/foo, add B/foo/bar, and commit. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, spool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, spool));
+  SVN_ERR(svn_fs_delete(txn_root, "B/foo", spool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "B/foo", spool));
+  SVN_ERR(svn_fs_make_file(txn_root, "B/foo/bar", spool));
+  SVN_ERR(test_commit_txn(&after_rev, txn, NULL, spool));
+  svn_pool_clear(spool);
+  SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, spool));
+
+  /* B/foo/bar has been copied.
+     Issue 4677 was caused by returning an error in this situation. */
+  SVN_ERR(svn_fs_closest_copy(&croot, &cpath, rev_root, "B/foo/bar", spool));
+  SVN_TEST_ASSERT(cpath == NULL);
+  SVN_TEST_ASSERT(croot == NULL);
+
+  return SVN_NO_ERROR;
+}
+
 /* ------------------------------------------------------------------------ */
 
 /* The test table.  */
@@ -7325,6 +7507,12 @@ static struct svn_test_descriptor_t test
                        "test reading a large changed paths list"),
     SVN_TEST_OPTS_PASS(commit_with_locked_rep_cache,
                        "test commit with locked rep-cache"),
+    SVN_TEST_OPTS_PASS(test_cache_clear_during_stream,
+                       "test clearing the cache while streaming a rep"),
+    SVN_TEST_OPTS_PASS(test_rep_sharing_strict_content_check,
+                       "test rep-sharing on content rather than SHA1"),
+    SVN_TEST_OPTS_PASS(closest_copy_test_svn_4677,
+                       "test issue SVN-4677 regression"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c Wed Nov  7 12:30:06 2018
@@ -1631,8 +1631,8 @@ delta_chain_with_plain(const svn_test_op
   svn_hash_sets(props, "p", svn_string_create(prop_value->data, pool));
 
   hash_rep = svn_stringbuf_create_empty(pool);
-  svn_hash_write2(props, svn_stream_from_stringbuf(hash_rep, pool), "END",
-                  pool);
+  SVN_ERR(svn_hash_write2(props, svn_stream_from_stringbuf(hash_rep, pool),
+                          "END", pool));
 
   SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
   SVN_ERR(svn_fs_txn_root(&root, txn, pool));

Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c Wed Nov  7 12:30:06 2018
@@ -85,8 +85,10 @@ verify_representation_stats(const svn_fs
   SVN_TEST_ASSERT(stats->total.count == expected_count);
   SVN_TEST_ASSERT(   stats->total.packed_size >= 10 * expected_count
                   && stats->total.packed_size <= 1000 * expected_count);
-  SVN_TEST_ASSERT(   stats->total.packed_size >= stats->total.expanded_size
-                  && stats->total.packed_size <= 2 * stats->total.expanded_size);
+  /* Expect the packed size to be sane, keeping in mind that it might
+   * be less or more than the expanded size due differences in the
+   * compression algorithms or options such as directory deltification. */
+  SVN_TEST_ASSERT(stats->total.packed_size <= 2 * stats->total.expanded_size);
   SVN_TEST_ASSERT(   stats->total.overhead_size >= 5 * expected_count
                   && stats->total.overhead_size <= 100 * expected_count);
 

Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c Wed Nov  7 12:30:06 2018
@@ -870,7 +870,7 @@ test_batch_fsync(const svn_test_opts_t *
 
   /* Initialize infrastructure with a pool that lives as long as this
    * application. */
-  SVN_ERR(svn_fs_x__batch_fsync_init());
+  SVN_ERR(svn_fs_x__batch_fsync_init(pool));
 
   /* We use and re-use the same batch object throughout this test. */
   SVN_ERR(svn_fs_x__batch_fsync_create(&batch, TRUE, pool));

Modified: subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c Wed Nov  7 12:30:06 2018
@@ -427,17 +427,7 @@ lock_cb(void *baton,
   struct lock_result_t *result = apr_palloc(b->pool,
                                             sizeof(struct lock_result_t));
 
-  if (lock)
-    {
-      result->lock = apr_palloc(b->pool, sizeof(svn_lock_t));
-      *result->lock = *lock;
-      result->lock->path = apr_pstrdup(b->pool, lock->path);
-      result->lock->token = apr_pstrdup(b->pool, lock->token);
-      result->lock->owner = apr_pstrdup(b->pool, lock->owner);
-      result->lock->comment = apr_pstrdup(b->pool, lock->comment);
-    }
-  else
-    result->lock = NULL;
+  result->lock = svn_lock_dup(lock, b->pool);
   result->err = ra_err;
 
   svn_hash_sets(b->results, apr_pstrdup(b->pool, path), result);
@@ -1682,6 +1672,118 @@ commit_empty_last_change(const svn_test_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+commit_locked_file(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  const char *url;
+  svn_ra_callbacks2_t *cbtable;
+  svn_ra_session_t *session;
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  void *root_baton;
+  void *file_baton;
+  struct lock_result_t *lock_result;
+  apr_hash_t *lock_tokens;
+  svn_txdelta_window_handler_t handler;
+  void *handler_baton;
+  svn_revnum_t fetched_rev;
+  apr_hash_t *fetched_props;
+  const svn_string_t *propval;
+
+  SVN_ERR(svn_test__create_repos2(NULL, &url, NULL,
+                                  "test-repo-commit-locked-file-test",
+                                  opts, pool, pool));
+
+  SVN_ERR(svn_ra_initialize(pool));
+  SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
+  SVN_ERR(svn_test__init_auth_baton(&cbtable->auth_baton, pool));
+
+  SVN_ERR(svn_ra_open4(&session, NULL, url, NULL, cbtable,
+                       NULL, NULL, pool));
+  SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+                                    apr_hash_make(pool),
+                                    NULL, NULL, NULL, TRUE, pool));
+  /* Add a file. */
+  SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
+                            pool, &root_baton));
+  SVN_ERR(editor->add_file("file", root_baton, NULL, SVN_INVALID_REVNUM,
+                           pool, &file_baton));
+  SVN_ERR(editor->close_file(file_baton, NULL, pool));
+  SVN_ERR(editor->close_directory(root_baton, pool));
+  SVN_ERR(editor->close_edit(edit_baton, pool));
+
+  /* Acquire a lock on this file. */
+  {
+    struct lock_baton_t baton = {0};
+    svn_revnum_t rev = 1;
+    apr_hash_t *lock_targets;
+
+    baton.results = apr_hash_make(pool);
+    baton.pool = pool;
+
+    lock_targets = apr_hash_make(pool);
+    svn_hash_sets(lock_targets, "file", &rev);
+    SVN_ERR(svn_ra_lock(session, lock_targets, "comment", FALSE,
+                        lock_cb, &baton, pool));
+
+    SVN_ERR(expect_lock("file", baton.results, session, pool));
+    lock_result = svn_hash_gets(baton.results, "file");
+  }
+
+  /* Open a new session using the file parent's URL. */
+  SVN_ERR(svn_ra_open4(&session, NULL, url, NULL, cbtable,
+                       NULL, NULL, pool));
+
+  /* Create a new commit editor supplying our lock token. */
+  lock_tokens = apr_hash_make(pool);
+  svn_hash_sets(lock_tokens, "file", lock_result->lock->token);
+  SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+                                    apr_hash_make(pool), NULL, NULL,
+                                    lock_tokens, TRUE, pool));
+  /* Edit the locked file. */
+  SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
+                            pool, &root_baton));
+  SVN_ERR(editor->open_file("file", root_baton, SVN_INVALID_REVNUM, pool,
+                            &file_baton));
+  SVN_ERR(editor->apply_textdelta(file_baton, NULL, pool, &handler,
+                                  &handler_baton));
+  SVN_ERR(svn_txdelta_send_string(svn_string_create("A", pool),
+                                  handler, handler_baton, pool));
+  SVN_ERR(editor->close_file(file_baton, NULL, pool));
+  SVN_ERR(editor->close_directory(root_baton, pool));
+  SVN_ERR(editor->close_edit(edit_baton, pool));
+
+  /* Check the result. */
+  SVN_ERR(svn_ra_get_file(session, "file", SVN_INVALID_REVNUM, NULL,
+                          &fetched_rev, NULL, pool));
+  SVN_TEST_INT_ASSERT((int) fetched_rev, 2);
+
+  /* Change property of the locked file. */
+  SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+                                    apr_hash_make(pool), NULL, NULL,
+                                    lock_tokens, TRUE, pool));
+  SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
+                            pool, &root_baton));
+  SVN_ERR(editor->open_file("file", root_baton, SVN_INVALID_REVNUM, pool,
+                            &file_baton));
+  SVN_ERR(editor->change_file_prop(file_baton, "propname",
+                                   svn_string_create("propval", pool),
+                                   pool));
+  SVN_ERR(editor->close_file(file_baton, NULL, pool));
+  SVN_ERR(editor->close_directory(root_baton, pool));
+  SVN_ERR(editor->close_edit(edit_baton, pool));
+
+  /* Check the result. */
+  SVN_ERR(svn_ra_get_file(session, "file", SVN_INVALID_REVNUM, NULL,
+                          &fetched_rev, &fetched_props, pool));
+  SVN_TEST_INT_ASSERT((int) fetched_rev, 3);
+  propval = svn_hash_gets(fetched_props, "propname");
+  SVN_TEST_ASSERT(propval);
+  SVN_TEST_STRING_ASSERT(propval->data, "propval");
+
+  return SVN_NO_ERROR;
+}
+
 
 /* The test table.  */
 
@@ -1716,6 +1818,8 @@ static struct svn_test_descriptor_t test
                        "verify checkout over a tunnel"),
     SVN_TEST_OPTS_PASS(commit_empty_last_change,
                        "check how last change applies to empty commit"),
+    SVN_TEST_OPTS_PASS(commit_locked_file,
+                       "check commit editor for a locked file"),
     SVN_TEST_NULL
   };
 

Propchange: subversion/branches/ra-git/subversion/tests/libsvn_repos/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Nov  7 12:30:06 2018
@@ -11,3 +11,4 @@ md5args
 .*~
 *.exe
 dump-load-test
+authz-test

Modified: subversion/branches/ra-git/subversion/tests/libsvn_repos/dump-load-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_repos/dump-load-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_repos/dump-load-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_repos/dump-load-test.c Wed Nov  7 12:30:06 2018
@@ -79,9 +79,9 @@ test_dump_bad_props(svn_stringbuf_t **du
   SVN_ERR(svn_repos_dump_fs4(repos, stream, start_rev, end_rev,
                              FALSE, FALSE, TRUE, TRUE,
                              notify_func, notify_baton,
-                             NULL, NULL,
+                             NULL, NULL, NULL, NULL,
                              pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_stream_close(stream));
 
   /* Check that the property appears in the dump data */
   expected_str = apr_psprintf(pool, "K %d\n%s\n"
@@ -120,17 +120,18 @@ test_load_bad_props(svn_stringbuf_t *dum
   svn_revnum_t youngest_rev;
   svn_string_t *loaded_prop_val;
 
-  SVN_ERR(svn_repos_load_fs5(repos, stream,
+  SVN_ERR(svn_repos_load_fs6(repos, stream,
                              SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
                              svn_repos_load_uuid_default,
                              parent_fspath,
                              FALSE, FALSE, /*use_*_commit_hook*/
                              validate_props,
                              FALSE /*ignore_dates*/,
+                             FALSE /*normalize_props*/,
                              notify_func, notify_baton,
                              NULL, NULL, /*cancellation*/
                              pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_stream_close(stream));
 
   /* Check the loaded property */
   fs = svn_repos_fs(repos);

Modified: subversion/branches/ra-git/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_repos/repos-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_repos/repos-test.c Wed Nov  7 12:30:06 2018
@@ -22,7 +22,9 @@
 
 #include <stdlib.h>
 #include <string.h>
+
 #include <apr_pools.h>
+#include <apr_time.h>
 
 #include "../svn_test.h"
 
@@ -1282,7 +1284,7 @@ authz(apr_pool_t *pool)
   contents =
     "[greek:/A]"                                                             NL
     "* = r"                                                                  NL
-    "plato = w"                                                              NL
+    "plato = rw"                                                             NL
     ""                                                                       NL
     "[greek:/iota]"                                                          NL
     "* ="                                                                    NL
@@ -1381,11 +1383,536 @@ authz(apr_pool_t *pool)
   SVN_TEST_ASSERT_ERROR(authz_get_handle(&authz_cfg, contents, FALSE, subpool),
                         SVN_ERR_AUTHZ_INVALID_CONFIG);
 
+  /* Verify that the rule on /dir2/secret doesn't affect this
+     request */
+  SVN_ERR(svn_repos_authz_check_access(authz_cfg, "greek",
+                                       "/dir", NULL,
+                                       (svn_authz_read
+                                        | svn_authz_recursive),
+                                       &access_granted, subpool));
+  if (!access_granted)
+    return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
+                            "Regression: incomplete ancestry test "
+                            "for recursive access lookup.");
+
   /* That's a wrap! */
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 
+/* Test the supported authz wildcard variants. */
+static svn_error_t *
+test_authz_wildcards(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+
+  /* Some non-trivially overlapping wildcard rules, convering all types
+   * of wildcards: "any", "any-var", "prefix", "postfix" and "complex".
+   *
+   * Note that the rules are not in 1:1 correspondence to that enumeration.
+   */
+  const char *contents =
+    "[:glob:/**/G]"                                                          NL
+    "* = r"                                                                  NL
+    ""                                                                       NL
+    "[:glob:/A/*/G]"                                                         NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:/A/**/*a*]"                                                      NL
+    "* = r"                                                                  NL
+    ""                                                                       NL
+    "[:glob:/**/*a]"                                                         NL
+    "* = rw"                                                                 NL
+    ""                                                                       NL
+    "[:glob:/A/**/g*]"                                                       NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:/**/lambda]"                                                     NL
+    "* = rw"                                                                 NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set[] = {
+    /* Test that read rules are correctly used. */
+    { "/", NULL, NULL, svn_authz_read, FALSE },              /* default */
+    { "/iota", NULL, NULL, svn_authz_write, TRUE },          /* rule 4 */
+    { "/A", NULL, NULL, svn_authz_read, FALSE },             /* inherited */
+    { "/A/mu", NULL, NULL, svn_authz_read, FALSE },          /* inherited */
+    { "/A/B", NULL, NULL, svn_authz_read, FALSE },           /* inherited */
+    { "/A/B/lambda", NULL, NULL, svn_authz_write, TRUE },    /* rule 6 */
+    { "/A/B/E", NULL, NULL, svn_authz_read, FALSE },         /* inherited */
+    { "/A/B/E/alpha", NULL, NULL, svn_authz_write, TRUE },   /* rule 4 */
+    { "/A/B/E/beta", NULL, NULL, svn_authz_write, TRUE },    /* rule 4 */
+    { "/A/B/F", NULL, NULL, svn_authz_read, FALSE },         /* inherited */
+    { "/A/C", NULL, NULL, svn_authz_read, FALSE },           /* inherited */
+    { "/A/D", NULL, NULL, svn_authz_read, FALSE },           /* inherited */
+    { "/A/D/gamma", NULL, NULL, svn_authz_read, FALSE },     /* rule 5 */
+    { "/A/D/G", NULL, NULL, svn_authz_read, FALSE },         /* rule 2 */
+    { "/A/D/G/pi", NULL, NULL, svn_authz_read, FALSE },      /* inherited */
+    { "/A/D/G/rho", NULL, NULL, svn_authz_read, FALSE },     /* inherited */
+    { "/A/D/G/tau", NULL, NULL, svn_authz_read, TRUE },      /* rule 3 */
+    { "/A/D/G/tau", NULL, NULL, svn_authz_write, FALSE },    /* rule 3 */
+    { "/A/D/H", NULL, NULL, svn_authz_read, FALSE },         /* inherited */
+    { "/A/D/H/chi", NULL, NULL, svn_authz_read, FALSE },     /* inherited */
+    { "/A/D/H/psi", NULL, NULL, svn_authz_read, FALSE },     /* inherited */
+    { "/A/D/H/omega", NULL, NULL, svn_authz_write, TRUE },   /* rule 4 */
+    /* Non-greek tree paths: */
+    { "/A/G", NULL, NULL, svn_authz_read, TRUE },            /* rule 1 */
+    { "/A/G", NULL, NULL, svn_authz_write, FALSE },          /* rule 1 */
+    { "/A/G/G", NULL, NULL, svn_authz_read, FALSE },         /* rule 2 */
+    { "/G", NULL, NULL, svn_authz_read, TRUE },              /* rule 1 */
+    { "/G", NULL, NULL, svn_authz_write, FALSE },            /* rule 1 */
+    { "/Y/G", NULL, NULL, svn_authz_read, TRUE },            /* rule 1 */
+    { "/Y/G", NULL, NULL, svn_authz_write, FALSE },          /* rule 1 */
+    { "/X/Z/G", NULL, NULL, svn_authz_read, TRUE },          /* rule 1 */
+    { "/X/Z/G", NULL, NULL, svn_authz_write, FALSE },        /* rule 1 */
+    /* Rule 5 prevents recursive access anywhere below /A. */
+    { "/", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/iota", NULL, NULL, svn_authz_read | svn_authz_recursive, TRUE },
+    { "/iota", NULL, NULL, svn_authz_write | svn_authz_recursive, FALSE },
+    { "/A", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/mu", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/lambda", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/E", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/E/alpha", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/E/beta", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/B/F", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/C", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/gamma", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G/pi", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G/rho", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/G/tau", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H/chi", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H/psi", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    { "/A/D/H/omega", NULL, NULL, svn_authz_read | svn_authz_recursive, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Load the test authz rules. */
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+
+  /* Loop over the test array and test each case. */
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Test the authz performance with wildcard rules. */
+static svn_error_t *
+test_authz_wildcard_performance(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+  svn_boolean_t access_granted;
+  int i, k;
+  apr_time_t start, end;
+
+  /* Some non-trivially overlapping wildcard rules, convering all types
+   * of wildcards: "any", "any-var", "prefix", "postfix" and "complex".
+   */
+  const char *contents =
+    "[:glob:greek:/A/*/G]"                                                   NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:greek:/A/**/*a*]"                                                NL
+    "* = r"                                                                  NL
+    ""                                                                       NL
+    "[:glob:greek:/**/*a]"                                                   NL
+    "* = rw"                                                                 NL
+    ""                                                                       NL
+    "[:glob:greek:/A/**/g*]"                                                 NL
+    "* ="                                                                    NL
+    ""                                                                       NL
+    "[:glob:greek:/**/lambda]"                                               NL
+    "* = rw"                                                                 NL;
+
+  /* Load the test authz rules. */
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+
+  start = apr_time_now();
+  for (k = 0; k < 100000; ++k)
+    for (i = 1; i < 4; ++i)
+      {
+        const char **path;
+        const char *paths[] =
+        { "/iota",
+          "/A",
+          "/A/mu",
+          "/A/B",
+          "/A/B/lambda",
+          "/A/B/E",
+          "/A/B/E/alpha",
+          "/A/B/E/beta",
+          "/A/B/F",
+          "/A/C",
+          "/A/D",
+          "/A/D/gamma",
+          "/A/D/G",
+          "/A/D/G/pi",
+          "/A/D/G/rho",
+          "/A/D/G/tau",
+          "/A/D/H",
+          "/A/D/H/chi",
+          "/A/D/H/psi",
+          "/A/D/H/omega",
+          NULL
+        };
+
+        for (path = paths; *path; ++path)
+          SVN_ERR(svn_repos_authz_check_access(authz_cfg, "greek",
+                                               *path, NULL, i,
+                                               &access_granted, pool));
+      }
+
+  end = apr_time_now();
+  printf("%"APR_TIME_T_FMT" musecs\n", end - start);
+  printf("%"APR_TIME_T_FMT" checks / sec\n",
+           (k * (i - 1) * 20 * 1000000l) / (end - start));
+
+  return SVN_NO_ERROR;
+}
+
+/* Test that the latest definition wins, regardless of whether the ":glob:"
+ * prefix has been given. */
+static svn_error_t *
+test_authz_prefixes(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  int i, combi;
+
+  /* Set all rights at some folder and replace them again.  Make sure to
+   * cover the "/" b/c that already has an implicit rule, so we* overwrite
+   * it twice.  The first 2 string placeholders in the rules are for the
+   * repository name and the optional glob support marker. */
+  const char *contents_format =
+    "[%s%s%s]"                                                              NL
+    "* = r"                                                                 NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[%s%s%s]"                                                              NL
+    "* ="                                                                   NL
+    "plato = r"                                                             NL;
+
+  /* The paths on which to apply this test. */
+  enum { PATH_COUNT = 2 };
+  const char *test_paths[PATH_COUNT] = { "/", "/A" };
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set1[] = {
+    /* Test that read rules are correctly used. */
+    { "", "greek", NULL, svn_authz_read, FALSE },
+    /* Test that write rules are correctly used. */
+    { "", "greek", "plato", svn_authz_read, TRUE },
+    { "", "greek", "plato", svn_authz_write, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* To be used when global rules are specified after per-repos rules.
+   * In that case, the global rules still win. */
+  struct check_access_tests test_set2[] = {
+    /* Test that read rules are correctly used. */
+    { "", "greek", NULL, svn_authz_read, TRUE },
+    { "", "greek", NULL, svn_authz_write, FALSE },
+    /* Test that write rules are correctly used. */
+    { "", "greek", "plato", svn_authz_read, TRUE },
+    { "", "greek", "plato", svn_authz_write, TRUE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* There is a total of 16 combinations of authz content. */
+  for (combi = 0; combi < 16; ++combi)
+    {
+      const char *contents;
+      const char *glob1 = (combi & 1) ? ":glob:" : "";
+      const char *glob2 = (combi & 2) ? ":glob:" : "";
+      const char *repo1 = (combi & 4) ? "greek:" : "";
+      const char *repo2 = (combi & 4) ? "" : "greek:";
+      const char *test_path = test_paths[combi / 8];
+      struct check_access_tests *test_set = (combi & 4) ? test_set2 : test_set1;
+
+      /* Create and parse the authz rules. */
+      svn_pool_clear(iterpool);
+      contents = apr_psprintf(iterpool, contents_format,
+                              glob1, repo1, test_path,
+                              glob2, repo2, test_path);
+      SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, iterpool));
+
+      /* iterate over all test paths */
+      for (i = combi / 8; i < PATH_COUNT; ++i)
+        {
+          /* Set the path for all test cases to the current test path. */
+          struct check_access_tests *test;
+          for (test = test_set; test->path != NULL; ++test)
+            test->path = test_paths[i];
+
+          /* Loop over the test array and test each case. */
+          SVN_ERR(authz_check_access(authz_cfg, test_set, iterpool));
+        }
+    }
+
+  /* That's a wrap! */
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_authz_recursive_override(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+
+  /* Set all rights at some folder and replace them again.  Make sure to
+   * cover the "/" b/c that already has an implicit rule, so we* overwrite
+   * it twice.  The first 2 string placeholders in the rules are for the
+   * repository name and the optional glob support marker. */
+  const char *contents =
+    "[:glob:/A/B]"                                                          NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/A/**]"                                                         NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[:glob:/B/C]"                                                          NL
+    "plato ="                                                               NL
+    ""                                                                      NL
+    "[:glob:/B/**]"                                                         NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/C/D]"                                                          NL
+    "plato = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/C/**/E]"                                                       NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[:glob:/D/E]"                                                          NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[:glob:/D/**/F]"                                                       NL
+    "plato = rw"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set[] = {
+    /* The root shall not be affected -> defaults to "no access". */
+    { "/", NULL, "plato", svn_authz_read, FALSE },
+    /* Recursive restriction of rights shall work. */
+    { "/A", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/A", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    /* Recursive extension of rights shall work. */
+    { "/B", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/B", NULL, "plato", svn_authz_write | svn_authz_recursive, TRUE },
+    /* Partial replacements shall not result in recursive rights. */
+    { "/C", NULL, "plato", svn_authz_read | svn_authz_recursive, FALSE },
+    { "/C/D", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/C/D", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/D", NULL, "plato", svn_authz_read | svn_authz_recursive, FALSE },
+    { "/D/E", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/D/E", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+
+  /* Loop over the test array and test each case. */
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  /* That's a wrap! */
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_authz_pattern_tests(apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+
+  /* Rules will be considered for recursive access checks irrespective of
+   * whether the respective paths actually do exist. */
+  const char *contents =
+    "[:glob:/**/Yeti]"                                                      NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[/]"                                                                   NL
+    "plato = r"                                                             NL
+    ""                                                                      NL
+    "[/trunk]"                                                              NL
+    "plato = rw"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set[] = {
+    /* We have no recursive write access anywhere. */
+    { "/", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/trunk", NULL, "plato", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/trunk", NULL, "plato", svn_authz_write | svn_authz_recursive, FALSE },
+
+    /* We do have ordinary write access to anything under /trunk that is
+     * not a Yeti. */
+    { "/trunk", NULL, "plato", svn_authz_write, TRUE },
+    { "/trunk/A/B/C", NULL, "plato", svn_authz_write, TRUE },
+
+    /* We don't have write access to Yetis. */
+    { "/trunk/A/B/C/Yeti", NULL, "plato", svn_authz_write, FALSE },
+    { "/trunk/Yeti", NULL, "plato", svn_authz_write, FALSE },
+    { "/Yeti", NULL, "plato", svn_authz_write, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Global override via "**" and selective override for a specific path. */
+  const char *contents2 =
+    "[:glob:/X]"                                                            NL
+    "user1 ="                                                               NL
+    ""                                                                      NL
+    "[:glob:/X/**]"                                                         NL
+    "user1 = rw"                                                            NL
+    "user2 = rw"                                                            NL
+    ""                                                                      NL
+    "[:glob:/X/Y/Z]"                                                        NL
+    "user2 ="                                                               NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set2[] = {
+    /* No access at the root*/
+    { "/", NULL, "user1", svn_authz_read, FALSE },
+    { "/", NULL, "user2", svn_authz_read, FALSE },
+
+    /* User 1 has recursive write access anywhere. */
+    { "/X", NULL, "user1", svn_authz_write | svn_authz_recursive, TRUE },
+    { "/X/Y", NULL, "user1", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/X/Y/Z", NULL, "user1", svn_authz_read | svn_authz_recursive, TRUE },
+
+    /* User 2 only has recursive read access to X/Y/Z. */
+    { "/X", NULL, "user1", svn_authz_read | svn_authz_recursive, TRUE },
+    { "/X", NULL, "user2", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/X/Y", NULL, "user2", svn_authz_write | svn_authz_recursive, FALSE },
+    { "/X/Y/Z", NULL, "user2", svn_authz_write | svn_authz_recursive, FALSE },
+
+    /* However, user2 has ordinary write access X and recursive write access
+     * to anything not in X/Y/Z. */
+    { "/X", NULL, "user2", svn_authz_write, TRUE },
+    { "/X/A", NULL, "user2", svn_authz_write | svn_authz_recursive, TRUE },
+    { "/X/Y/A", NULL, "user2", svn_authz_write | svn_authz_recursive, TRUE },
+
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Global patterns vs. global path rules. */
+  const char *contents3 =
+    "[groups]"                                                              NL
+    "Team1 = user1"                                                         NL
+    "Team2 = user1, user2"                                                  NL
+    ""                                                                      NL
+    "[/]"                                                                   NL
+    "* ="                                                                   NL
+    ""                                                                      NL
+    "[:glob:Repo1:/**/folder*]"                                             NL
+    "@Team1 = rw"                                                           NL
+    ""                                                                      NL
+    "[Repo2:/]"                                                             NL
+    "@Team2 = r"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set3[] = {
+    /* No access at the root of Repo1 (inherited from global settings) */
+    { "/", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/", "Repo1", "user2", svn_authz_read, FALSE },
+
+    /* r/o access for both users at the root of Repo2 */
+    { "/", "Repo2", "user1", svn_authz_read, TRUE },
+    { "/", "Repo2", "user2", svn_authz_read, TRUE },
+    { "/", "Repo2", "user1", svn_authz_write, FALSE },
+    { "/", "Repo2", "user2", svn_authz_write, FALSE },
+
+    /* user1 has recursive write access (b/c there are no further rules
+     * restricting the access once granted at the parent) wherever there is
+     * a "folder..." in the  path, while user2 has no access at all. */
+    { "/folder_1", "Repo1", "user1",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/folder_1", "Repo1", "user2", svn_authz_read, FALSE },
+    { "/1_folder", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/foo/bar/folder_2/random", "Repo1", "user1",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/foo/bar/folder_2/random", "Repo1", "user2", svn_authz_read, FALSE },
+    { "/foo/bar/2_folder/random", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/foo/bar/folder", "Repo1", "user1",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/foo/bar/folder", "Repo1", "user2", svn_authz_read, FALSE },
+
+    /* Doesn't quite match the pattern: */
+    { "/foo/bar/folde", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/foo/bar/folde", "Repo1", "user2", svn_authz_read, FALSE },
+
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Illustrate the difference between "matching" rule and "applying" rule.
+   * "*" only _matches_ a single level and will _apply_ to sub-paths only
+   * if no other rule _applies_.  The "**" rule applies to all paths in
+   * trunk and will only be eclipsed for members of team1 and then only for
+   * the first sub-level. */
+  const char *contents4 =
+    "[groups]"                                                              NL
+    "team1 = user1, user3"                                                  NL
+    "team2 = user2, user3"                                                  NL
+    ""                                                                      NL
+    "[:glob:Repo1:/trunk/**]"                                               NL
+    "@team2 = rw"                                                           NL
+    ""                                                                      NL
+    "[:glob:Repo1:/trunk/*]"                                                NL
+    "@team1 = r"                                                            NL;
+
+  /* Definition of the paths to test and expected replies for each. */
+  struct check_access_tests test_set4[] = {
+    /* Team2 has r/w access to /trunk */
+    { "/trunk", "Repo1", "user1", svn_authz_read, FALSE },
+    { "/trunk", "Repo1", "user2", svn_authz_write, TRUE },
+    { "/trunk", "Repo1", "user3", svn_authz_write, TRUE },
+
+    /* At the first sub-level, team1 has only read access;
+     * the remainder of team2 has write access. */
+    { "/trunk/A", "Repo1", "user1", svn_authz_read, TRUE },
+    { "/trunk/A", "Repo1", "user3", svn_authz_read, TRUE },
+    { "/trunk/A", "Repo1", "user1", svn_authz_write, FALSE },
+    { "/trunk/A", "Repo1", "user2", svn_authz_write, TRUE },
+    { "/trunk/A", "Repo1", "user3", svn_authz_write, FALSE },
+
+    /* At the second sub-level, team2 has full write access;
+     * the remainder of team1 has still r/o access. */
+    { "/trunk/A/B", "Repo1", "user2",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/trunk/A/B", "Repo1", "user3",
+      svn_authz_write | svn_authz_recursive, TRUE },
+    { "/trunk/A/B", "Repo1", "user1", svn_authz_read, TRUE },
+    { "/trunk/A/B", "Repo1", "user1", svn_authz_write, FALSE },
+
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Verify that the rules are applies as expected. */
+  SVN_ERR(authz_get_handle(&authz_cfg, contents, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents2, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set2, pool));
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents3, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set3, pool));
+
+  SVN_ERR(authz_get_handle(&authz_cfg, contents4, FALSE, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set4, pool));
+
+  /* That's a wrap! */
+  return SVN_NO_ERROR;
+}
+
 
 /* Test in-repo authz paths */
 static svn_error_t *
@@ -1798,7 +2325,7 @@ groups_authz(const svn_test_opts_t *opts
 
   SVN_ERR(authz_check_access(authz_cfg, test_set1, pool));
 
-  /* Access rights in the global groups file are discarded. */
+  /* Access rights in the global groups file are forbidden. */
   groups_contents =
     "[groups]"                                                               NL
     "philosophers = socrates"                                                NL
@@ -1812,6 +2339,19 @@ groups_authz(const svn_test_opts_t *opts
     "@philosophers = rw"                                                     NL
     ""                                                                       NL;
 
+  SVN_TEST_ASSERT_ERROR(
+      authz_groups_get_handle(&authz_cfg, authz_contents,
+                              groups_contents, TRUE, pool),
+      SVN_ERR_AUTHZ_INVALID_CONFIG);
+  SVN_TEST_ASSERT_ERROR(
+      authz_groups_get_handle(&authz_cfg, authz_contents,
+                              groups_contents, FALSE, pool),
+      SVN_ERR_AUTHZ_INVALID_CONFIG);
+
+  groups_contents =
+    "[groups]"                                                               NL
+    "philosophers = socrates"                                                NL
+    ""                                                                       NL;
   SVN_ERR(authz_groups_get_handle(&authz_cfg, authz_contents,
                                   groups_contents, TRUE, pool));
 
@@ -3350,18 +3890,14 @@ test_config_pool(const svn_test_opts_t *
   svn_error_t *err;
 
   svn_repos__config_pool_t *config_pool;
-  apr_pool_t *config_pool_pool;
   apr_pool_t *subpool = svn_pool_create(pool);
 
   const char *wrk_dir = svn_test_data_path("config_pool", pool);
 
   SVN_ERR(svn_io_make_dir_recursively(wrk_dir, pool));
 
-  /* read all config info through a single config pool and we want to be
-     able to control its lifetime.  The latter requires a separate pool. */
-  config_pool_pool = svn_pool_create(pool);
-  SVN_ERR(svn_repos__config_pool_create(&config_pool, TRUE,
-                                        config_pool_pool));
+  /* read all config info through a single config pool. */
+  SVN_ERR(svn_repos__config_pool_create(&config_pool, TRUE, pool));
 
   /* have two different configurations  */
   SVN_ERR(svn_test_get_srcdir(&srcdir, opts, pool));
@@ -3402,11 +3938,11 @@ test_config_pool(const svn_test_opts_t *
   for (i = 0; i < 4; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
-                                    &cfg, NULL, config_pool,
+                                    &cfg, config_pool,
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test1.cfg",
                                                     pool),
-                                    TRUE, TRUE, NULL, subpool));
+                                    TRUE, NULL, subpool));
 
       if (sections1 == NULL)
         sections1 = cfg->sections;
@@ -3421,11 +3957,11 @@ test_config_pool(const svn_test_opts_t *
   for (i = 0; i < 4; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
-                                    &cfg, NULL, config_pool,
+                                    &cfg, config_pool,
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test2.cfg",
                                                     pool),
-                                    TRUE, TRUE, NULL, subpool));
+                                    TRUE, NULL, subpool));
 
       SVN_TEST_ASSERT(cfg->sections == sections1);
 
@@ -3437,11 +3973,11 @@ test_config_pool(const svn_test_opts_t *
   for (i = 0; i < 2; ++i)
     {
       SVN_ERR(svn_repos__config_pool_get(
-                                    &cfg, NULL, config_pool,
+                                    &cfg, config_pool,
                                     svn_dirent_join(wrk_dir,
                                                     "config-pool-test3.cfg",
                                                     pool),
-                                    TRUE, TRUE, NULL, subpool));
+                                    TRUE, NULL, subpool));
 
       if (sections2 == NULL)
         sections2 = cfg->sections;
@@ -3467,11 +4003,11 @@ test_config_pool(const svn_test_opts_t *
   SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
 
   /* reading the config from the repo should still give cfg1 */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
@@ -3485,48 +4021,48 @@ test_config_pool(const svn_test_opts_t *
   SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
 
   /* reading the config from the repo should give cfg2 now */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections2);
   svn_pool_clear(subpool);
 
   /* reading the copied config should still give cfg1 */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "another-dir/config",
                                                     pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
   /* once again: repeated reads.  This triggers a different code path. */
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "dir/config", pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections2);
-  SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                      svn_path_url_add_component2(
                                                     repo_root_url,
                                                     "another-dir/config",
                                                     pool),
-                                     TRUE, TRUE, NULL, subpool));
+                                     TRUE, NULL, subpool));
   SVN_TEST_ASSERT(cfg->sections == sections1);
   svn_pool_clear(subpool);
 
   /* access paths that don't exist */
-  SVN_TEST_ASSERT_ERROR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+  SVN_TEST_ASSERT_ERROR(svn_repos__config_pool_get(&cfg, config_pool,
                           svn_path_url_add_component2(repo_root_url, "X",
                                                       pool),
-                          TRUE, TRUE, NULL, subpool),
+                          TRUE, NULL, subpool),
                         SVN_ERR_ILLEGAL_TARGET);
-  err = svn_repos__config_pool_get(&cfg, NULL, config_pool, "X.cfg",
-                                   TRUE, TRUE, NULL, subpool);
+  err = svn_repos__config_pool_get(&cfg, config_pool, "X.cfg", TRUE, NULL,
+                                   subpool);
   SVN_TEST_ASSERT(err && APR_STATUS_IS_ENOENT(err->apr_err));
   svn_error_clear(err);
   svn_pool_clear(subpool);
@@ -3925,7 +4461,7 @@ test_list(const svn_test_opts_t *opts,
   SVN_ERR(svn_repos_list(rev_root, "/A", patterns, svn_depth_infinity, FALSE,
                          NULL, NULL, list_callback, &counter, NULL, NULL,
                          pool));
-  SVN_TEST_ASSERT(counter == 6);
+  SVN_TEST_ASSERT(counter == 7);
 
   return SVN_NO_ERROR;
 }
@@ -3989,6 +4525,16 @@ static struct svn_test_descriptor_t test
                        "authz for svn_repos_trace_node_locations"),
     SVN_TEST_OPTS_PASS(commit_aborted_txn,
                        "test committing a previously aborted txn"),
+    SVN_TEST_PASS2(test_authz_prefixes,
+                   "test authz prefixes"),
+    SVN_TEST_PASS2(test_authz_recursive_override,
+                   "test recursively authz rule override"),
+    SVN_TEST_PASS2(test_authz_pattern_tests,
+                   "test various basic authz pattern combinations"),
+    SVN_TEST_PASS2(test_authz_wildcards,
+                   "test the different types of authz wildcards"),
+    SVN_TEST_SKIP2(test_authz_wildcard_performance, TRUE,
+                   "optional authz wildcard performance test"),
     SVN_TEST_OPTS_PASS(test_list,
                        "test svn_repos_list"),
     SVN_TEST_NULL

Propchange: subversion/branches/ra-git/subversion/tests/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Nov  7 12:30:06 2018
@@ -10,6 +10,7 @@ Debug
 Release
 checksum-test
 compat-test
+compress-test
 config-test
 crypto-test
 error-test
@@ -54,3 +55,4 @@ io-test-*
 sqlite-test-*
 x509-test
 xml-test
+test_apr_trunc_workaround

Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/auth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/auth-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_subr/auth-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_subr/auth-test.c Wed Nov  7 12:30:06 2018
@@ -50,7 +50,7 @@ test_platform_specific_auth_providers(ap
   SVN_ERR(svn_auth_get_platform_specific_client_providers(&providers, NULL,
                                                           pool));
 
-#ifdef SVN_HAVE_GNOME_KEYRING
+#if defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_LIBSECRET)
   number_of_providers += 2;
 #endif
 #ifdef SVN_HAVE_KWALLET
@@ -145,7 +145,7 @@ test_platform_specific_auth_providers(ap
 #endif
 
   /* Test GNOME Keyring auth providers */
-#ifdef SVN_HAVE_GNOME_KEYRING
+#if defined(SVN_HAVE_GNOME_KEYRING) || defined(SVN_HAVE_LIBSECRET)
   SVN_ERR(svn_auth_get_platform_specific_provider(&provider, "gnome_keyring",
                                                   "simple", pool));
 

Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/checksum-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/checksum-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_subr/checksum-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_subr/checksum-test.c Wed Nov  7 12:30:06 2018
@@ -296,6 +296,74 @@ test_checksum_parse_all_zero(apr_pool_t
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_checksummed_stream_read(apr_pool_t *pool)
+{
+  const svn_string_t *str = svn_string_create("abcde", pool);
+  svn_checksum_kind_t kind;
+
+  for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
+    {
+      svn_stream_t *stream;
+      svn_checksum_t *expected_checksum;
+      svn_checksum_t *actual_checksum;
+      char buf[64];
+      apr_size_t len;
+
+      stream = svn_stream_from_string(str, pool);
+      stream = svn_stream_checksummed2(stream, &actual_checksum, NULL,
+                                       kind, TRUE, pool);
+      len = str->len;
+      SVN_ERR(svn_stream_read_full(stream, buf, &len));
+      SVN_TEST_INT_ASSERT((int) len, str->len);
+
+      SVN_ERR(svn_stream_close(stream));
+
+      SVN_ERR(svn_checksum(&expected_checksum, kind,
+                           str->data, str->len, pool));
+      SVN_TEST_ASSERT(svn_checksum_match(expected_checksum, actual_checksum));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_checksummed_stream_reset(apr_pool_t *pool)
+{
+  const svn_string_t *str = svn_string_create("abcde", pool);
+  svn_checksum_kind_t kind;
+
+  for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
+    {
+      svn_stream_t *stream;
+      svn_checksum_t *expected_checksum;
+      svn_checksum_t *actual_checksum;
+      char buf[64];
+      apr_size_t len;
+
+      stream = svn_stream_from_string(str, pool);
+      stream = svn_stream_checksummed2(stream, &actual_checksum, NULL,
+                                       kind, TRUE, pool);
+      len = str->len;
+      SVN_ERR(svn_stream_read_full(stream, buf, &len));
+      SVN_TEST_INT_ASSERT((int) len, str->len);
+
+      SVN_ERR(svn_stream_reset(stream));
+
+      len = str->len;
+      SVN_ERR(svn_stream_read_full(stream, buf, &len));
+      SVN_TEST_INT_ASSERT((int) len, str->len);
+
+      SVN_ERR(svn_stream_close(stream));
+
+      SVN_ERR(svn_checksum(&expected_checksum, kind,
+                           str->data, str->len, pool));
+      SVN_TEST_ASSERT(svn_checksum_match(expected_checksum, actual_checksum));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* An array of all test functions */
 
 static int max_threads = 1;
@@ -317,6 +385,10 @@ static struct svn_test_descriptor_t test
                    "checksum (de-)serialization"),
     SVN_TEST_PASS2(test_checksum_parse_all_zero,
                    "checksum parse all zero"),
+    SVN_TEST_PASS2(test_checksummed_stream_read,
+                   "read from checksummed stream"),
+    SVN_TEST_PASS2(test_checksummed_stream_reset,
+                   "reset checksummed stream"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.c Wed Nov  7 12:30:06 2018
@@ -37,6 +37,7 @@
 #include "svn_error.h"
 #include "svn_config.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_config_private.h"
 
 #include "../svn_test.h"
 
@@ -69,12 +70,12 @@ get_config_file_path(const char **cfg_fi
 }
 
 static const char *config_keys[] = { "foo", "a", "b", "c", "d", "e", "f", "g",
-                                     "h", "i", NULL };
+                                     "h", "i", "m", NULL };
 static const char *config_values[] = { "bar", "Aa", "100", "bar",
                                        "a %(bogus)s oyster bar",
                                        "%(bogus)s shmoo %(",
                                        "%Aa", "lyrical bard", "%(unterminated",
-                                       "Aa 100", NULL };
+                                       "Aa 100", "foo bar baz", NULL };
 
 static svn_error_t *
 test_text_retrieval(const svn_test_opts_t *opts,
@@ -403,6 +404,60 @@ test_invalid_bom(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_serialization(apr_pool_t *pool)
+{
+  svn_stringbuf_t *original_content;
+  svn_stringbuf_t *written_content;
+  svn_config_t *cfg;
+
+  const struct
+    {
+      const char *section;
+      const char *option;
+      const char *value;
+    } test_data[] =
+    {
+      { "my section", "value1", "some" },
+      { "my section", "value2", "something" },
+      { "another Section", "value1", "one" },
+      { "another Section", "value2", "two" },
+      { "another Section", "value 3", "more" },
+    };
+  int i;
+
+  /* Format the original with the same formatting that the writer will use. */
+  original_content = svn_stringbuf_create("\n[my section]\n"
+                                          "value1=some\n"
+                                          "value2=%(value1)sthing\n"
+                                          "\n[another Section]\n"
+                                          "value1=one\n"
+                                          "value2=two\n"
+                                          "value 3=more\n",
+                                          pool);
+  written_content = svn_stringbuf_create_empty(pool);
+
+  SVN_ERR(svn_config_parse(&cfg,
+                           svn_stream_from_stringbuf(original_content, pool),
+                           TRUE, TRUE, pool));
+  SVN_ERR(svn_config__write(svn_stream_from_stringbuf(written_content, pool),
+                            cfg, pool));
+  SVN_ERR(svn_config_parse(&cfg,
+                           svn_stream_from_stringbuf(written_content, pool),
+                           TRUE, TRUE, pool));
+
+  /* The serialized and re-parsed config must have the expected contents. */
+  for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
+    {
+      const char *val;
+      svn_config_get(cfg, &val, test_data[i].section, test_data[i].option,
+                     NULL);
+      SVN_TEST_STRING_ASSERT(val, test_data[i].value);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /*
    ====================================================================
    If you add a new test to this file, update this array.
@@ -437,6 +492,8 @@ static struct svn_test_descriptor_t test
                        "test variable expansion"),
     SVN_TEST_PASS2(test_invalid_bom,
                    "test parsing config file with invalid BOM"),
+    SVN_TEST_PASS2(test_serialization,
+                   "test writing a config"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.cfg
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.cfg?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.cfg (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_subr/config-test.cfg Wed Nov  7 12:30:06 2018
@@ -45,6 +45,10 @@ j=some %(k)scle
 k=c%(j)sy
 # Depends on a cyclic definition
 l=depends on a %(j)scycle!
+# line continuation
+m = foo
+ bar
+  baz
 
 [UpperCaseSection]
 a=Aa

Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/dirent_uri-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/dirent_uri-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_subr/dirent_uri-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_subr/dirent_uri-test.c Wed Nov  7 12:30:06 2018
@@ -938,6 +938,13 @@ static const testcase_canonicalize_t uri
     /* Hostnames that look like non-canonical paths */
     { "file://./foo",             "file://./foo" },
     { "http://./foo",             "http://./foo" },
+    /* Some invalid URLs, these still have a canonical form */
+    { "http://server:81:81/",  "http://server:81:81" },
+    { "http://server:81foo/",  "http://server:81foo" },
+    { "http://server::/",      "http://server::" },
+    { "http://server:-/",      "http://server:-" },
+    { "http://hst:1.2.3.4.5/", "http://hst:1.2.3.4.5"},
+    { "http://hst:1.2.999.4/", "http://hst:1.2.999.4"},
   /* svn_uri_is_canonical() was a private function in the 1.6 API, and
      has since taken a MAJOR change of direction, namely that only
      absolute URLs are considered canonical uris now. */
@@ -1238,6 +1245,12 @@ test_uri_is_canonical(apr_pool_t *pool)
                                  t->path,
                                  canonical ? "TRUE" : "FALSE",
                                  t->result);
+
+      if (t->result && !svn_uri_is_canonical(t->result, pool))
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "svn_uri_is_canonical(\"%s\") returned "
+                                 "FALSE on canonical form",
+                                 t->result);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_subr/mergeinfo-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_subr/mergeinfo-test.c Wed Nov  7 12:30:06 2018
@@ -1670,10 +1670,123 @@ test_remove_prefix_from_catalog(apr_pool
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_rangelist_merge_overlap(apr_pool_t *pool)
+{
+  const char *rangelist_str = "19473-19612*,19615-19630*,19631-19634";
+  const char *changes_str = "15014-20515*";
+  const char *expected_str = "15014-19630*,19631-19634,19635-20515*";
+  /* wrong result: "15014-19630*,19634-19631*,19631-19634,19635-20515*" */
+  svn_rangelist_t *rangelist, *changes;
+  svn_string_t *result_string;
+
+  /* prepare the inputs */
+  SVN_ERR(svn_rangelist__parse(&rangelist, rangelist_str, pool));
+  SVN_ERR(svn_rangelist__parse(&changes, changes_str, pool));
+  SVN_TEST_ASSERT(svn_rangelist__is_canonical(rangelist));
+  SVN_TEST_ASSERT(svn_rangelist__is_canonical(changes));
+
+  /* perform the merge */
+  SVN_ERR(svn_rangelist_merge2(rangelist, changes, pool, pool));
+
+  /* check the output */
+  SVN_TEST_ASSERT(svn_rangelist__is_canonical(rangelist));
+  SVN_ERR(svn_rangelist_to_string(&result_string, rangelist, pool));
+  SVN_TEST_STRING_ASSERT(result_string->data, expected_str);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_rangelist_loop(apr_pool_t *pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  int x, y;
+
+  for (x = 0; x < 62; x++)
+    for (y = x + 1; y < 63; y++)
+      {
+        svn_rangelist_t *base_list;
+        svn_rangelist_t *change_list;
+        svn_merge_range_t *mrange;
+        svn_pool_clear(iterpool);
+
+        SVN_ERR(svn_rangelist__parse(&base_list,
+                                     "2,4,7-9,12-15,18-20,"
+                                     "22*,25*,28-30*,33-35*,"
+                                     "38-40,43-45*,48-50,52-54,56-59*",
+                                     iterpool));
+
+        change_list = apr_array_make(iterpool, 1, sizeof(mrange));
+
+        mrange = apr_pcalloc(pool, sizeof(*mrange));
+        mrange->start = x;
+        mrange->end = y;
+        APR_ARRAY_PUSH(change_list, svn_merge_range_t *) = mrange;
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          SVN_ERR(svn_rangelist_merge2(bl, cl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_ERR(svn_rangelist_merge2(cl, bl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+
+        mrange->inheritable = TRUE;
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          SVN_ERR(svn_rangelist_merge2(bl, cl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_ERR(svn_rangelist_merge2(cl, bl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+      }
+
+  return SVN_NO_ERROR;
+}
 
 /* The test table.  */
 
-static int max_threads = 1;
+static int max_threads = 4;
 
 static struct svn_test_descriptor_t test_funcs[] =
   {
@@ -1714,6 +1827,10 @@ static struct svn_test_descriptor_t test
                    "diff of rangelists"),
     SVN_TEST_PASS2(test_remove_prefix_from_catalog,
                    "removal of prefix paths from catalog keys"),
+    SVN_TEST_PASS2(test_rangelist_merge_overlap,
+                   "merge of rangelists with overlaps (issue 4686)"),
+    SVN_TEST_PASS2(test_rangelist_loop,
+                    "test rangelist edgecases via loop"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/priority-queue-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/priority-queue-test.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/tests/libsvn_subr/priority-queue-test.c (original)
+++ subversion/branches/ra-git/subversion/tests/libsvn_subr/priority-queue-test.c Wed Nov  7 12:30:06 2018
@@ -125,7 +125,7 @@ verify_queue_order(svn_priority_queue__t
     }
 
   /* the queue should now be empty */
-  verify_empty_queue(queue);
+  SVN_ERR(verify_empty_queue(queue));
 
   return SVN_NO_ERROR;
 }
@@ -154,7 +154,7 @@ test_empty_queue(apr_pool_t *pool)
   svn_priority_queue__t *queue
     = svn_priority_queue__create(elements, compare_func);
 
-  verify_empty_queue(queue);
+  SVN_ERR(verify_empty_queue(queue));
 
   return SVN_NO_ERROR;
 }
@@ -214,7 +214,7 @@ test_update(apr_pool_t *pool)
     }
 
   /* the queue should now be empty */
-  verify_empty_queue(queue);
+  SVN_ERR(verify_empty_queue(queue));
 
   return SVN_NO_ERROR;
 }