subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1685464 [38/43] - in /subversion/branches/fsx-1.10: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/svncopy/ doc/ notes/ subversion/bindings/javahl/ subversion/bindings/javahl/native/ subversion/b...
Date Sun, 14 Jun 2015 20:58:16 GMT
Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_client/client-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_client/client-test.c Sun Jun 14 20:58:10 2015
@@ -35,6 +35,8 @@
 #include "svn_repos.h"
 #include "svn_subst.h"
 #include "private/svn_wc_private.h"
+#include "svn_props.h"
+#include "svn_hash.h"
 
 #include "../svn_test.h"
 #include "../svn_test_fs.h"
@@ -1055,6 +1057,357 @@ test_remote_only_status(const svn_test_o
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_copy_pin_externals(const svn_test_opts_t *opts,
+                        apr_pool_t *pool)
+{
+  svn_opt_revision_t rev;
+  svn_opt_revision_t peg_rev;
+  const char *repos_url;
+  const char *A_url;
+  const char *A_copy_url;
+  const char *wc_path;
+  svn_client_ctx_t *ctx;
+  const svn_string_t *propval;
+  apr_hash_t *externals_to_pin;
+  apr_array_header_t *external_items;
+  apr_array_header_t *copy_sources;
+  svn_wc_external_item2_t items[6];
+  svn_client_copy_source_t copy_source;
+  apr_hash_t *props;
+  apr_array_header_t *pinned_externals_descs;
+  apr_array_header_t *pinned_externals;
+  int i;
+  int num_tested_externals;
+  svn_stringbuf_t *externals_test_prop;
+  struct pin_externals_test_data {
+    const char *src_external_desc;
+    const char *expected_dst_external_desc;
+  } pin_externals_test_data[] = {
+    { "^/A/D/gamma B/gamma",    "^/A/D/gamma@2 B/gamma" },
+    { "-r1 ^/A/D/G C/exdir_G",  "-r1 ^/A/D/G C/exdir_G" },
+    { "^/A/D/H@1 C/exdir_H",    "^/A/D/H@1 C/exdir_H"  },
+    { "^/A/D/H C/exdir_H2",     "^/A/D/H@2 C/exdir_H2" },
+    { "-r1 ^/A/B D/z/y/z/blah", "-r1 ^/A/B@2 D/z/y/z/blah" } ,
+    { "-r1 ^/A/D@2 exdir_D", "-r1 ^/A/D@2 exdir_D" },
+    /* Dated revision should retain their date string exactly. */
+    { "-r{1970-01-01T00:00} ^/A/C 70s", "-r{1970-01-01T00:00} ^/A/C@2 70s"},
+    { "-r{2004-02-23} ^/svn 1.0", "-r{2004-02-23} ^/svn 1.0"},
+    { NULL },
+  };
+
+  /* Create a filesytem and repository containing the Greek tree. */
+  SVN_ERR(create_greek_repos(&repos_url, "pin-externals", opts, pool));
+
+  wc_path = svn_test_data_path("pin-externals-working-copy", pool);
+
+  /* Remove old test data from the previous run */
+  SVN_ERR(svn_io_remove_dir2(wc_path, TRUE, NULL, NULL, pool));
+
+  SVN_ERR(svn_io_make_dir_recursively(wc_path, pool));
+  svn_test_add_dir_cleanup(wc_path);
+
+  rev.kind = svn_opt_revision_head;
+  peg_rev.kind = svn_opt_revision_unspecified;
+  SVN_ERR(svn_client_create_context(&ctx, pool));
+
+  /* Configure some externals on ^/A */
+  i = 0;
+  externals_test_prop = svn_stringbuf_create_empty(pool);
+  while (pin_externals_test_data[i].src_external_desc)
+    {
+      svn_stringbuf_appendcstr(externals_test_prop,
+                               pin_externals_test_data[i].src_external_desc);
+      svn_stringbuf_appendbyte(externals_test_prop, '\n');
+      i++;
+    }
+  propval = svn_string_create_from_buf(externals_test_prop, pool);
+  A_url = apr_pstrcat(pool, repos_url, "/A", SVN_VA_NULL);
+  SVN_ERR(svn_client_propset_remote(SVN_PROP_EXTERNALS, propval,
+                                    A_url, TRUE, 1, NULL,
+                                    NULL, NULL, ctx, pool));
+
+  /* Set up parameters for pinning some externals. */
+  externals_to_pin = apr_hash_make(pool);
+
+  items[0].url = "^/A/D/gamma";
+  items[0].target_dir = "B/gamma";
+  items[1].url = "^/A/B";
+  items[1].target_dir = "D/z/y/z/blah";
+  items[2].url = "^/A/D/H";
+  items[2].target_dir = "C/exdir_H2";
+  items[3].url= "^/A/D";
+  items[3].target_dir= "exdir_D";
+  items[4].url = "^/A/C";
+  items[4].target_dir = "70s";
+  /* Also add an entry which doesn't match any actual definition. */
+  items[5].url = "^/this/does/not/exist";
+  items[5].target_dir = "in/test/data";
+
+  external_items = apr_array_make(pool, 2, sizeof(svn_wc_external_item2_t *));
+  for (i = 0; i < sizeof(items) / sizeof(items[0]); i++)
+    APR_ARRAY_PUSH(external_items, svn_wc_external_item2_t *) = &items[i];
+  svn_hash_sets(externals_to_pin, A_url, external_items);
+
+  /* Copy ^/A to ^/A_copy, pinning two non-pinned externals. */
+  copy_source.path = A_url;
+  copy_source.revision = &rev;
+  copy_source.peg_revision = &peg_rev;
+  copy_sources = apr_array_make(pool, 1, sizeof(svn_client_copy_source_t *));
+  APR_ARRAY_PUSH(copy_sources, svn_client_copy_source_t *) = &copy_source;
+  A_copy_url = apr_pstrcat(pool, repos_url, "/A_copy", SVN_VA_NULL);
+  SVN_ERR(svn_client_copy7(copy_sources, A_copy_url, FALSE, FALSE,
+                           FALSE, FALSE, TRUE, externals_to_pin,
+                           NULL, NULL, NULL, ctx, pool));
+
+  /* Verify that externals were pinned as expected. */
+  SVN_ERR(svn_client_propget5(&props, NULL, SVN_PROP_EXTERNALS,
+                              A_copy_url, &peg_rev, &rev, NULL,
+                              svn_depth_empty, NULL, ctx, pool, pool));
+  propval = svn_hash_gets(props, A_copy_url);
+  SVN_TEST_ASSERT(propval);
+
+  /* Test the unparsed representation of copied externals descriptions. */
+  pinned_externals_descs = svn_cstring_split(propval->data, "\n", FALSE, pool);
+  for (i = 0; i < pinned_externals_descs->nelts; i++)
+    {
+      const char *externals_desc;
+      const char *expected_desc;
+
+      externals_desc = APR_ARRAY_IDX(pinned_externals_descs, i, const char *);
+      expected_desc = pin_externals_test_data[i].expected_dst_external_desc;
+      SVN_TEST_STRING_ASSERT(externals_desc, expected_desc);
+    }
+  /* Ensure all test cases were tested. */
+  SVN_TEST_ASSERT(i == (sizeof(pin_externals_test_data) /
+                        sizeof(pin_externals_test_data[0]) - 1));
+
+  SVN_ERR(svn_wc_parse_externals_description3(&pinned_externals, A_copy_url,
+                                              propval->data, TRUE, pool));
+
+  /* For completeness, test the parsed representation, too */
+  num_tested_externals = 0;
+  for (i = 0; i < pinned_externals->nelts; i++)
+    {
+      svn_wc_external_item2_t *item;
+
+      item = APR_ARRAY_IDX(pinned_externals, i, svn_wc_external_item2_t *);
+      if (strcmp(item->url, "^/A/D/gamma") == 0)
+        {
+          SVN_TEST_STRING_ASSERT(item->target_dir, "B/gamma");
+          /* Pinned to r2. */
+          SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->revision.value.number == 2);
+          SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+          num_tested_externals++;
+        }
+      else if (strcmp(item->url, "^/A/D/G") == 0)
+        {
+          SVN_TEST_STRING_ASSERT(item->target_dir, "C/exdir_G");
+          /* Not pinned. */
+          SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->revision.value.number == 1);
+          SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_head);
+          num_tested_externals++;
+        }
+      else if (strcmp(item->url, "^/A/D/H") == 0)
+        {
+          if (strcmp(item->target_dir, "C/exdir_H") == 0)
+            {
+              /* Was already pinned to r1. */
+              SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+              SVN_TEST_ASSERT(item->revision.value.number == 1);
+              SVN_TEST_ASSERT(item->peg_revision.kind ==
+                              svn_opt_revision_number);
+              SVN_TEST_ASSERT(item->peg_revision.value.number == 1);
+              num_tested_externals++;
+            }
+          else if (strcmp(item->target_dir, "C/exdir_H2") == 0)
+            {
+              /* Pinned to r2. */
+              SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+              SVN_TEST_ASSERT(item->revision.value.number == 2);
+              SVN_TEST_ASSERT(item->peg_revision.kind ==
+                              svn_opt_revision_number);
+              SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+              num_tested_externals++;
+            }
+          else
+            SVN_TEST_ASSERT(FALSE); /* unknown external */
+        }
+      else if (strcmp(item->url, "^/A/B") == 0)
+        {
+          SVN_TEST_STRING_ASSERT(item->target_dir, "D/z/y/z/blah");
+          /* Pinned to r2. */
+          SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->revision.value.number == 1);
+          SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+          num_tested_externals++;
+        }
+      else if (strcmp(item->url, "^/A/D") == 0)
+        {
+          SVN_TEST_STRING_ASSERT(item->target_dir, "exdir_D");
+          /* Pinned to r2. */
+          SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->revision.value.number == 1);
+          SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+          num_tested_externals++;
+        }
+      else if (strcmp(item->url, "^/A/C") == 0)
+        {
+          SVN_TEST_STRING_ASSERT(item->target_dir, "70s");
+          /* Pinned to r2. */
+          SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_date);
+          /* Don't bother testing the exact date value here. */
+          SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_number);
+          SVN_TEST_ASSERT(item->peg_revision.value.number == 2);
+          num_tested_externals++;
+        }
+      else if (strcmp(item->url, "^/svn") == 0)
+        {
+          SVN_TEST_STRING_ASSERT(item->target_dir, "1.0");
+          /* Was and not in externals_to_pin, operative revision was a date. */
+          SVN_TEST_ASSERT(item->revision.kind == svn_opt_revision_date);
+          /* Don't bother testing the exact date value here. */
+          SVN_TEST_ASSERT(item->peg_revision.kind == svn_opt_revision_head);
+          num_tested_externals++;
+        }
+      else
+        SVN_TEST_ASSERT(FALSE); /* unknown URL */
+    }
+
+  /* Ensure all test cases were tested. */
+  SVN_TEST_ASSERT(num_tested_externals == (sizeof(pin_externals_test_data) /
+                                           sizeof(pin_externals_test_data[0])
+                                          - 1));
+
+  return SVN_NO_ERROR;
+}
+
+/* issue #4560 */
+static svn_error_t *
+test_copy_pin_externals_select_subtree(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_opt_revision_t rev;
+  svn_opt_revision_t peg_rev;
+  const char *repos_url;
+  const char *A_copy_url;
+  const char *B_url;
+  const char *wc_path;
+  svn_client_ctx_t *ctx;
+  apr_hash_t *externals_to_pin;
+  apr_array_header_t *external_items;
+  apr_array_header_t *copy_sources;
+  svn_wc_external_item2_t item;
+  svn_client_copy_source_t copy_source;
+  apr_hash_t *props;
+  int i;
+  struct test_data {
+    const char *subtree_relpath;
+    const char *src_external_desc;
+    const char *expected_dst_external_desc;
+  } test_data[] = {
+    /* Note: these externals definitions contain extra whitespace on
+       purpose, to test that the pinning logic doesn't make
+       whitespace-only changes to values that aren't pinned. */
+
+    /* External on A/B will be pinned. */
+    { "B", "^/A/D/gamma  gamma-ext", "^/A/D/gamma@3 gamma-ext" },
+
+    /* External on A/D won't be pinned. */
+    { "D", "^/A/B/F  F-ext", "^/A/B/F  F-ext" } ,
+
+    { NULL },
+  };
+
+  /* Create a filesytem and repository containing the Greek tree. */
+  SVN_ERR(create_greek_repos(&repos_url, "pin-externals-select-subtree",
+                             opts, pool));
+
+  wc_path = svn_test_data_path("pin-externals-select-subtree-wc", pool);
+
+  /* Remove old test data from the previous run */
+  SVN_ERR(svn_io_remove_dir2(wc_path, TRUE, NULL, NULL, pool));
+
+  SVN_ERR(svn_io_make_dir_recursively(wc_path, pool));
+  svn_test_add_dir_cleanup(wc_path);
+
+  rev.kind = svn_opt_revision_head;
+  peg_rev.kind = svn_opt_revision_unspecified;
+  SVN_ERR(svn_client_create_context(&ctx, pool));
+
+  /* Configure externals. */
+  i = 0;
+  while (test_data[i].subtree_relpath)
+    {
+      const char *subtree_relpath;
+      const char *url;
+      const svn_string_t *propval;
+
+      subtree_relpath = test_data[i].subtree_relpath;
+      propval = svn_string_create(test_data[i].src_external_desc, pool);
+
+      url = apr_pstrcat(pool, repos_url, "/A/", subtree_relpath, SVN_VA_NULL);
+      SVN_ERR(svn_client_propset_remote(SVN_PROP_EXTERNALS, propval,
+                                        url, TRUE, 1, NULL,
+                                        NULL, NULL, ctx, pool));
+      i++;
+    }
+
+  /* Set up parameters for pinning externals on A/B. */
+  externals_to_pin = apr_hash_make(pool);
+
+  item.url = "^/A/D/gamma";
+  item.target_dir = "gamma-ext";
+
+  external_items = apr_array_make(pool, 2, sizeof(svn_wc_external_item2_t *));
+  APR_ARRAY_PUSH(external_items, svn_wc_external_item2_t *) = &item;
+  B_url = apr_pstrcat(pool, repos_url, "/A/B", SVN_VA_NULL);
+  svn_hash_sets(externals_to_pin, B_url, external_items);
+
+  /* Copy ^/A to ^/A_copy, pinning externals on ^/A/B. */
+  copy_source.path = apr_pstrcat(pool, repos_url, "/A", SVN_VA_NULL);
+  copy_source.revision = &rev;
+  copy_source.peg_revision = &peg_rev;
+  copy_sources = apr_array_make(pool, 1, sizeof(svn_client_copy_source_t *));
+  APR_ARRAY_PUSH(copy_sources, svn_client_copy_source_t *) = &copy_source;
+  A_copy_url = apr_pstrcat(pool, repos_url, "/A_copy", SVN_VA_NULL);
+  SVN_ERR(svn_client_copy7(copy_sources, A_copy_url, FALSE, FALSE,
+                           FALSE, FALSE, TRUE, externals_to_pin,
+                           NULL, NULL, NULL, ctx, pool));
+
+  /* Verify that externals were pinned as expected. */
+  i = 0;
+  while (test_data[i].subtree_relpath)
+    {
+      const char *subtree_relpath;
+      const char *url;
+      const svn_string_t *propval;
+      svn_stringbuf_t *externals_desc;
+      const char *expected_desc;
+
+      subtree_relpath = test_data[i].subtree_relpath;
+      url = apr_pstrcat(pool, A_copy_url, "/", subtree_relpath, SVN_VA_NULL);
+
+      SVN_ERR(svn_client_propget5(&props, NULL, SVN_PROP_EXTERNALS,
+                                  url, &peg_rev, &rev, NULL,
+                                  svn_depth_empty, NULL, ctx, pool, pool));
+      propval = svn_hash_gets(props, url);
+      SVN_TEST_ASSERT(propval);
+      externals_desc = svn_stringbuf_create(propval->data, pool);
+      svn_stringbuf_strip_whitespace(externals_desc);
+      expected_desc = test_data[i].expected_dst_external_desc;
+      SVN_TEST_STRING_ASSERT(externals_desc->data, expected_desc);
+
+      i++;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* ========================================================================== */
 
 
@@ -1079,6 +1432,10 @@ static struct svn_test_descriptor_t test
                        "test svn_client_suggest_merge_sources"),
     SVN_TEST_OPTS_PASS(test_remote_only_status,
                        "test svn_client_status6 with ignore_local_mods"),
+    SVN_TEST_OPTS_PASS(test_copy_pin_externals,
+                       "test svn_client_copy7 with externals_to_pin"),
+    SVN_TEST_OPTS_PASS(test_copy_pin_externals_select_subtree,
+                       "pin externals on selected subtrees only"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_client/mtcc-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_client/mtcc-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_client/mtcc-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_client/mtcc-test.c Sun Jun 14 20:58:10 2015
@@ -472,8 +472,55 @@ struct handle_rev_baton
   svn_revnum_t last;
   svn_boolean_t up;
   svn_boolean_t first;
+
+  /* Per revision handler */
+  svn_txdelta_window_handler_t inner_handler;
+  void *inner_baton;
+
+  /* Swapped between revisions to reconstruct data */
+  svn_stringbuf_t *cur;
+  svn_stringbuf_t *prev;
+
+  /* Pool for some test stuff */
+  apr_pool_t *pool;
 };
 
+/* Implement svn_txdelta_window_handler_t */
+static svn_error_t *
+handle_rev_delta(svn_txdelta_window_t *window,
+                 void * baton)
+{
+  struct handle_rev_baton *hrb = baton;
+
+  SVN_ERR(hrb->inner_handler(window, hrb->inner_baton));
+
+  if (!window)
+    {
+      int expected_rev;
+      const char *expected;
+
+      /* Some revisions don't update the revision body */
+      switch (hrb->last)
+        {
+          case 5:
+            expected_rev = 4;
+            break;
+          case 7: /* Not reported */
+          case 8:
+            expected_rev = 6;
+            break;
+          default:
+            expected_rev = (int)hrb->last;
+        }
+
+      expected = apr_psprintf(hrb->pool, "revision-%d", expected_rev);
+
+      SVN_TEST_STRING_ASSERT(hrb->cur->data, expected);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Helper for test_file_revs_both_ways */
 static svn_error_t *
 handle_rev(void *baton,
@@ -489,19 +536,38 @@ handle_rev(void *baton,
   struct handle_rev_baton *hrb = baton;
   svn_revnum_t expected_rev = hrb->up ? (hrb->last + 1) : (hrb->last - 1);
 
+  if (expected_rev == 7)
+    expected_rev = hrb->up ? 8 : 6;
+
   SVN_TEST_ASSERT(rev == expected_rev);
   SVN_TEST_ASSERT(apr_hash_count(rev_props) >= 3);
   SVN_TEST_STRING_ASSERT(path, (rev < 5) ? "/iota" : "/mu");
 
-  if (!hrb->first && rev == (hrb->up ? 5 : 4))
+  if (!hrb->first
+      && (rev == (hrb->up ? 5 : 4) || rev == (hrb->up ? 8 : 6)))
     SVN_TEST_ASSERT(delta_handler == NULL);
   else
     SVN_TEST_ASSERT(delta_handler != NULL);
 
   if (delta_handler)
     {
-      *delta_handler = svn_delta_noop_window_handler;
-      *delta_baton = NULL;
+      svn_stringbuf_t *tmp;
+
+      *delta_handler = handle_rev_delta;
+      *delta_baton = hrb;
+
+      /* Swap string buffers, to use previous as original */
+      tmp = hrb->prev;
+      hrb->prev = hrb->cur;
+      hrb->cur = tmp;
+
+      svn_stringbuf_setempty(hrb->cur);
+
+      svn_txdelta_apply(svn_stream_from_stringbuf(hrb->prev, pool),
+                        svn_stream_from_stringbuf(hrb->cur, pool),
+                        NULL, NULL, pool,
+                        &hrb->inner_handler,
+                        &hrb->inner_baton);
     }
 
   hrb->last = rev;
@@ -579,10 +645,16 @@ test_file_revs_both_ways(const svn_test_
 
   SVN_ERR(svn_client_open_ra_session2(&ra, repos_url, NULL, ctx, pool, subpool));
 
+  hrb.prev = svn_stringbuf_create("", pool);
+  hrb.cur = svn_stringbuf_create("", pool);
+  hrb.pool = pool;
+
   svn_pool_clear(subpool);
   hrb.up = FALSE;
   hrb.last = 5;
   hrb.first = TRUE;
+  svn_stringbuf_setempty(hrb.prev);
+  svn_stringbuf_setempty(hrb.cur);
   SVN_ERR(svn_ra_get_file_revs2(ra, "iota", 4, 1, FALSE,
                                 handle_rev, &hrb,
                                 subpool));
@@ -592,6 +664,8 @@ test_file_revs_both_ways(const svn_test_
   hrb.up = TRUE;
   hrb.last = 0;
   hrb.first = TRUE;
+  svn_stringbuf_setempty(hrb.prev);
+  svn_stringbuf_setempty(hrb.cur);
   SVN_ERR(svn_ra_get_file_revs2(ra, "iota", 1, 4, FALSE,
                                 handle_rev, &hrb,
                                 subpool));
@@ -601,6 +675,8 @@ test_file_revs_both_ways(const svn_test_
   hrb.up = FALSE;
   hrb.last = 7;
   hrb.first = TRUE;
+  svn_stringbuf_setempty(hrb.prev);
+  svn_stringbuf_setempty(hrb.cur);
   SVN_ERR(svn_ra_get_file_revs2(ra, "mu", 6, 1, FALSE,
                                 handle_rev, &hrb,
                                 subpool));
@@ -610,11 +686,41 @@ test_file_revs_both_ways(const svn_test_
   hrb.up = TRUE;
   hrb.last = 0;
   hrb.first = TRUE;
+  svn_stringbuf_setempty(hrb.prev);
+  svn_stringbuf_setempty(hrb.cur);
   SVN_ERR(svn_ra_get_file_revs2(ra, "mu", 1, 6, FALSE,
                                 handle_rev, &hrb,
                                 subpool));
   SVN_TEST_ASSERT(hrb.last == 6);
-  
+
+  /* Ressurect mu */
+  svn_pool_clear(subpool);
+  SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 7, ctx, subpool, subpool));
+  SVN_ERR(svn_client__mtcc_add_copy("mu", 6, "mu", mtcc, subpool));
+  SVN_ERR(verify_mtcc_commit(mtcc, 8, subpool));
+
+  svn_pool_clear(subpool);
+  hrb.up = TRUE;
+  hrb.last = 0;
+  hrb.first = TRUE;
+  svn_stringbuf_setempty(hrb.prev);
+  svn_stringbuf_setempty(hrb.cur);
+  SVN_ERR(svn_ra_get_file_revs2(ra, "mu", 1, SVN_INVALID_REVNUM, FALSE,
+                                handle_rev, &hrb,
+                                subpool));
+  SVN_TEST_ASSERT(hrb.last == 8);
+
+  svn_pool_clear(subpool);
+  hrb.up = FALSE;
+  hrb.last = 9;
+  hrb.first = TRUE;
+  svn_stringbuf_setempty(hrb.prev);
+  svn_stringbuf_setempty(hrb.cur);
+  SVN_ERR(svn_ra_get_file_revs2(ra, "mu", SVN_INVALID_REVNUM, 1, FALSE,
+                                handle_rev, &hrb,
+                                subpool));
+  SVN_TEST_ASSERT(hrb.last == 1);
+
   return SVN_NO_ERROR;
 }
 

Propchange: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Jun 14 20:58:10 2015
@@ -1,7 +1,7 @@
 .libs
 test-*
 locks-test
-fs-test
+fs-*test
 *.o
 *.lo
 *~

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/fs-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/fs-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/fs-test.c Sun Jun 14 20:58:10 2015
@@ -4268,7 +4268,7 @@ check_related(const svn_test_opts_t *opt
             if (i == j)
               {
                 /* Identical note. */
-                if (!related || relation != svn_fs_node_same)
+                if (!related || relation != svn_fs_node_unchanged)
                   {
                     return svn_error_createf
                       (SVN_ERR_TEST_FAILED, NULL,
@@ -4319,7 +4319,7 @@ check_related(const svn_test_opts_t *opt
                                          rev_root, path, subpool));
 
             /* They shall use the same noderevs */
-            if (relation != svn_fs_node_same)
+            if (relation != svn_fs_node_unchanged)
               {
                 return svn_error_createf
                   (SVN_ERR_TEST_FAILED, NULL,
@@ -4339,6 +4339,209 @@ check_related(const svn_test_opts_t *opt
 
 
 static svn_error_t *
+check_txn_related(const svn_test_opts_t *opts,
+                  apr_pool_t *pool)
+{
+  apr_pool_t *subpool = svn_pool_create(pool);
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn[3];
+  svn_fs_root_t *root[3];
+  svn_revnum_t youngest_rev = 0;
+
+  /* Create a filesystem and repository. */
+  SVN_ERR(svn_test__create_fs(&fs, "test-repo-check-txn-related",
+                              opts, pool));
+
+  /*** Step I: Build up some state in our repository through a series
+       of commits */
+
+  /* This is the node graph we are testing.  It contains one revision (r1)
+     and two transactions, T1 and T2 - yet uncommitted.
+
+     A is a file that exists in r1 (A-0) and gets modified in both txns.
+     C is a copy of A-0 made in both txns.
+     B is a new node created in both txns
+     D is a file that exists in r1 (D-0) and never gets modified.
+     / is the root folder, touched in r0, r1 and both txns (root-0)
+     R is a copy of the root-0 made in both txns.
+
+     The edges in the graph connect related noderevs:
+
+                 +--A-0--+                D-0           +-root-0-+
+                 |       |                              |        |
+           +-----+       +-----+                 +------+        +------+
+           |     |       |     |                 |      |        |      |
+     B-1   C-1   A-1     A-2   C-2   B-2         R-1    root-1   root-2 R-2
+  */
+  /* Revision 1 */
+  SVN_ERR(svn_fs_begin_txn(&txn[0], fs, youngest_rev, subpool));
+  SVN_ERR(svn_fs_txn_root(&root[0], txn[0], subpool));
+  SVN_ERR(svn_fs_make_file(root[0], "A", subpool));
+  SVN_ERR(svn_test__set_file_contents(root[0], "A", "1", subpool));
+  SVN_ERR(svn_fs_make_file(root[0], "D", subpool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &youngest_rev, txn[0], subpool));
+  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
+  svn_pool_clear(subpool);
+  SVN_ERR(svn_fs_revision_root(&root[0], fs, youngest_rev, pool));
+
+  /* Transaction 1 */
+  SVN_ERR(svn_fs_begin_txn(&txn[1], fs, youngest_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root[1], txn[1], pool));
+  SVN_ERR(svn_test__set_file_contents(root[1], "A", "2", pool));
+  SVN_ERR(svn_fs_copy(root[0], "A", root[1], "C", pool));
+  SVN_ERR(svn_fs_copy(root[0], "", root[1], "R", pool));
+  SVN_ERR(svn_fs_make_file(root[1], "B", pool));
+
+  /* Transaction 2 */
+  SVN_ERR(svn_fs_begin_txn(&txn[2], fs, youngest_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root[2], txn[2], pool));
+  SVN_ERR(svn_test__set_file_contents(root[2], "A", "2", pool));
+  SVN_ERR(svn_fs_copy(root[0], "A", root[2], "C", pool));
+  SVN_ERR(svn_fs_copy(root[0], "", root[2], "R", pool));
+  SVN_ERR(svn_fs_make_file(root[2], "B", pool));
+
+  /*** Step II: Exhaustively verify relationship between all nodes in
+       existence. */
+  {
+    enum { NODE_COUNT = 13 };
+    int i, j;
+
+    struct path_rev_t
+    {
+      const char *path;
+      int root;
+    };
+
+    /* Our 16 existing files/revisions. */
+    struct path_rev_t path_revs[NODE_COUNT] = {
+      { "A", 0 }, { "A", 1 }, { "A", 2 },
+      { "B", 1 }, { "B", 2 },
+      { "C", 1 }, { "C", 2 },
+      { "D", 0 },
+      { "/", 0 }, { "/", 1 }, { "/", 2 },
+      { "R", 1 }, { "R", 2 }
+    };
+
+    int related_matrix[NODE_COUNT][NODE_COUNT] = {
+      /* A-0 ... R-2 across the top here*/
+      { 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* A-0 */
+      { 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* A-1 */
+      { 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* A-2 */
+      { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* B-1 */
+      { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, /* B-2 */
+      { 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* C-1 */
+      { 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, /* C-2 */
+      { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, /* D-0 */
+      { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, /* root-0 */
+      { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, /* root-1 */
+      { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, /* root-2 */
+      { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, /* R-1 */
+      { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 }, /* R-2 */
+    };
+
+    /* Here's the fun part.  Running the tests. */
+    for (i = 0; i < NODE_COUNT; i++)
+      {
+        for (j = 0; j < NODE_COUNT; j++)
+          {
+            struct path_rev_t pr1 = path_revs[i];
+            struct path_rev_t pr2 = path_revs[j];
+            const svn_fs_id_t *id1, *id2;
+            int related = 0;
+            svn_fs_node_relation_t relation;
+
+            svn_pool_clear(subpool);
+
+            /* Get the ID for the first path/revision combination. */
+            SVN_ERR(svn_fs_node_id(&id1, root[pr1.root], pr1.path, subpool));
+
+            /* Get the ID for the second path/revision combination. */
+            SVN_ERR(svn_fs_node_id(&id2, root[pr2.root], pr2.path, subpool));
+
+            /* <exciting> Now, run the relationship check! </exciting> */
+            related = svn_fs_check_related(id1, id2) ? 1 : 0;
+            if (related == related_matrix[i][j])
+              {
+                /* xlnt! */
+              }
+            else if ((! related) && related_matrix[i][j])
+              {
+                return svn_error_createf
+                  (SVN_ERR_TEST_FAILED, NULL,
+                   "expected '%s-%d' to be related to '%s-%d'; it was not",
+                   pr1.path, pr1.root, pr2.path, pr2.root);
+              }
+            else if (related && (! related_matrix[i][j]))
+              {
+                return svn_error_createf
+                  (SVN_ERR_TEST_FAILED, NULL,
+                   "expected '%s-%d' to not be related to '%s-%d'; it was",
+                   pr1.path, pr1.root, pr2.path, pr2.root);
+              }
+
+            /* Asking directly, i.e. without involving the noderev IDs as
+             * an intermediate, should yield the same results. */
+            SVN_ERR(svn_fs_node_relation(&relation, root[pr1.root], pr1.path,
+                                         root[pr2.root], pr2.path, subpool));
+            if (i == j)
+              {
+                /* Identical noderev. */
+                if (!related || relation != svn_fs_node_unchanged)
+                  {
+                    return svn_error_createf
+                      (SVN_ERR_TEST_FAILED, NULL,
+                      "expected '%s-%d' to be the same as '%s-%d';"
+                      " it was not",
+                      pr1.path, pr1.root, pr2.path, pr2.root);
+                  }
+              }
+            else if (related && relation != svn_fs_node_common_ancestor)
+              {
+                return svn_error_createf
+                  (SVN_ERR_TEST_FAILED, NULL,
+                   "expected '%s-%d' to have a common ancestor with '%s-%d';"
+                   " it had not",
+                   pr1.path, pr1.root, pr2.path, pr2.root);
+              }
+            else if (!related && relation != svn_fs_node_unrelated)
+              {
+                return svn_error_createf
+                  (SVN_ERR_TEST_FAILED, NULL,
+                   "expected '%s-%d' to not be related to '%s-%d'; it was",
+                   pr1.path, pr1.root, pr2.path, pr2.root);
+              }
+          } /* for ... */
+      } /* for ... */
+
+    /* Verify that the noderevs stay the same after their last change.
+       There is only D that is not changed. */
+    for (i = 1; i <= 2; ++i)
+      {
+        svn_fs_node_relation_t relation;
+        svn_pool_clear(subpool);
+
+        /* Query their noderev relationship to the latest change. */
+        SVN_ERR(svn_fs_node_relation(&relation, root[i], "D",
+                                     root[0], "D", subpool));
+
+        /* They shall use the same noderevs */
+        if (relation != svn_fs_node_unchanged)
+          {
+            return svn_error_createf
+              (SVN_ERR_TEST_FAILED, NULL,
+              "expected 'D-%d' to be the same as 'D-0'; it was not", i);
+          }
+      } /* for ... */
+  }
+
+  /* Destroy the subpool. */
+  svn_pool_destroy(subpool);
+
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
 branch_test(const svn_test_opts_t *opts,
             apr_pool_t *pool)
 {
@@ -4709,7 +4912,7 @@ unordered_txn_dirprops(const svn_test_op
   svn_fs_root_t *txn_root, *txn_root2;
   svn_string_t pval;
   svn_revnum_t new_rev, not_rev;
-  svn_boolean_t is_bdb = strcmp(opts->fs_type, "bdb") == 0;
+  svn_boolean_t is_bdb = strcmp(opts->fs_type, SVN_FS_TYPE_BDB) == 0;
 
   /* This is a regression test for issue #2751. */
 
@@ -5100,15 +5303,11 @@ filename_trailing_newline(const svn_test
   svn_fs_root_t *txn_root, *root;
   svn_revnum_t youngest_rev = 0;
   svn_error_t *err;
-  svn_boolean_t legacy_backend;
-  static const char contents[] = "foo\003bar";
-
-  /* The FS API wants \n to be permitted, but FSFS never implemented that,
-   * so for FSFS we expect errors rather than successes in some of the commits.
-   * Use a blacklist approach so that new FSes default to implementing the API
-   * as originally defined. */
-  legacy_backend = (!strcmp(opts->fs_type, SVN_FS_TYPE_FSFS));
 
+  /* The FS API wants \n to be permitted, but FSFS never implemented that.
+   * Moreover, formats like svn:mergeinfo and svn:externals don't support
+   * it either.  So, we can't have newlines in file names in any FS.
+   */
   SVN_ERR(svn_test__create_fs(&fs, "test-repo-filename-trailing-newline",
                               opts, pool));
 
@@ -5120,64 +5319,20 @@ filename_trailing_newline(const svn_test
   SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
   svn_pool_clear(subpool);
 
-  /* Attempt to copy /foo to "/bar\n". This should fail on FSFS. */
+  /* Attempt to copy /foo to "/bar\n". This should fail. */
   SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, subpool));
   SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
   SVN_ERR(svn_fs_revision_root(&root, fs, youngest_rev, subpool));
   err = svn_fs_copy(root, "/foo", txn_root, "/bar\n", subpool);
-  if (!legacy_backend)
-    SVN_TEST_ASSERT(err == SVN_NO_ERROR);
-  else
-    SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_PATH_SYNTAX);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_PATH_SYNTAX);
 
-  /* Attempt to create a file /foo/baz\n. This should fail on FSFS. */
+  /* Attempt to create a file /foo/baz\n. This should fail. */
   err = svn_fs_make_file(txn_root, "/foo/baz\n", subpool);
-  if (!legacy_backend)
-    SVN_TEST_ASSERT(err == SVN_NO_ERROR);
-  else
-    SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_PATH_SYNTAX);
-  
-
-  /* Create another file, with contents. */
-  if (!legacy_backend)
-    {
-      SVN_ERR(svn_fs_make_file(txn_root, "/bar\n/baz\n", subpool));
-      SVN_ERR(svn_test__set_file_contents(txn_root, "bar\n/baz\n",
-                                          contents, pool));
-    }
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_PATH_SYNTAX);
 
-  if (!legacy_backend)
-    {
-      svn_revnum_t after_rev;
-      static svn_test__tree_entry_t expected_entries[] = {
-        { "foo", NULL },
-        { "bar\n", NULL },
-        { "foo/baz\n", "" },
-        { "bar\n/baz\n", contents },
-        { NULL, NULL }
-      };
-      const char *expected_changed_paths[] = {
-        "/bar\n",
-        "/foo/baz\n",
-        "/bar\n/baz\n",
-        NULL
-      };
-      apr_hash_t *expected_changes = apr_hash_make(pool);
-      int i;
-
-      SVN_ERR(svn_fs_commit_txn(NULL, &after_rev, txn, subpool));
-      SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
-
-      /* Validate the DAG. */
-      SVN_ERR(svn_fs_revision_root(&root, fs, after_rev, pool));
-      SVN_ERR(svn_test__validate_tree(root, expected_entries, 4, pool));
-
-      /* Validate changed-paths, where the problem originally occurred. */
-      for (i = 0; expected_changed_paths[i]; i++)
-        svn_hash_sets(expected_changes, expected_changed_paths[i],
-                      "undefined value");
-      SVN_ERR(svn_test__validate_changes(root, expected_changes, pool));
-    }
+  /* Attempt to create a directory /foo/bang\n. This should fail. */
+  err = svn_fs_make_dir(txn_root, "/foo/bang\n", subpool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_PATH_SYNTAX);
 
   return SVN_NO_ERROR;
 }
@@ -5215,6 +5370,17 @@ test_fs_info_format(const svn_test_opts_
   return SVN_NO_ERROR;
 }
 
+/* Sleeps until apr_time_now() value changes. */
+static void sleep_for_timestamps(void)
+{
+  apr_time_t start = apr_time_now();
+
+  while (start == apr_time_now())
+    {
+      apr_sleep(APR_USEC_PER_SEC / 1000);
+    }
+}
+
 static svn_error_t *
 commit_timestamp(const svn_test_opts_t *opts,
                  apr_pool_t *pool)
@@ -5226,6 +5392,7 @@ commit_timestamp(const svn_test_opts_t *
   svn_revnum_t rev = 0;
   apr_hash_t *proplist;
   svn_string_t *svn_date;
+  svn_string_t *txn_svn_date;
 
   SVN_ERR(svn_test__create_fs(&fs, "test-fs-commit-timestamp",
                               opts, pool));
@@ -5244,29 +5411,6 @@ commit_timestamp(const svn_test_opts_t *
 
   /* Commit that overwrites the specified svn:date. */
   SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
-  {
-    /* Setting the internal property doesn't enable svn:date behaviour. */
-    apr_array_header_t *props = apr_array_make(pool, 3, sizeof(svn_prop_t));
-    svn_prop_t prop, other_prop1, other_prop2;
-    svn_string_t *val;
-
-    prop.name = SVN_FS__PROP_TXN_CLIENT_DATE;
-    prop.value = svn_string_create("1", pool);
-    other_prop1.name = "foo";
-    other_prop1.value = svn_string_create("fooval", pool);
-    other_prop2.name = "bar";
-    other_prop2.value = svn_string_create("barval", pool);
-    APR_ARRAY_PUSH(props, svn_prop_t) = other_prop1;
-    APR_ARRAY_PUSH(props, svn_prop_t) = prop;
-    APR_ARRAY_PUSH(props, svn_prop_t) = other_prop2;
-    SVN_ERR(svn_fs_change_txn_props(txn, props, pool));
-    SVN_ERR(svn_fs_txn_prop(&val, txn, other_prop1.name, pool));
-    SVN_TEST_ASSERT(val && !strcmp(val->data, other_prop1.value->data));
-    SVN_ERR(svn_fs_txn_prop(&val, txn, other_prop2.name, pool));
-    SVN_TEST_ASSERT(val && !strcmp(val->data, other_prop2.value->data));
-
-    SVN_ERR(svn_fs_change_txn_prop(txn, prop.name, prop.value, pool));
-  }
   SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
   SVN_ERR(svn_fs_make_dir(txn_root, "/bar", pool));
   SVN_ERR(svn_fs_change_txn_prop(txn, SVN_PROP_REVISION_DATE, date, pool));
@@ -5305,6 +5449,37 @@ commit_timestamp(const svn_test_opts_t *
                           APR_HASH_KEY_STRING);
   SVN_TEST_ASSERT(svn_date);
 
+  /* Commit that doesn't do anything special about svn:date. */
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, rev, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "/zig/foo", pool));
+  SVN_ERR(svn_fs_txn_prop(&txn_svn_date, txn, SVN_PROP_REVISION_DATE, pool));
+  SVN_TEST_ASSERT(txn_svn_date);
+  sleep_for_timestamps();
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  SVN_ERR(svn_fs_revision_proplist(&proplist, fs, rev, pool));
+  svn_date = apr_hash_get(proplist, SVN_PROP_REVISION_DATE,
+                          APR_HASH_KEY_STRING);
+  SVN_TEST_ASSERT(svn_date);
+  SVN_TEST_ASSERT(!svn_string_compare(svn_date, txn_svn_date));
+
+  /* Commit that instructs the backend to use a specific svn:date, but
+   * doesn't provide one.  This used to fail with BDB prior to r1663697. */
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, rev, SVN_FS_TXN_CLIENT_DATE, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "/zig/bar", pool));
+  SVN_ERR(svn_fs_txn_prop(&txn_svn_date, txn, SVN_PROP_REVISION_DATE, pool));
+  SVN_TEST_ASSERT(txn_svn_date);
+  sleep_for_timestamps();
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  SVN_ERR(svn_fs_revision_proplist(&proplist, fs, rev, pool));
+  svn_date = apr_hash_get(proplist, SVN_PROP_REVISION_DATE,
+                          APR_HASH_KEY_STRING);
+  SVN_TEST_ASSERT(svn_date);
+  SVN_TEST_ASSERT(!svn_string_compare(svn_date, txn_svn_date));
+
   return SVN_NO_ERROR;
 }
 
@@ -5314,7 +5489,7 @@ test_compat_version(const svn_test_opts_
 {
   svn_version_t *compatible_version;
   apr_hash_t *config = apr_hash_make(pool);
-  
+
   svn_version_t vcurrent = {SVN_VER_MAJOR, SVN_VER_MINOR, 0, ""};
   svn_version_t v1_2_0 = {1, 2, 0, ""};
   svn_version_t v1_3_0 = {1, 3, 0, ""};
@@ -5369,7 +5544,7 @@ dir_prop_merge(const svn_test_opts_t *op
   svn_revnum_t head_rev;
   svn_fs_root_t *root;
   svn_fs_txn_t *txn, *mid_txn, *top_txn, *sub_txn, *c_txn;
-  svn_boolean_t is_bdb = strcmp(opts->fs_type, "bdb") == 0;
+  svn_boolean_t is_bdb = strcmp(opts->fs_type, SVN_FS_TYPE_BDB) == 0;
 
   /* Create test repository. */
   SVN_ERR(svn_test__create_fs(&fs, "test-fs-dir_prop-merge", opts, pool));
@@ -5435,100 +5610,6 @@ dir_prop_merge(const svn_test_opts_t *op
   return SVN_NO_ERROR;
 }
 
-#if APR_HAS_THREADS
-struct reopen_modify_baton_t {
-  const char *fs_path;
-  const char *txn_name;
-  apr_pool_t *pool;
-  svn_error_t *err;
-};
-
-static void * APR_THREAD_FUNC
-reopen_modify_child(apr_thread_t *tid, void *data)
-{
-  struct reopen_modify_baton_t *baton = data;
-  svn_fs_t *fs;
-  svn_fs_txn_t *txn;
-  svn_fs_root_t *root;
-
-  baton->err = svn_fs_open(&fs, baton->fs_path, NULL, baton->pool);
-  if (!baton->err)
-    baton->err = svn_fs_open_txn(&txn, fs, baton->txn_name, baton->pool);
-  if (!baton->err)
-    baton->err = svn_fs_txn_root(&root, txn, baton->pool);
-  if (!baton->err)
-    baton->err = svn_fs_change_node_prop(root, "A", "name",
-                                         svn_string_create("value",
-                                                           baton->pool),
-                                         baton->pool);
-  svn_pool_destroy(baton->pool);
-  apr_thread_exit(tid, 0);
-  return NULL;
-}
-#endif
-
-static svn_error_t *
-reopen_modify(const svn_test_opts_t *opts,
-              apr_pool_t *pool)
-{
-#if APR_HAS_THREADS
-  svn_fs_t *fs;
-  svn_revnum_t head_rev = 0;
-  svn_fs_root_t *root;
-  svn_fs_txn_t *txn;
-  const char *fs_path, *txn_name;
-  svn_string_t *value;
-  struct reopen_modify_baton_t baton;
-  apr_status_t status, child_status;
-  apr_threadattr_t *tattr;
-  apr_thread_t *tid;
-
-  /* Create test repository with greek tree. */
-  fs_path = "test-reopen-modify";
-  SVN_ERR(svn_test__create_fs(&fs, fs_path, opts, pool));
-  SVN_ERR(svn_fs_begin_txn(&txn, fs, head_rev, pool));
-  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
-  SVN_ERR(svn_test__create_greek_tree(root, pool));
-  SVN_ERR(test_commit_txn(&head_rev, txn, NULL, pool));
-
-  /* Create txn with changes. */
-  SVN_ERR(svn_fs_begin_txn(&txn, fs, head_rev, pool));
-  SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool)); 
-  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
-  SVN_ERR(svn_fs_make_dir(root, "X", pool));
-
-  /* In another thread: reopen fs and txn, and add more changes.  This
-     works in BDB and FSX but in FSFS the txn_dir_cache becomes
-     out-of-date and the thread's changes don't reach the revision. */
-  baton.fs_path = fs_path;
-  baton.txn_name = txn_name;
-  baton.pool = svn_pool_create(pool);
-  status = apr_threadattr_create(&tattr, pool);
-  if (status)
-    return svn_error_wrap_apr(status, _("Can't create threadattr"));
-  status = apr_thread_create(&tid, tattr, reopen_modify_child, &baton, pool);
-  if (status)
-    return svn_error_wrap_apr(status, _("Can't create thread"));
-  status = apr_thread_join(&child_status, tid);
-  if (status)
-    return svn_error_wrap_apr(status, _("Can't join thread"));
-  if (baton.err)
-    return svn_error_trace(baton.err);
-
-  /* Commit */
-  SVN_ERR(test_commit_txn(&head_rev, txn, NULL, pool));
-
-  /* Check for change made by thread. */
-  SVN_ERR(svn_fs_revision_root(&root, fs, head_rev, pool));
-  SVN_ERR(svn_fs_node_prop(&value, root, "A", "name", pool));
-  SVN_TEST_ASSERT(value && !strcmp(value->data, "value"));
-
-  return SVN_NO_ERROR;
-#else
-  return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, "no thread support");
-#endif
-}
-
 static svn_error_t *
 upgrade_while_committing(const svn_test_opts_t *opts,
                          apr_pool_t *pool)
@@ -5634,7 +5715,7 @@ test_paths_changed(const svn_test_opts_t
   int i;
 
   /* The "mergeinfo_mod flag will say "unknown" until recently. */
-  if (   strcmp(opts->fs_type, "bdb") != 0
+  if (   strcmp(opts->fs_type, SVN_FS_TYPE_BDB) != 0
       && (!opts->server_minor_version || (opts->server_minor_version >= 9)))
     has_mergeinfo_mod = TRUE;
 
@@ -5903,7 +5984,7 @@ compare_contents(const svn_test_opts_t *
   svn_checksum_t *checksum1, *checksum2;
 
   /* (path, rev) pairs to compare plus the expected API return values */
-  struct 
+  struct
     {
       svn_revnum_t rev1;
       const char *path1;
@@ -5931,12 +6012,12 @@ compare_contents(const svn_test_opts_t *
       { 3, "bar", 4, "bar", TRUE, svn_tristate_true },
 
       /* variations on the same theme: same content, possibly different rep */
-      { 4, "foo", 4, "bar", FALSE, svn_tristate_unknown }, 
-      { 1, "foo", 4, "bar", FALSE, svn_tristate_unknown }, 
-      { 2, "foo", 4, "bar", FALSE, svn_tristate_unknown }, 
-      { 1, "foo", 4, "foo", FALSE, svn_tristate_unknown }, 
-      { 2, "foo", 4, "foo", FALSE, svn_tristate_unknown }, 
-      { 2, "bar", 4, "bar", FALSE, svn_tristate_unknown }, 
+      { 4, "foo", 4, "bar", FALSE, svn_tristate_unknown },
+      { 1, "foo", 4, "bar", FALSE, svn_tristate_unknown },
+      { 2, "foo", 4, "bar", FALSE, svn_tristate_unknown },
+      { 1, "foo", 4, "foo", FALSE, svn_tristate_unknown },
+      { 2, "foo", 4, "foo", FALSE, svn_tristate_unknown },
+      { 2, "bar", 4, "bar", FALSE, svn_tristate_unknown },
 
       /* EOL */
       { 0 },
@@ -6218,11 +6299,11 @@ test_print_modules(const svn_test_opts_t
   svn_stringbuf_t *modules = svn_stringbuf_create_empty(pool);
 
   /* Name of the providing module */
-  if (strcmp(opts->fs_type, "fsx") == 0)
+  if (strcmp(opts->fs_type, SVN_FS_TYPE_FSX) == 0)
     module_name = "fs_x";
-  else if (strcmp(opts->fs_type, "fsfs") == 0)
+  else if (strcmp(opts->fs_type, SVN_FS_TYPE_FSFS) == 0)
     module_name = "fs_fs";
-  else if (strcmp(opts->fs_type, "bdb") == 0)
+  else if (strcmp(opts->fs_type, SVN_FS_TYPE_BDB) == 0)
     module_name = "fs_base";
   else
     return svn_error_createf(SVN_ERR_TEST_SKIPPED, NULL,
@@ -6349,7 +6430,7 @@ test_dir_optimal_order(const svn_test_op
 
   /* Call the API function we are interested in. */
   SVN_ERR(svn_fs_dir_entries(&unordered, root, "A", pool));
-  SVN_ERR(svn_fs_dir_optimal_order(&ordered, root, unordered, pool));
+  SVN_ERR(svn_fs_dir_optimal_order(&ordered, root, unordered, pool, pool));
 
   /* Verify that all entries are returned. */
   SVN_TEST_ASSERT(ordered->nelts == apr_hash_count(unordered));
@@ -6549,7 +6630,7 @@ test_fsfs_config_opts(const svn_test_opt
   const svn_fs_fsfs_info_t *fsfs_info;
 
   /* Bail (with SKIP) on known-untestable scenarios */
-  if (strcmp(opts->fs_type, "fsfs") != 0)
+  if (strcmp(opts->fs_type, SVN_FS_TYPE_FSFS) != 0)
     return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
                             "this will test FSFS repositories only");
 
@@ -6655,9 +6736,9 @@ test_modify_txn_being_written(const svn_
   svn_stream_t *bar_contents;
 
   /* Bail (with success) on known-untestable scenarios */
-  if (strcmp(opts->fs_type, SVN_FS_TYPE_FSFS) != 0)
+  if (strcmp(opts->fs_type, SVN_FS_TYPE_BDB) == 0)
     return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
-                            "this will test FSFS repositories only");
+                            "this will not test BDB repositories");
 
   /* Create a new repo. */
   SVN_ERR(svn_test__create_fs(&fs, "test-modify-txn-being-written",
@@ -6743,7 +6824,136 @@ test_prop_and_text_rep_sharing_collision
   SVN_ERR(svn_fs_file_length(&length, rev_root, "/foo", pool));
 
   SVN_TEST_ASSERT(length == 23);
-  return SVN_NO_ERROR; 
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_internal_txn_props(const svn_test_opts_t *opts,
+                        apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_string_t *val;
+  svn_prop_t prop;
+  svn_prop_t internal_prop;
+  apr_array_header_t *props;
+  apr_hash_t *proplist;
+  svn_error_t *err;
+
+  SVN_ERR(svn_test__create_fs(&fs, "test-repo-internal-txn-props",
+                              opts, pool));
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, 0,
+                            SVN_FS_TXN_CHECK_LOCKS |
+                            SVN_FS_TXN_CHECK_OOD |
+                            SVN_FS_TXN_CLIENT_DATE, pool));
+
+  /* Ensure that we cannot read internal transaction properties. */
+  SVN_ERR(svn_fs_txn_prop(&val, txn, SVN_FS__PROP_TXN_CHECK_LOCKS, pool));
+  SVN_TEST_ASSERT(!val);
+  SVN_ERR(svn_fs_txn_prop(&val, txn, SVN_FS__PROP_TXN_CHECK_OOD, pool));
+  SVN_TEST_ASSERT(!val);
+  SVN_ERR(svn_fs_txn_prop(&val, txn, SVN_FS__PROP_TXN_CLIENT_DATE, pool));
+  SVN_TEST_ASSERT(!val);
+
+  SVN_ERR(svn_fs_txn_proplist(&proplist, txn, pool));
+  SVN_TEST_ASSERT(apr_hash_count(proplist) == 1);
+  val = svn_hash_gets(proplist, SVN_PROP_REVISION_DATE);
+  SVN_TEST_ASSERT(val);
+
+  /* We also cannot change or discard them. */
+  val = svn_string_create("Ooops!", pool);
+
+  err = svn_fs_change_txn_prop(txn, SVN_FS__PROP_TXN_CHECK_LOCKS, val, pool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_INCORRECT_PARAMS);
+  err = svn_fs_change_txn_prop(txn, SVN_FS__PROP_TXN_CHECK_LOCKS, NULL, pool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_INCORRECT_PARAMS);
+  err = svn_fs_change_txn_prop(txn, SVN_FS__PROP_TXN_CHECK_OOD, val, pool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_INCORRECT_PARAMS);
+  err = svn_fs_change_txn_prop(txn, SVN_FS__PROP_TXN_CHECK_OOD, NULL, pool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_INCORRECT_PARAMS);
+  err = svn_fs_change_txn_prop(txn, SVN_FS__PROP_TXN_CLIENT_DATE, val, pool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_INCORRECT_PARAMS);
+  err = svn_fs_change_txn_prop(txn, SVN_FS__PROP_TXN_CLIENT_DATE, NULL, pool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_INCORRECT_PARAMS);
+
+  prop.name = "foo";
+  prop.value = svn_string_create("bar", pool);
+  internal_prop.name = SVN_FS__PROP_TXN_CHECK_LOCKS;
+  internal_prop.value = svn_string_create("Ooops!", pool);
+
+  props = apr_array_make(pool, 2, sizeof(svn_prop_t));
+  APR_ARRAY_PUSH(props, svn_prop_t) = prop;
+  APR_ARRAY_PUSH(props, svn_prop_t) = internal_prop;
+
+  err = svn_fs_change_txn_props(txn, props, pool);
+  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_INCORRECT_PARAMS);
+
+  return SVN_NO_ERROR;
+}
+
+/* A freeze function that expects an 'svn_error_t *' baton, and returns it. */
+/* This function implements svn_fs_freeze_func_t. */
+static svn_error_t *
+freeze_func(void *baton, apr_pool_t *pool)
+{
+  return baton;
+}
+
+static svn_error_t *
+freeze_and_commit(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 = 0;
+  apr_pool_t *subpool = svn_pool_create(pool);
+
+  if (!strcmp(opts->fs_type, "bdb"))
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+                            "this will not test BDB repositories");
+
+  SVN_ERR(svn_test__create_fs(&fs, "test-freeze-and-commit", opts, subpool));
+
+  /* This test used to FAIL with an SQLite error since svn_fs_freeze()
+   * wouldn't unlock rep-cache.db.  Therefore, part of the role of creating
+   * the Greek tree is to create a rep-cache.db, in order to test that
+   * svn_fs_freeze() unlocks it. */
+
+  /* r1: Commit the Greek tree. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, new_rev, subpool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
+  SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
+  SVN_ERR(test_commit_txn(&new_rev, txn, NULL, subpool));
+
+  /* Freeze and unfreeze. */
+  SVN_ERR(svn_fs_freeze(fs, freeze_func, SVN_NO_ERROR, pool));
+
+  /* Freeze again, but have freeze_func fail. */
+    {
+      svn_error_t *err = svn_error_create(APR_EGENERAL, NULL, NULL);
+      SVN_TEST_ASSERT_ERROR(svn_fs_freeze(fs, freeze_func, err, pool),
+                            err->apr_err);
+    }
+
+  /* Make some commit using same FS instance. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, new_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_change_node_prop(txn_root, "", "temperature",
+                                  svn_string_create("310.05", pool),
+                                  pool));
+  SVN_ERR(test_commit_txn(&new_rev, txn, NULL, pool));
+
+  /* Re-open FS and make another commit. */
+  SVN_ERR(svn_fs_open(&fs, "test-freeze-and-commit", NULL, subpool));
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, new_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_change_node_prop(txn_root, "/", "temperature",
+                                  svn_string_create("451", pool),
+                                  pool));
+  SVN_ERR(test_commit_txn(&new_rev, txn, NULL, pool));
+
+  return SVN_NO_ERROR;
 }
 
 /* ------------------------------------------------------------------------ */
@@ -6840,9 +7050,6 @@ static struct svn_test_descriptor_t test
                        "test svn_fs__compatible_version"),
     SVN_TEST_OPTS_PASS(dir_prop_merge,
                        "test merge directory properties"),
-    SVN_TEST_OPTS_XFAIL_OTOH(reopen_modify,
-                             "test reopen and modify txn",
-                             SVN_TEST_PASS_IF_FS_TYPE_IS_NOT("fsfs")),
     SVN_TEST_OPTS_PASS(upgrade_while_committing,
                        "upgrade while committing"),
     SVN_TEST_OPTS_PASS(test_paths_changed,
@@ -6874,9 +7081,15 @@ static struct svn_test_descriptor_t test
     SVN_TEST_OPTS_PASS(test_txn_pool_lifetime,
                        "test pool lifetime dependencies with txn roots"),
     SVN_TEST_OPTS_PASS(test_modify_txn_being_written,
-                       "test modify txn being written in FSFS"),
+                       "test modify txn being written"),
     SVN_TEST_OPTS_PASS(test_prop_and_text_rep_sharing_collision,
                        "test property and text rep-sharing collision"),
+    SVN_TEST_OPTS_PASS(test_internal_txn_props,
+                       "test setting and getting internal txn props"),
+    SVN_TEST_OPTS_PASS(check_txn_related,
+                       "test svn_fs_check_related for transactions"),
+    SVN_TEST_OPTS_PASS(freeze_and_commit,
+                       "freeze and commit"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/locks-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/locks-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/locks-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_fs/locks-test.c Sun Jun 14 20:58:10 2015
@@ -58,7 +58,7 @@ get_locks_callback(void *baton,
     {
       apr_hash_set(b->locks, lock_path->data, lock_path->len,
                    svn_lock_dup(lock, hash_pool));
-      return SVN_NO_ERROR; 
+      return SVN_NO_ERROR;
     }
   else
     {
@@ -1101,9 +1101,10 @@ obtain_write_lock_failure(const svn_test
   apr_hash_t *lock_paths, *unlock_paths;
 
   /* The test makes sense only for FSFS. */
-  if (strcmp(opts->fs_type, SVN_FS_TYPE_FSFS) != 0)
+  if (strcmp(opts->fs_type, SVN_FS_TYPE_FSFS) != 0
+      && strcmp(opts->fs_type, SVN_FS_TYPE_FSX) != 0)
     return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
-                            "this will test FSFS repositories only");
+                            "this will test FSFS/FSX repositories only");
 
   SVN_ERR(create_greek_fs(&fs, &newrev, "test-obtain-write-lock-failure",
                           opts, pool));

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c Sun Jun 14 20:58:10 2015
@@ -325,7 +325,7 @@ fuzzing_null_byte_test(const svn_test_op
                              apr_pool_t *pool) \
   { \
     return svn_error_trace(fuzzing_set_byte_test(opts, N, M, pool)); \
-  } 
+  }
 
 /* Add the test function declared above to the test_funcs array. */
 #define TEST_FUZZING_SET_BYTE_TEST_N(N,M)\

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c Sun Jun 14 20:58:10 2015
@@ -144,7 +144,7 @@ create_packed_filesystem(const char *dir
   SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
   SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
   SVN_ERR(svn_fs_change_txn_prop(txn, SVN_PROP_REVISION_LOG,
-                                 svn_string_create(R1_LOG_MSG, pool), 
+                                 svn_string_create(R1_LOG_MSG, pool),
                                  pool));
   SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
   SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
@@ -1164,7 +1164,7 @@ id_parser_test(const svn_test_opts_t *op
                apr_pool_t *pool)
 {
  #define LONG_MAX_STR #LONG_MAX
-  
+
   /* Verify the revision number parser (e.g. first element of a txn ID) */
   svn_fs_fs__id_part_t id_part;
   SVN_ERR(svn_fs_fs__id_txn_parse(&id_part, "0-0"));
@@ -1372,6 +1372,281 @@ plain_0_length(const svn_test_opts_t *op
 
 #undef REPO_NAME
 
+/* ------------------------------------------------------------------------ */
+
+#define REPO_NAME "test-repo-rep_sharing_effectiveness"
+
+static int
+count_substring(svn_stringbuf_t *string,
+                const char *needle)
+{
+  int count = 0;
+  apr_size_t len = strlen(needle);
+  apr_size_t pos;
+
+  for (pos = 0; pos + len <= string->len; ++pos)
+    if (memcmp(string->data + pos, needle, len) == 0)
+      ++count;
+
+  return count;
+}
+
+static svn_error_t *
+count_representations(int *count,
+                      svn_fs_t *fs,
+                      svn_revnum_t revision,
+                      apr_pool_t *pool)
+{
+  svn_stringbuf_t *rev_contents;
+  const char *rev_path = svn_fs_fs__path_rev_absolute(fs, revision, pool);
+  SVN_ERR(svn_stringbuf_from_file2(&rev_contents, rev_path, pool));
+
+  *count = count_substring(rev_contents, "PLAIN")
+         + count_substring(rev_contents, "DELTA");
+
+  return SVN_NO_ERROR;
+}
+
+/* Repeat string S many times to make it big enough for deltification etc.
+   to kick in. */
+static const char*
+multiply_string(const char *s,
+                apr_pool_t *pool)
+{
+  svn_stringbuf_t *temp = svn_stringbuf_create(s, pool);
+
+  int i;
+  for (i = 0; i < 7; ++i)
+    svn_stringbuf_insert(temp, temp->len, temp->data, temp->len);
+
+  return temp->data;
+}
+
+static svn_error_t *
+rep_sharing_effectiveness(const svn_test_opts_t *opts,
+                          apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  fs_fs_data_t *ffd;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *root;
+  svn_revnum_t rev;
+  const char *hello_str = multiply_string("Hello, ", pool);
+  const char *world_str = multiply_string("World!", pool);
+  const char *goodbye_str = multiply_string("Goodbye!", pool);
+
+  if (strcmp(opts->fs_type, "fsfs") != 0)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL);
+
+  /* Create a repo that and explicitly enable rep sharing. */
+  SVN_ERR(svn_test__create_fs(&fs, REPO_NAME, opts, pool));
+
+  ffd = fs->fsap_data;
+  if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL);
+
+  ffd->rep_sharing_allowed = TRUE;
+
+  /* Revision 1: create 2 files with different content. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_fs_make_file(root, "foo", pool));
+  SVN_ERR(svn_test__set_file_contents(root, "foo", hello_str, pool));
+  SVN_ERR(svn_fs_make_file(root, "bar", pool));
+  SVN_ERR(svn_test__set_file_contents(root, "bar", world_str, pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  /* Revision 2: modify a file to match another file's r1 content and
+                 add another with the same content.
+                 (classic rep-sharing). */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_test__set_file_contents(root, "foo", world_str, pool));
+  SVN_ERR(svn_fs_make_file(root, "baz", pool));
+  SVN_ERR(svn_test__set_file_contents(root, "baz", hello_str, pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  /* Revision 3: modify all files to some new, identical content and add
+                 another with the same content.
+                 (in-revision rep-sharing). */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_test__set_file_contents(root, "foo", goodbye_str, pool));
+  SVN_ERR(svn_test__set_file_contents(root, "bar", goodbye_str, pool));
+  SVN_ERR(svn_test__set_file_contents(root, "baz", goodbye_str, pool));
+  SVN_ERR(svn_fs_make_file(root, "qux", pool));
+  SVN_ERR(svn_test__set_file_contents(root, "qux", goodbye_str, pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  /* Verify revision contents. */
+  {
+    const struct {
+      svn_revnum_t revision;
+      const char *file;
+      const char *contents;
+    } expected[] = {
+      { 1, "foo", "Hello, " },
+      { 1, "bar", "World!" },
+      { 2, "foo", "World!" },
+      { 2, "bar", "World!" },
+      { 2, "baz", "Hello, " },
+      { 3, "foo", "Goodbye!" },
+      { 3, "bar", "Goodbye!" },
+      { 3, "baz", "Goodbye!" },
+      { 3, "qux", "Goodbye!" },
+      { SVN_INVALID_REVNUM, NULL, NULL }
+    };
+
+    int i;
+    apr_pool_t *iterpool = svn_pool_create(pool);
+    for (i = 0; SVN_IS_VALID_REVNUM(expected[i].revision); ++i)
+      {
+        svn_stringbuf_t *str;
+
+        SVN_ERR(svn_fs_revision_root(&root, fs, expected[i].revision,
+                                     iterpool));
+        SVN_ERR(svn_test__get_file_contents(root, expected[i].file, &str,
+                                            iterpool));
+
+        SVN_TEST_STRING_ASSERT(str->data,
+                               multiply_string(expected[i].contents,
+                                               iterpool));
+      }
+
+    svn_pool_destroy(iterpool);
+  }
+
+  /* Verify that rep sharing eliminated most reps. */
+  {
+    /* Number of expected representations (including the root directory). */
+    const int expected[] = { 1, 3, 1, 2 } ;
+
+    svn_revnum_t i;
+    apr_pool_t *iterpool = svn_pool_create(pool);
+    for (i = 0; i <= rev; ++i)
+      {
+        int count;
+        SVN_ERR(count_representations(&count, fs, i, iterpool));
+        SVN_TEST_ASSERT(count == expected[i]);
+      }
+
+    svn_pool_destroy(iterpool);
+  }
+
+  return SVN_NO_ERROR;
+}
+
+#undef REPO_NAME
+
+/* ------------------------------------------------------------------------ */
+
+#define REPO_NAME "test-repo-delta_chain_with_plain"
+
+static svn_error_t *
+delta_chain_with_plain(const svn_test_opts_t *opts,
+                       apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  fs_fs_data_t *ffd;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *root;
+  svn_revnum_t rev;
+  svn_stringbuf_t *prop_value, *contents, *contents2, *hash_rep;
+  int i;
+  apr_hash_t *fs_config, *props;
+
+  if (strcmp(opts->fs_type, "fsfs") != 0)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL);
+
+  /* Reproducing issue #4577 without the r1676667 fix is much harder in 1.9+
+   * than it was in 1.8.  The reason is that 1.9+ won't deltify small reps
+   * nor against small reps.  So, we must construct relatively large PLAIN
+   * and DELTA reps.
+   *
+   * The idea is to construct a PLAIN prop rep, make a file share that as
+   * its text rep, grow the file considerably (to make the PLAIN rep later
+   * read beyond EOF) and then replace it entirely with another longish
+   * contents.
+   */
+
+  /* Create a repo that and explicitly enable rep sharing. */
+  SVN_ERR(svn_test__create_fs(&fs, REPO_NAME, opts, pool));
+
+  ffd = fs->fsap_data;
+  if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL);
+
+  ffd->rep_sharing_allowed = TRUE;
+
+  /* Make sure all props are stored as PLAIN reps. */
+  ffd->deltify_properties = FALSE;
+
+  /* Construct various content strings.
+   * Note that props need to be shorter than the file contents. */
+  prop_value = svn_stringbuf_create("prop", pool);
+  for (i = 0; i < 10; ++i)
+    svn_stringbuf_appendstr(prop_value, prop_value);
+
+  contents = svn_stringbuf_create("Some text.", pool);
+  for (i = 0; i < 10; ++i)
+    svn_stringbuf_appendstr(contents, contents);
+
+  contents2 = svn_stringbuf_create("Totally new!", pool);
+  for (i = 0; i < 10; ++i)
+    svn_stringbuf_appendstr(contents2, contents2);
+
+  /* Revision 1: create a property rep. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_fs_change_node_prop(root, "/", "p",
+                                  svn_string_create(prop_value->data, pool),
+                                  pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  /* Revision 2: create a file that shares the text rep with the PLAIN
+   * property rep from r1. */
+  props = apr_hash_make(pool);
+  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_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_fs_make_file(root, "foo", pool));
+  SVN_ERR(svn_test__set_file_contents(root, "foo", hash_rep->data, pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  /* Revision 3: modify the file contents to a long-ish full text
+   * (~10kByte, longer than the r1 revision file). */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_test__set_file_contents(root, "foo", contents->data, pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  /* Revision 4: replace file contents to something disjoint from r3. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_test__set_file_contents(root, "foo", contents2->data, pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+
+  /* Getting foo@4 must work.  To make sure we actually read from disk,
+   * use a new FS instance with disjoint caches. */
+  fs_config = apr_hash_make(pool);
+  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NS,
+                           svn_uuid_generate(pool));
+  SVN_ERR(svn_fs_open2(&fs, REPO_NAME, fs_config, pool, pool));
+
+  SVN_ERR(svn_fs_revision_root(&root, fs, rev, pool));
+  SVN_ERR(svn_test__get_file_contents(root, "foo", &contents, pool));
+  SVN_TEST_STRING_ASSERT(contents->data, contents2->data);
+
+  return SVN_NO_ERROR;
+}
+
+#undef REPO_NAME
+
 
 /* The test table.  */
 
@@ -1416,6 +1691,10 @@ static struct svn_test_descriptor_t test
                        "id parser test"),
     SVN_TEST_OPTS_PASS(plain_0_length,
                        "file with 0 expanded-length, issue #4554"),
+    SVN_TEST_OPTS_PASS(rep_sharing_effectiveness,
+                       "rep-sharing effectiveness"),
+    SVN_TEST_OPTS_PASS(delta_chain_with_plain,
+                       "delta chains starting with PLAIN, issue #4577"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c Sun Jun 14 20:58:10 2015
@@ -349,8 +349,6 @@ dump_index(const svn_test_opts_t *opts,
 
 /* ------------------------------------------------------------------------ */
 
-#define REPO_NAME "test-repo-load-index-test"
-
 static svn_error_t *
 receive_index(const svn_fs_fs__p2l_entry_t *entry,
               void *baton,
@@ -364,8 +362,8 @@ receive_index(const svn_fs_fs__p2l_entry
 }
 
 static svn_error_t *
-load_index(const svn_test_opts_t *opts,
-           apr_pool_t *pool)
+load_index_test(const svn_test_opts_t *opts, apr_pool_t *pool,
+                const char *repo_name, svn_boolean_t keep_going)
 {
   svn_repos_t *repos;
   svn_revnum_t rev;
@@ -383,7 +381,7 @@ load_index(const svn_test_opts_t *opts,
                             "pre-1.9 SVN doesn't have FSFS indexes");
 
   /* Create a filesystem */
-  SVN_ERR(create_greek_repo(&repos, &rev, opts, REPO_NAME, pool, pool));
+  SVN_ERR(create_greek_repo(&repos, &rev, opts, repo_name, pool, pool));
 
   /* Read the original index contents for REV in ENTRIES. */
   SVN_ERR(svn_fs_fs__dump_index(svn_repos_fs(repos), rev, receive_index,
@@ -400,19 +398,33 @@ load_index(const svn_test_opts_t *opts,
 
   SVN_ERR(svn_fs_fs__load_index(svn_repos_fs(repos), rev, alt_entries, pool));
   SVN_TEST_ASSERT_ERROR(svn_repos_verify_fs3(repos, rev, rev,
-                                             FALSE, FALSE, FALSE,
+                                             keep_going, FALSE, FALSE,
                                              NULL, NULL, NULL, NULL, pool),
-                        SVN_ERR_REPOS_CORRUPTED);
+                        (keep_going
+                         ? SVN_ERR_REPOS_VERIFY_FAILED
+                         : SVN_ERR_FS_INDEX_CORRUPTION));
 
   /* Restore the original index. */
   SVN_ERR(svn_fs_fs__load_index(svn_repos_fs(repos), rev, entries, pool));
-  SVN_ERR(svn_repos_verify_fs3(repos, rev, rev, FALSE, FALSE, FALSE,
+  SVN_ERR(svn_repos_verify_fs3(repos, rev, rev, keep_going, FALSE, FALSE,
                                NULL, NULL, NULL, NULL, pool));
 
   return SVN_NO_ERROR;
 }
 
-#undef REPO_NAME
+static svn_error_t *
+load_index(const svn_test_opts_t *opts,
+           apr_pool_t *pool)
+{
+  return load_index_test(opts, pool, "test-repo-load-index-test", FALSE);
+}
+
+static svn_error_t *
+load_index_keep_going(const svn_test_opts_t *opts,
+                      apr_pool_t *pool)
+{
+  return load_index_test(opts, pool, "test-repo-load-index-full-test", TRUE);
+}
 
 
 /* The test table.  */
@@ -428,6 +440,8 @@ static struct svn_test_descriptor_t test
                        "dump the P2L index"),
     SVN_TEST_OPTS_PASS(load_index,
                        "load the P2L index"),
+    SVN_TEST_OPTS_PASS(load_index_keep_going,
+                       "load the P2L index (full verification)"),
     SVN_TEST_NULL
   };
 

Propchange: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sun Jun 14 20:58:10 2015
@@ -56,6 +56,7 @@
 /subversion/branches/nfc-nfd-aware-client/subversion/tests/libsvn_fs_x:870276,870376
 /subversion/branches/node_pool/subversion/tests/libsvn_fs_x:1304828-1305388
 /subversion/branches/performance/subversion/tests/libsvn_fs_x:979193,980118,981087,981090,981189,981194,981287,981684,981827,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-10293
 36,1029339-1029340,1029342,1029344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
+/subversion/branches/pin-externals/subversion/tests/libsvn_fs_x:1643757-1659392
 /subversion/branches/py-tests-as-modules/subversion/tests/libsvn_fs_x:956579-1033052
 /subversion/branches/ra_serf-digest-authn/subversion/tests/libsvn_fs_x:875693-876404
 /subversion/branches/reintegrate-improvements/subversion/tests/libsvn_fs_x:873853-874164
@@ -82,4 +83,4 @@
 /subversion/branches/verify-at-commit/subversion/tests/libsvn_fs_x:1462039-1462408
 /subversion/branches/verify-keep-going/subversion/tests/libsvn_fs_x:1439280-1492639,1546002-1546110
 /subversion/branches/wc-collate-path/subversion/tests/libsvn_fs_x:1402685-1480384
-/subversion/trunk/subversion/tests/libsvn_fs_x:1414756-1509914
+/subversion/trunk/subversion/tests/libsvn_fs_x:1414756-1509914,1658218-1685462

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/fs-x-pack-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/fs-x-pack-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/fs-x-pack-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/fs-x-pack-test.c Sun Jun 14 20:58:10 2015
@@ -166,7 +166,7 @@ create_packed_filesystem(const char *dir
   SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
   SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
   SVN_ERR(svn_fs_change_txn_prop(txn, SVN_PROP_REVISION_LOG,
-                                 svn_string_create(R1_LOG_MSG, pool), 
+                                 svn_string_create(R1_LOG_MSG, pool),
                                  pool));
   SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
   SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));

Modified: subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/string-table-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/string-table-test.c?rev=1685464&r1=1685463&r2=1685464&view=diff
==============================================================================
--- subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/string-table-test.c (original)
+++ subversion/branches/fsx-1.10/subversion/tests/libsvn_fs_x/string-table-test.c Sun Jun 14 20:58:10 2015
@@ -124,19 +124,19 @@ short_string_table_body(svn_boolean_t do
                         apr_pool_t *pool)
 {
   apr_size_t indexes[STRING_COUNT] = { 0 };
-    
+
   string_table_builder_t *builder;
   string_table_t *table;
   int i;
-  
+
   builder = svn_fs_x__string_table_builder_create(pool);
   for (i = 0; i < STRING_COUNT; ++i)
     indexes[i] = svn_fs_x__string_table_builder_add(builder, basic_strings[i], 0);
-  
+
   table = svn_fs_x__string_table_create(builder, pool);
   if (do_load_store)
     SVN_ERR(store_and_load_table(&table, pool));
-  
+
   SVN_TEST_ASSERT(indexes[2] == indexes[6]);
   for (i = 0; i < STRING_COUNT; ++i)
     {



Mime
View raw message