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) {
