You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/06/14 22:58:16 UTC
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...
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 *) = ©_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 *) = ©_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)
{