You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ph...@apache.org on 2015/05/06 16:22:52 UTC
svn commit: r1678004 [2/3] - in /subversion/trunk: build.conf
subversion/tests/libsvn_fs/fs-sequential-test.c
subversion/tests/libsvn_fs/fs-test.c
Copied: subversion/trunk/subversion/tests/libsvn_fs/fs-sequential-test.c (from r1677901, subversion/trunk/subversion/tests/libsvn_fs/fs-test.c)
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_fs/fs-sequential-test.c?p2=subversion/trunk/subversion/tests/libsvn_fs/fs-sequential-test.c&p1=subversion/trunk/subversion/tests/libsvn_fs/fs-test.c&r1=1677901&r2=1678004&rev=1678004&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_fs/fs-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_fs/fs-sequential-test.c Wed May 6 14:22:51 2015
@@ -1,4 +1,4 @@
-/* fs-test.c --- tests for the filesystem
+/* fs-sequential-test.c --- tests for the filesystem
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -53,7 +53,7 @@
/*-----------------------------------------------------------------*/
-/** The actual fs-tests called by `make check` **/
+/** The actual fs-sequential-tests called by `make check` **/
/* Helper: commit TXN, expecting either success or failure:
*
@@ -148,6978 +148,112 @@ test_commit_txn(svn_revnum_t *new_rev,
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;
+};
-
-/* Begin a txn, check its name, then close it */
-static svn_error_t *
-trivial_transaction(const svn_test_opts_t *opts,
- apr_pool_t *pool)
-{
- svn_fs_t *fs;
- svn_fs_txn_t *txn;
- const char *txn_name;
- int is_invalid_char[256];
- int i;
- const char *p;
-
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-trivial-txn",
- opts, pool));
-
- /* Begin a new transaction that is based on revision 0. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
-
- /* Test that the txn name is non-null. */
- SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
-
- if (! txn_name)
- return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
- "Got a NULL txn name.");
-
- /* Test that the txn name contains only valid characters. See
- svn_fs.h for the list of valid characters. */
- for (i = 0; i < sizeof(is_invalid_char)/sizeof(*is_invalid_char); ++i)
- is_invalid_char[i] = 1;
- for (i = '0'; i <= '9'; ++i)
- is_invalid_char[i] = 0;
- for (i = 'a'; i <= 'z'; ++i)
- is_invalid_char[i] = 0;
- for (i = 'A'; i <= 'Z'; ++i)
- is_invalid_char[i] = 0;
- for (p = "-."; *p; ++p)
- is_invalid_char[(unsigned char) *p] = 0;
-
- for (p = txn_name; *p; ++p)
- {
- if (is_invalid_char[(unsigned char) *p])
- return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
- "The txn name '%s' contains an illegal '%c' "
- "character", txn_name, *p);
- }
-
- return SVN_NO_ERROR;
-}
-
-
-
-/* Open an existing transaction by name. */
-static svn_error_t *
-reopen_trivial_transaction(const svn_test_opts_t *opts,
- apr_pool_t *pool)
-{
- svn_fs_t *fs;
- svn_fs_txn_t *txn;
- svn_fs_root_t *root;
- const char *txn_name;
- apr_pool_t *subpool = svn_pool_create(pool);
-
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-reopen-trivial-txn",
- opts, pool));
-
- /* Create a first transaction - we don't want that one to reopen. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, subpool));
-
- /* Begin a second transaction that is based on revision 0. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, subpool));
-
- /* Don't use the subpool, txn_name must persist beyond the current txn */
- SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
-
- /* Create a third transaction - we don't want that one to reopen. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, subpool));
-
- /* Close the transaction. */
- svn_pool_clear(subpool);
-
- /* Reopen the transaction by name */
- SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, subpool));
-
- /* Does it have the same name? */
- SVN_ERR(svn_fs_txn_root(&root, txn, subpool));
- SVN_TEST_STRING_ASSERT(svn_fs_txn_root_name(root, subpool), txn_name);
-
- /* Close the transaction ... again. */
- svn_pool_destroy(subpool);
-
- return SVN_NO_ERROR;
-}
-
-
-
-/* Create a file! */
-static svn_error_t *
-create_file_transaction(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_ERR(svn_test__create_fs(&fs, "test-repo-create-file-txn",
- opts, pool));
-
- /* Begin a new transaction that is based on revision 0. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
-
- /* Get the txn root */
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Create a new file in the root directory. */
- SVN_ERR(svn_fs_make_file(txn_root, "beer.txt", pool));
-
- return SVN_NO_ERROR;
-}
-
-
-/* Make sure we get txn lists correctly. */
-static svn_error_t *
-verify_txn_list(const svn_test_opts_t *opts,
- apr_pool_t *pool)
-{
- svn_fs_t *fs;
- apr_pool_t *subpool;
- svn_fs_txn_t *txn1, *txn2;
- const char *name1, *name2;
- apr_array_header_t *txn_list;
-
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-verify-txn-list",
- opts, pool));
-
- /* Begin a new transaction, get its name (in the top pool), close it. */
- subpool = svn_pool_create(pool);
- SVN_ERR(svn_fs_begin_txn(&txn1, fs, 0, subpool));
- SVN_ERR(svn_fs_txn_name(&name1, txn1, pool));
- svn_pool_destroy(subpool);
-
- /* Begin *another* transaction, get its name (in the top pool), close it. */
- subpool = svn_pool_create(pool);
- SVN_ERR(svn_fs_begin_txn(&txn2, fs, 0, subpool));
- SVN_ERR(svn_fs_txn_name(&name2, txn2, pool));
- svn_pool_destroy(subpool);
-
- /* Get the list of active transactions from the fs. */
- SVN_ERR(svn_fs_list_transactions(&txn_list, fs, pool));
-
- /* Check the list. It should have *exactly* two entries. */
- if (txn_list->nelts != 2)
- goto all_bad;
-
- /* We should be able to find our 2 txn names in the list, in some
- order. */
- if ((! strcmp(name1, APR_ARRAY_IDX(txn_list, 0, const char *)))
- && (! strcmp(name2, APR_ARRAY_IDX(txn_list, 1, const char *))))
- goto all_good;
-
- else if ((! strcmp(name2, APR_ARRAY_IDX(txn_list, 0, const char *)))
- && (! strcmp(name1, APR_ARRAY_IDX(txn_list, 1, const char *))))
- goto all_good;
-
- all_bad:
-
- return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
- "Got a bogus txn list.");
- all_good:
-
- return SVN_NO_ERROR;
-}
-
-
-/* Generate N consecutive transactions, then abort them all. Return
- the list of transaction names. */
-static svn_error_t *
-txn_names_are_not_reused_helper1(apr_hash_t **txn_names,
- svn_fs_t *fs,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
- const int N = 10;
- int i;
-
- *txn_names = apr_hash_make(pool);
-
- /* Create the transactions and store in a hash table the transaction
- name as the key and the svn_fs_txn_t * as the value. */
- for (i = 0; i < N; ++i)
- {
- svn_fs_txn_t *txn;
- const char *name;
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_name(&name, txn, pool));
- if (apr_hash_get(*txn_names, name, APR_HASH_KEY_STRING) != NULL)
- return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
- "beginning a new transaction used an "
- "existing transaction name '%s'",
- name);
- apr_hash_set(*txn_names, name, APR_HASH_KEY_STRING, txn);
- }
-
- i = 0;
- for (hi = apr_hash_first(pool, *txn_names); hi; hi = apr_hash_next(hi))
- {
- void *val;
- apr_hash_this(hi, NULL, NULL, &val);
- SVN_ERR(svn_fs_abort_txn((svn_fs_txn_t *)val, pool));
- ++i;
- }
-
- if (i != N)
- return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
- "created %d transactions, but only aborted %d",
- N, i);
-
- return SVN_NO_ERROR;
-}
-
-/* Compare two hash tables and ensure that no keys in the first hash
- table appear in the second hash table. */
-static svn_error_t *
-txn_names_are_not_reused_helper2(apr_hash_t *ht1,
- apr_hash_t *ht2,
- apr_pool_t *pool)
-{
- apr_hash_index_t *hi;
-
- for (hi = apr_hash_first(pool, ht1); hi; hi = apr_hash_next(hi))
- {
- const void *key;
- const char *key_string;
- apr_hash_this(hi, &key, NULL, NULL);
- key_string = key;
- if (apr_hash_get(ht2, key, APR_HASH_KEY_STRING) != NULL)
- return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
- "the transaction name '%s' was reused",
- key_string);
- }
-
- return SVN_NO_ERROR;
-}
-
-/* Make sure that transaction names are not reused. */
-static svn_error_t *
-txn_names_are_not_reused(const svn_test_opts_t *opts,
- apr_pool_t *pool)
-{
- svn_fs_t *fs;
- apr_pool_t *subpool;
- apr_hash_t *txn_names1, *txn_names2;
-
- /* Bail (with success) on known-untestable scenarios */
- if ((strcmp(opts->fs_type, "fsfs") == 0)
- && (opts->server_minor_version && (opts->server_minor_version < 5)))
- return SVN_NO_ERROR;
-
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-txn-names-are-not-reused",
- opts, pool));
-
- subpool = svn_pool_create(pool);
-
- /* Create N transactions, abort them all, and collect the generated
- transaction names. Do this twice. */
- SVN_ERR(txn_names_are_not_reused_helper1(&txn_names1, fs, subpool));
- SVN_ERR(txn_names_are_not_reused_helper1(&txn_names2, fs, subpool));
-
- /* Check that no transaction names appear in both hash tables. */
- SVN_ERR(txn_names_are_not_reused_helper2(txn_names1, txn_names2, subpool));
- SVN_ERR(txn_names_are_not_reused_helper2(txn_names2, txn_names1, subpool));
-
- svn_pool_destroy(subpool);
-
- return SVN_NO_ERROR;
-}
-
-
-
-/* Test writing & reading a file's contents. */
-static svn_error_t *
-write_and_read_file(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_stream_t *rstream;
- svn_stringbuf_t *rstring;
- svn_stringbuf_t *wstring;
-
- wstring = svn_stringbuf_create("Wicki wild, wicki wicki wild.", pool);
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-read-and-write-file",
- opts, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Add an empty file. */
- SVN_ERR(svn_fs_make_file(txn_root, "beer.txt", pool));
-
- /* And write some data into this file. */
- SVN_ERR(svn_test__set_file_contents(txn_root, "beer.txt",
- wstring->data, pool));
-
- /* Now let's read the data back from the file. */
- SVN_ERR(svn_fs_file_contents(&rstream, txn_root, "beer.txt", pool));
- SVN_ERR(svn_test__stream_to_string(&rstring, rstream, pool));
-
- /* Compare what was read to what was written. */
- if (! svn_stringbuf_compare(rstring, wstring))
- return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
- "data read != data written.");
-
- return SVN_NO_ERROR;
-}
-
-
-
-/* Create a file, a directory, and a file in that directory! */
-static svn_error_t *
-create_mini_tree_transaction(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_ERR(svn_test__create_fs(&fs, "test-repo-create-mini-tree-txn",
- opts, pool));
-
- /* Begin a new transaction that is based on revision 0. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
-
- /* Get the txn root */
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Create a new file in the root directory. */
- SVN_ERR(svn_fs_make_file(txn_root, "wine.txt", pool));
-
- /* Create a new directory in the root directory. */
- SVN_ERR(svn_fs_make_dir(txn_root, "keg", pool));
-
- /* Now, create a file in our new directory. */
- SVN_ERR(svn_fs_make_file(txn_root, "keg/beer.txt", pool));
-
- return SVN_NO_ERROR;
-}
-
-
-/* Create a file, a directory, and a file in that directory! */
-static svn_error_t *
-create_greek_tree_transaction(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;
-
- /* Prepare a txn to receive the greek tree. */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-create-greek-tree-txn",
- opts, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Create and verify the greek tree. */
- SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
-
- return SVN_NO_ERROR;
-}
-
-
-/* Verify that entry KEY is present in ENTRIES, and that its value is
- an svn_fs_dirent_t whose name and id are not null. */
-static svn_error_t *
-verify_entry(apr_hash_t *entries, const char *key)
-{
- svn_fs_dirent_t *ent = apr_hash_get(entries, key,
- APR_HASH_KEY_STRING);
-
- if (ent == NULL)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "didn't find dir entry for \"%s\"", key);
-
- if ((ent->name == NULL) && (ent->id == NULL))
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "dir entry for \"%s\" has null name and null id", key);
-
- if (ent->name == NULL)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "dir entry for \"%s\" has null name", key);
-
- if (ent->id == NULL)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "dir entry for \"%s\" has null id", key);
-
- if (strcmp(ent->name, key) != 0)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "dir entry for \"%s\" contains wrong name (\"%s\")", key, ent->name);
-
- return SVN_NO_ERROR;
-}
-
-
-static svn_error_t *
-list_directory(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;
- apr_hash_t *entries;
-
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-list-dir",
- opts, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* We create this tree
- *
- * /q
- * /A/x
- * /A/y
- * /A/z
- * /B/m
- * /B/n
- * /B/o
- *
- * then list dir A. It should have 3 files: "x", "y", and "z", no
- * more, no less.
- */
-
- /* Create the tree. */
- SVN_ERR(svn_fs_make_file(txn_root, "q", pool));
- SVN_ERR(svn_fs_make_dir(txn_root, "A", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/x", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/y", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/z", pool));
- SVN_ERR(svn_fs_make_dir(txn_root, "B", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "B/m", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "B/n", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "B/o", pool));
-
- /* Get A's entries. */
- SVN_ERR(svn_fs_dir_entries(&entries, txn_root, "A", pool));
-
- /* Make sure exactly the right set of entries is present. */
- if (apr_hash_count(entries) != 3)
- {
- return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
- "unexpected number of entries in dir");
- }
- else
- {
- SVN_ERR(verify_entry(entries, "x"));
- SVN_ERR(verify_entry(entries, "y"));
- SVN_ERR(verify_entry(entries, "z"));
- }
-
- return SVN_NO_ERROR;
-}
-
-
-/* If EXPR raises SVN_ERR_FS_PROP_BASEVALUE_MISMATCH, continue; else, fail
- * the test. */
-#define FAILS_WITH_BOV(expr) \
- do { \
- svn_error_t *__err = (expr); \
- if (!__err || __err->apr_err != SVN_ERR_FS_PROP_BASEVALUE_MISMATCH) \
- return svn_error_create(SVN_ERR_TEST_FAILED, __err, \
- "svn_fs_change_rev_prop2() failed to " \
- "detect unexpected old value"); \
- else \
- svn_error_clear(__err); \
- } while (0)
-
-static svn_error_t *
-revision_props(const svn_test_opts_t *opts,
- apr_pool_t *pool)
-{
- svn_fs_t *fs;
- apr_hash_t *proplist;
- svn_string_t *value;
- int i;
- svn_string_t s1;
-
- const char *initial_props[4][2] = {
- { "color", "red" },
- { "size", "XXL" },
- { "favorite saturday morning cartoon", "looney tunes" },
- { "auto", "Green 1997 Saturn SL1" }
- };
-
- const char *final_props[4][2] = {
- { "color", "violet" },
- { "flower", "violet" },
- { "favorite saturday morning cartoon", "looney tunes" },
- { "auto", "Red 2000 Chevrolet Blazer" }
- };
-
- /* Open the fs */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-rev-props",
- opts, pool));
-
- /* Set some properties on the revision. */
- for (i = 0; i < 4; i++)
- {
- SET_STR(&s1, initial_props[i][1]);
- SVN_ERR(svn_fs_change_rev_prop(fs, 0, initial_props[i][0], &s1, pool));
- }
-
- /* Change some of the above properties. */
- SET_STR(&s1, "violet");
- SVN_ERR(svn_fs_change_rev_prop(fs, 0, "color", &s1, pool));
-
- SET_STR(&s1, "Red 2000 Chevrolet Blazer");
- SVN_ERR(svn_fs_change_rev_prop(fs, 0, "auto", &s1, pool));
-
- /* Remove a property altogether */
- SVN_ERR(svn_fs_change_rev_prop(fs, 0, "size", NULL, pool));
-
- /* Copy a property's value into a new property. */
- SVN_ERR(svn_fs_revision_prop(&value, fs, 0, "color", pool));
- SVN_TEST_ASSERT(value);
-
- s1.data = value->data;
- s1.len = value->len;
- SVN_ERR(svn_fs_change_rev_prop(fs, 0, "flower", &s1, pool));
-
- /* Test svn_fs_change_rev_prop2(). If the whole block goes through, then
- * it is a no-op (it undoes all changes it makes). */
- {
- const svn_string_t s2 = { "wrong value", 11 };
- const svn_string_t *s2_p = &s2;
- const svn_string_t *s1_p = &s1;
- const svn_string_t *unset = NULL;
- const svn_string_t *s1_dup;
-
- /* Value of "flower" is 's1'. */
-
- FAILS_WITH_BOV(svn_fs_change_rev_prop2(fs, 0, "flower", &s2_p, s1_p, pool));
- s1_dup = svn_string_dup(&s1, pool);
- SVN_ERR(svn_fs_change_rev_prop2(fs, 0, "flower", &s1_dup, s2_p, pool));
-
- /* Value of "flower" is 's2'. */
-
- FAILS_WITH_BOV(svn_fs_change_rev_prop2(fs, 0, "flower", &s1_p, NULL, pool));
- SVN_ERR(svn_fs_change_rev_prop2(fs, 0, "flower", &s2_p, NULL, pool));
-
- /* Value of "flower" is <not set>. */
-
- FAILS_WITH_BOV(svn_fs_change_rev_prop2(fs, 0, "flower", &s2_p, s1_p, pool));
- SVN_ERR(svn_fs_change_rev_prop2(fs, 0, "flower", &unset, s1_p, pool));
-
- /* Value of "flower" is 's1'. */
- }
-
- /* Obtain a list of all current properties, and make sure it matches
- the expected values. */
- SVN_ERR(svn_fs_revision_proplist(&proplist, fs, 0, pool));
- SVN_TEST_ASSERT(proplist);
- {
- svn_string_t *prop_value;
-
- if (apr_hash_count(proplist) < 4 )
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "too few revision properties found");
-
- /* Loop through our list of expected revision property name/value
- pairs. */
- for (i = 0; i < 4; i++)
- {
- /* For each expected property: */
-
- /* Step 1. Find it by name in the hash of all rev. props
- returned to us by svn_fs_revision_proplist. If it can't be
- found, return an error. */
- prop_value = apr_hash_get(proplist,
- final_props[i][0],
- APR_HASH_KEY_STRING);
- if (! prop_value)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "unable to find expected revision property");
-
- /* Step 2. Make sure the value associated with it is the same
- as what was expected, else return an error. */
- if (strcmp(prop_value->data, final_props[i][1]))
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "revision property had an unexpected value");
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-
-static svn_error_t *
-transaction_props(const svn_test_opts_t *opts,
- apr_pool_t *pool)
-{
- svn_fs_t *fs;
- svn_fs_txn_t *txn;
- apr_hash_t *proplist;
- svn_string_t *value;
- svn_revnum_t after_rev;
- int i;
- svn_string_t s1;
-
- const char *initial_props[4][2] = {
- { "color", "red" },
- { "size", "XXL" },
- { "favorite saturday morning cartoon", "looney tunes" },
- { "auto", "Green 1997 Saturn SL1" }
- };
-
- const char *final_props[5][2] = {
- { "color", "violet" },
- { "flower", "violet" },
- { "favorite saturday morning cartoon", "looney tunes" },
- { "auto", "Red 2000 Chevrolet Blazer" },
- { SVN_PROP_REVISION_DATE, "<some datestamp value>" }
- };
-
- /* Open the fs */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-txn-props",
- opts, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
-
- /* Set some properties on the revision. */
- for (i = 0; i < 4; i++)
- {
- SET_STR(&s1, initial_props[i][1]);
- SVN_ERR(svn_fs_change_txn_prop(txn, initial_props[i][0], &s1, pool));
- }
-
- /* Change some of the above properties. */
- SET_STR(&s1, "violet");
- SVN_ERR(svn_fs_change_txn_prop(txn, "color", &s1, pool));
-
- SET_STR(&s1, "Red 2000 Chevrolet Blazer");
- SVN_ERR(svn_fs_change_txn_prop(txn, "auto", &s1, pool));
-
- /* Remove a property altogether */
- SVN_ERR(svn_fs_change_txn_prop(txn, "size", NULL, pool));
-
- /* Copy a property's value into a new property. */
- SVN_ERR(svn_fs_txn_prop(&value, txn, "color", pool));
-
- s1.data = value->data;
- s1.len = value->len;
- SVN_ERR(svn_fs_change_txn_prop(txn, "flower", &s1, pool));
-
- /* Obtain a list of all current properties, and make sure it matches
- the expected values. */
- SVN_ERR(svn_fs_txn_proplist(&proplist, txn, pool));
- {
- svn_string_t *prop_value;
-
- /* All transactions get a datestamp property at their inception,
- so we expect *5*, not 4 properties. */
- if (apr_hash_count(proplist) != 5 )
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "unexpected number of transaction properties were found");
-
- /* Loop through our list of expected revision property name/value
- pairs. */
- for (i = 0; i < 5; i++)
- {
- /* For each expected property: */
-
- /* Step 1. Find it by name in the hash of all rev. props
- returned to us by svn_fs_revision_proplist. If it can't be
- found, return an error. */
- prop_value = apr_hash_get(proplist,
- final_props[i][0],
- APR_HASH_KEY_STRING);
- if (! prop_value)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "unable to find expected transaction property");
-
- /* Step 2. Make sure the value associated with it is the same
- as what was expected, else return an error. */
- if (strcmp(final_props[i][0], SVN_PROP_REVISION_DATE))
- if (strcmp(prop_value->data, final_props[i][1]))
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "transaction property had an unexpected value");
- }
- }
-
- /* Commit the transaction. */
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- if (after_rev != 1)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "committed transaction got wrong revision number");
-
- /* Obtain a list of all properties on the new revision, and make
- sure it matches the expected values. If you're wondering, the
- expected values should be the exact same set of properties that
- existed on the transaction just prior to its being committed. */
- SVN_ERR(svn_fs_revision_proplist(&proplist, fs, after_rev, pool));
- {
- svn_string_t *prop_value;
-
- if (apr_hash_count(proplist) < 5 )
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "unexpected number of revision properties were found");
-
- /* Loop through our list of expected revision property name/value
- pairs. */
- for (i = 0; i < 5; i++)
- {
- /* For each expected property: */
-
- /* Step 1. Find it by name in the hash of all rev. props
- returned to us by svn_fs_revision_proplist. If it can't be
- found, return an error. */
- prop_value = apr_hash_get(proplist,
- final_props[i][0],
- APR_HASH_KEY_STRING);
- if (! prop_value)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "unable to find expected revision property");
-
- /* Step 2. Make sure the value associated with it is the same
- as what was expected, else return an error. */
- if (strcmp(final_props[i][0], SVN_PROP_REVISION_DATE))
- if (strcmp(prop_value->data, final_props[i][1]))
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "revision property had an unexpected value");
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-
-static svn_error_t *
-node_props(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;
- apr_hash_t *proplist;
- svn_string_t *value;
- int i;
- svn_string_t s1;
-
- const char *initial_props[4][2] = {
- { "Best Rock Artist", "Creed" },
- { "Best Rap Artist", "Eminem" },
- { "Best Country Artist", "(null)" },
- { "Best Sound Designer", "Pluessman" }
- };
-
- const char *final_props[4][2] = {
- { "Best Rock Artist", "P.O.D." },
- { "Best Rap Artist", "Busta Rhymes" },
- { "Best Sound Designer", "Pluessman" },
- { "Biggest Cakewalk Fanatic", "Pluessman" }
- };
-
- /* Open the fs and transaction */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-node-props",
- opts, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Make a node to put some properties into */
- SVN_ERR(svn_fs_make_file(txn_root, "music.txt", pool));
-
- /* Set some properties on the nodes. */
- for (i = 0; i < 4; i++)
- {
- SET_STR(&s1, initial_props[i][1]);
- SVN_ERR(svn_fs_change_node_prop
- (txn_root, "music.txt", initial_props[i][0], &s1, pool));
- }
-
- /* Change some of the above properties. */
- SET_STR(&s1, "P.O.D.");
- SVN_ERR(svn_fs_change_node_prop(txn_root, "music.txt", "Best Rock Artist",
- &s1, pool));
-
- SET_STR(&s1, "Busta Rhymes");
- SVN_ERR(svn_fs_change_node_prop(txn_root, "music.txt", "Best Rap Artist",
- &s1, pool));
-
- /* Remove a property altogether */
- SVN_ERR(svn_fs_change_node_prop(txn_root, "music.txt",
- "Best Country Artist", NULL, pool));
-
- /* Copy a property's value into a new property. */
- SVN_ERR(svn_fs_node_prop(&value, txn_root, "music.txt",
- "Best Sound Designer", pool));
-
- s1.data = value->data;
- s1.len = value->len;
- SVN_ERR(svn_fs_change_node_prop(txn_root, "music.txt",
- "Biggest Cakewalk Fanatic", &s1, pool));
-
- /* Obtain a list of all current properties, and make sure it matches
- the expected values. */
- SVN_ERR(svn_fs_node_proplist(&proplist, txn_root, "music.txt", pool));
- {
- svn_string_t *prop_value;
-
- if (apr_hash_count(proplist) != 4 )
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "unexpected number of node properties were found");
-
- /* Loop through our list of expected node property name/value
- pairs. */
- for (i = 0; i < 4; i++)
- {
- /* For each expected property: */
-
- /* Step 1. Find it by name in the hash of all node props
- returned to us by svn_fs_node_proplist. If it can't be
- found, return an error. */
- prop_value = apr_hash_get(proplist,
- final_props[i][0],
- APR_HASH_KEY_STRING);
- if (! prop_value)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "unable to find expected node property");
-
- /* Step 2. Make sure the value associated with it is the same
- as what was expected, else return an error. */
- if (strcmp(prop_value->data, final_props[i][1]))
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "node property had an unexpected value");
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-
-
-/* Set *PRESENT to true if entry NAME is present in directory PATH
- under ROOT, else set *PRESENT to false. */
-static svn_error_t *
-check_entry(svn_fs_root_t *root,
- const char *path,
- const char *name,
- svn_boolean_t *present,
- apr_pool_t *pool)
-{
- apr_hash_t *entries;
- svn_fs_dirent_t *ent;
-
- SVN_ERR(svn_fs_dir_entries(&entries, root, path, pool));
- ent = apr_hash_get(entries, name, APR_HASH_KEY_STRING);
-
- if (ent)
- *present = TRUE;
- else
- *present = FALSE;
-
- return SVN_NO_ERROR;
-}
-
-
-/* Return an error if entry NAME is absent in directory PATH under ROOT. */
-static svn_error_t *
-check_entry_present(svn_fs_root_t *root, const char *path,
- const char *name, apr_pool_t *pool)
-{
- svn_boolean_t present = FALSE;
- SVN_ERR(check_entry(root, path, name, &present, pool));
-
- if (! present)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "entry \"%s\" absent when it should be present", name);
-
- return SVN_NO_ERROR;
-}
-
-
-/* Return an error if entry NAME is present in directory PATH under ROOT. */
-static svn_error_t *
-check_entry_absent(svn_fs_root_t *root, const char *path,
- const char *name, apr_pool_t *pool)
-{
- svn_boolean_t present = TRUE;
- SVN_ERR(check_entry(root, path, name, &present, pool));
-
- if (present)
- return svn_error_createf
- (SVN_ERR_FS_GENERAL, NULL,
- "entry \"%s\" present when it should be absent", name);
-
- return SVN_NO_ERROR;
-}
-
-
-/* Fetch the youngest revision from a repos. */
-static svn_error_t *
-fetch_youngest_rev(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;
- svn_revnum_t youngest_rev, new_youngest_rev;
-
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-youngest-rev",
- opts, pool));
-
- /* Get youngest revision of brand spankin' new filesystem. */
- SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
-
- /* Prepare a txn to receive the greek tree. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Create the greek tree. */
- SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
-
- /* Commit it. */
- SVN_ERR(test_commit_txn(&new_rev, txn, NULL, pool));
-
- /* Get the new youngest revision. */
- SVN_ERR(svn_fs_youngest_rev(&new_youngest_rev, fs, pool));
-
- if (youngest_rev == new_rev)
- return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
- "commit didn't bump up revision number");
-
- if (new_youngest_rev != new_rev)
- return svn_error_create(SVN_ERR_FS_GENERAL, NULL,
- "couldn't fetch youngest revision");
-
- return SVN_NO_ERROR;
-}
-
-
-/* Test committing against an empty repository.
- todo: also test committing against youngest? */
-static svn_error_t *
-basic_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, *revision_root;
- svn_revnum_t before_rev, after_rev;
- const char *conflict;
-
- /* Prepare a filesystem. */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-basic-commit",
- opts, pool));
-
- /* Save the current youngest revision. */
- SVN_ERR(svn_fs_youngest_rev(&before_rev, fs, pool));
-
- /* Prepare a txn to receive the greek tree. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Paranoidly check that the current youngest rev is unchanged. */
- SVN_ERR(svn_fs_youngest_rev(&after_rev, fs, pool));
- if (after_rev != before_rev)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "youngest revision changed unexpectedly");
-
- /* Create the greek tree. */
- SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
- SVN_TEST_ASSERT(svn_fs_is_txn_root(txn_root));
- SVN_TEST_ASSERT(!svn_fs_is_revision_root(txn_root));
-
- /* Commit it. */
- SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, pool));
- SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
-
- /* Make sure it's a different revision than before. */
- if (after_rev == before_rev)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "youngest revision failed to change");
-
- /* Get root of the revision */
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_TEST_ASSERT(!svn_fs_is_txn_root(revision_root));
- SVN_TEST_ASSERT(svn_fs_is_revision_root(revision_root));
-
- /* Check the tree. */
- SVN_ERR(svn_test__check_greek_tree(revision_root, pool));
-
- return SVN_NO_ERROR;
-}
-
-
-
-static svn_error_t *
-test_tree_node_validation(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, *revision_root;
- svn_revnum_t after_rev;
- const char *conflict;
- apr_pool_t *subpool;
-
- /* Prepare a filesystem. */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-validate-tree-entries",
- opts, pool));
-
- /* In a txn, create the greek tree. */
- subpool = svn_pool_create(pool);
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "iota", "This is the file 'iota'.\n" },
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/H", 0 },
- { "A/D/H/chi", "This is the file 'chi'.\n" },
- { "A/D/H/psi", "This is the file 'psi'.\n" },
- { "A/D/H/omega", "This is the file 'omega'.\n" }
- };
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, subpool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
- SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
-
- /* Carefully validate that tree in the transaction. */
- SVN_ERR(svn_test__validate_tree(txn_root, expected_entries, 20,
- subpool));
-
- /* Go ahead and commit the tree, and destroy the txn object. */
- SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
- SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
-
- /* Carefully validate that tree in the new revision, now. */
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, subpool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries, 20,
- subpool));
- }
- svn_pool_destroy(subpool);
-
- /* In a new txn, modify the greek tree. */
- subpool = svn_pool_create(pool);
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "iota", "This is a new version of 'iota'.\n" },
- { "A", 0 },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/H", 0 },
- { "A/D/H/chi", "This is the file 'chi'.\n" },
- { "A/D/H/psi", "This is the file 'psi'.\n" },
- { "A/D/H/omega", "This is the file 'omega'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
-
- SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, subpool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "iota", "This is a new version of 'iota'.\n",
- subpool));
- SVN_ERR(svn_fs_delete(txn_root, "A/mu", subpool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/G", subpool));
- SVN_ERR(svn_fs_make_dir(txn_root, "A/D/I", subpool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/I/delta", subpool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/I/delta", "This is the file 'delta'.\n",
- subpool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/I/epsilon", subpool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/I/epsilon", "This is the file 'epsilon'.\n",
- subpool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/C/kappa", subpool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/C/kappa", "This is the file 'kappa'.\n",
- subpool));
-
- /* Carefully validate that tree in the transaction. */
- SVN_ERR(svn_test__validate_tree(txn_root, expected_entries, 19,
- subpool));
-
- /* Go ahead and commit the tree, and destroy the txn object. */
- SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
- SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(after_rev));
-
- /* Carefully validate that tree in the new revision, now. */
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, subpool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries,
- 19, subpool));
- }
- svn_pool_destroy(subpool);
-
- return SVN_NO_ERROR;
-}
-
-
-/* Commit with merging (committing against non-youngest). */
-static svn_error_t *
-merging_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, *revision_root;
- svn_revnum_t after_rev;
- svn_revnum_t revisions[24];
- apr_size_t i;
- svn_revnum_t revision_count;
-
- /* Prepare a filesystem. */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-merging-commit",
- opts, pool));
-
- /* Initialize our revision number stuffs. */
- for (i = 0;
- i < ((sizeof(revisions)) / (sizeof(svn_revnum_t)));
- i++)
- revisions[i] = SVN_INVALID_REVNUM;
- revision_count = 0;
- revisions[revision_count++] = 0; /* the brand spankin' new revision */
-
- /***********************************************************************/
- /* REVISION 0 */
- /***********************************************************************/
-
- /* In one txn, create and commit the greek tree. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- /***********************************************************************/
- /* REVISION 1 */
- /***********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "iota", "This is the file 'iota'.\n" },
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/H", 0 },
- { "A/D/H/chi", "This is the file 'chi'.\n" },
- { "A/D/H/psi", "This is the file 'psi'.\n" },
- { "A/D/H/omega", "This is the file 'omega'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries,
- 20, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* Let's add a directory and some files to the tree, and delete
- 'iota' */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[revision_count-1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_dir(txn_root, "A/D/I", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/I/delta", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/I/delta", "This is the file 'delta'.\n", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/I/epsilon", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/I/epsilon", "This is the file 'epsilon'.\n", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/C/kappa", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/C/kappa", "This is the file 'kappa'.\n", pool));
- SVN_ERR(svn_fs_delete(txn_root, "iota", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- /***********************************************************************/
- /* REVISION 2 */
- /***********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/H", 0 },
- { "A/D/H/chi", "This is the file 'chi'.\n" },
- { "A/D/H/psi", "This is the file 'psi'.\n" },
- { "A/D/H/omega", "This is the file 'omega'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries,
- 23, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* We don't think the A/D/H directory is pulling its weight...let's
- knock it off. Oh, and let's re-add iota, too. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[revision_count-1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/H", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "iota", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "iota", "This is the new file 'iota'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- /***********************************************************************/
- /* REVISION 3 */
- /***********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "iota", "This is the new file 'iota'.\n" },
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries,
- 20, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* Delete iota (yet again). */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[revision_count-1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_delete(txn_root, "iota", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- /***********************************************************************/
- /* REVISION 4 */
- /***********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries,
- 19, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /***********************************************************************/
- /* GIVEN: A and B, with common ancestor ANCESTOR, where A and B
- directories, and E, an entry in either A, B, or ANCESTOR.
-
- For every E, the following cases exist:
- - E exists in neither ANCESTOR nor A.
- - E doesn't exist in ANCESTOR, and has been added to A.
- - E exists in ANCESTOR, but has been deleted from A.
- - E exists in both ANCESTOR and A ...
- - but refers to different node revisions.
- - and refers to the same node revision.
-
- The same set of possible relationships with ANCESTOR holds for B,
- so there are thirty-six combinations. The matrix is symmetrical
- with A and B reversed, so we only have to describe one triangular
- half, including the diagonal --- 21 combinations.
-
- Our goal here is to test all the possible scenarios that can
- occur given the above boolean logic table, and to make sure that
- the results we get are as expected.
-
- The test cases below have the following features:
-
- - They run straight through the scenarios as described in the
- `structure' document at this time.
-
- - In each case, a txn is begun based on some revision (ANCESTOR),
- is modified into a new tree (B), and then is attempted to be
- committed (which happens against the head of the tree, A).
-
- - If the commit is successful (and is *expected* to be such),
- that new revision (which exists now as a result of the
- successful commit) is thoroughly tested for accuracy of tree
- entries, and in the case of files, for their contents. It is
- important to realize that these successful commits are
- advancing the head of the tree, and each one effective becomes
- the new `A' described in further test cases.
- */
- /***********************************************************************/
-
- /* (6) E exists in neither ANCESTOR nor A. */
- {
- /* (1) E exists in neither ANCESTOR nor B. Can't occur, by
- assumption that E exists in either A, B, or ancestor. */
-
- /* (1) E has been added to B. Add E in the merged result. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[0], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_file(txn_root, "theta", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "theta", "This is the file 'theta'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- /*********************************************************************/
- /* REVISION 5 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root,
- expected_entries,
- 20, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* (1) E has been deleted from B. Can't occur, by assumption that
- E doesn't exist in ANCESTOR. */
-
- /* (3) E exists in both ANCESTOR and B. Can't occur, by
- assumption that E doesn't exist in ancestor. */
- }
-
- /* (5) E doesn't exist in ANCESTOR, and has been added to A. */
- {
- svn_revnum_t failed_rev;
- /* (1) E doesn't exist in ANCESTOR, and has been added to B.
- Conflict. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[4], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_file(txn_root, "theta", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "theta", "This is another file 'theta'.\n", pool));
-
- /* TXN must actually be based upon revisions[4] (instead of HEAD). */
- SVN_TEST_ASSERT(svn_fs_txn_base_revision(txn) == revisions[4]);
-
- SVN_ERR(test_commit_txn(&failed_rev, txn, "/theta", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- /* (1) E exists in ANCESTOR, but has been deleted from B. Can't
- occur, by assumption that E doesn't exist in ANCESTOR. */
-
- /* (3) E exists in both ANCESTOR and B. Can't occur, by assumption
- that E doesn't exist in ANCESTOR. */
-
- SVN_TEST_ASSERT(failed_rev == SVN_INVALID_REVNUM);
- }
-
- /* (4) E exists in ANCESTOR, but has been deleted from A */
- {
- /* (1) E exists in ANCESTOR, but has been deleted from B. If
- neither delete was a result of a rename, then omit E from the
- merged tree. Otherwise, conflict. */
- /* ### cmpilato todo: the rename case isn't actually handled by
- merge yet, so we know we won't get a conflict here. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/H", pool));
-
- /* TXN must actually be based upon revisions[1] (instead of HEAD). */
- SVN_TEST_ASSERT(svn_fs_txn_base_revision(txn) == revisions[1]);
-
- /* We used to create the revision like this before fixing issue
- #2751 -- Directory prop mods reverted in overlapping commits scenario.
-
- But we now expect that to fail as out of date */
- {
- svn_revnum_t failed_rev;
- SVN_ERR(test_commit_txn(&failed_rev, txn, "/A/D/H", pool));
-
- SVN_TEST_ASSERT(failed_rev == SVN_INVALID_REVNUM);
- }
- /*********************************************************************/
- /* REVISION 6 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root,
- expected_entries,
- 20, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* Try deleting a file F inside a subtree S where S does not exist
- in the most recent revision, but does exist in the ancestor
- tree. This should conflict. */
- {
- svn_revnum_t failed_rev;
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/H/omega", pool));
- SVN_ERR(test_commit_txn(&failed_rev, txn, "/A/D/H", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- SVN_TEST_ASSERT(failed_rev == SVN_INVALID_REVNUM);
- }
-
- /* E exists in both ANCESTOR and B ... */
- {
- /* (1) but refers to different nodes. Conflict. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_dir(txn_root, "A/D/H", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- revisions[revision_count++] = after_rev;
-
- /*********************************************************************/
- /* REVISION 7 */
- /*********************************************************************/
-
- /* Re-remove A/D/H because future tests expect it to be absent. */
- {
- SVN_ERR(svn_fs_begin_txn
- (&txn, fs, revisions[revision_count - 1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/H", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- revisions[revision_count++] = after_rev;
- }
-
- /*********************************************************************/
- /* REVISION 8 (looks exactly like revision 6, we hope) */
- /*********************************************************************/
-
- /* (1) but refers to different revisions of the same node.
- Conflict. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/H/zeta", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, "/A/D/H", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- /* (1) and refers to the same node revision. Omit E from the
- merged tree. This is already tested in Merge-Test 3
- (A/D/H/chi, A/D/H/psi, e.g.), but we'll test it here again
- anyway. A little paranoia never hurt anyone. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/mu", pool)); /* unrelated change */
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- /*********************************************************************/
- /* REVISION 9 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root,
- expected_entries,
- 19, pool));
- }
- revisions[revision_count++] = after_rev;
- }
- }
-
- /* Preparation for upcoming tests.
- We make a new head revision, with A/mu restored, but containing
- slightly different contents than its first incarnation. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[revision_count-1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/mu", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/mu", "A new file 'mu'.\n", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/G/xi", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/G/xi", "This is the file 'xi'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- /*********************************************************************/
- /* REVISION 10 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/mu", "A new file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/G/xi", "This is the file 'xi'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries,
- 21, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* (3) E exists in both ANCESTOR and A, but refers to different
- nodes. */
- {
- /* (1) E exists in both ANCESTOR and B, but refers to different
- nodes, and not all nodes are directories. Conflict. */
-
- /* ### kff todo: A/mu's contents will be exactly the same.
- If the fs ever starts optimizing this case, these tests may
- start to fail. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/mu", pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/mu", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/mu", "This is the file 'mu'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, "/A/mu", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- /* (1) E exists in both ANCESTOR and B, but refers to different
- revisions of the same node. Conflict. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/mu", "A change to file 'mu'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, "/A/mu", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- /* (1) E exists in both ANCESTOR and B, and refers to the same
- node revision. Replace E with A's node revision. */
- {
- svn_stringbuf_t *old_mu_contents;
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__get_file_contents
- (txn_root, "A/mu", &old_mu_contents, pool));
- if ((! old_mu_contents) || (strcmp(old_mu_contents->data,
- "This is the file 'mu'.\n") != 0))
- {
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "got wrong contents from an old revision tree");
- }
- SVN_ERR(svn_fs_make_file(txn_root, "A/sigma", pool));
- SVN_ERR(svn_test__set_file_contents /* unrelated change */
- (txn_root, "A/sigma", "This is the file 'sigma'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- /*********************************************************************/
- /* REVISION 11 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/mu", "A new file 'mu'.\n" },
- { "A/sigma", "This is the file 'sigma'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/G/xi", "This is the file 'xi'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root,
- expected_entries,
- 22, pool));
- }
- revisions[revision_count++] = after_rev;
- }
- }
-
- /* Preparation for upcoming tests.
- We make a new head revision. There are two changes in the new
- revision: A/B/lambda has been modified. We will also use the
- recent addition of A/D/G/xi, treated as a modification to
- A/D/G. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[revision_count-1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/B/lambda", "Change to file 'lambda'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- /*********************************************************************/
- /* REVISION 12 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/mu", "A new file 'mu'.\n" },
- { "A/sigma", "This is the file 'sigma'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "Change to file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/G/xi", "This is the file 'xi'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root, expected_entries,
- 22, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* (2) E exists in both ANCESTOR and A, but refers to different
- revisions of the same node. */
- {
- /* (1a) E exists in both ANCESTOR and B, but refers to different
- revisions of the same file node. Conflict. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/B/lambda", "A different change to 'lambda'.\n",
- pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, "/A/B/lambda", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- /* (1b) E exists in both ANCESTOR and B, but refers to different
- revisions of the same directory node. Merge A/E and B/E,
- recursively. Succeed, because no conflict beneath E. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/G/nu", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/G/nu", "This is the file 'nu'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- /*********************************************************************/
- /* REVISION 13 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/mu", "A new file 'mu'.\n" },
- { "A/sigma", "This is the file 'sigma'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "Change to file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/G/xi", "This is the file 'xi'.\n" },
- { "A/D/G/nu", "This is the file 'nu'.\n" },
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root,
- expected_entries,
- 23, pool));
- }
- revisions[revision_count++] = after_rev;
-
- /* (1c) E exists in both ANCESTOR and B, but refers to different
- revisions of the same directory node. Merge A/E and B/E,
- recursively. Fail, because conflict beneath E. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_make_file(txn_root, "A/D/G/xi", pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/G/xi", "This is a different file 'xi'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, "/A/D/G/xi", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- /* (1) E exists in both ANCESTOR and B, and refers to the same node
- revision. Replace E with A's node revision. */
- {
- svn_stringbuf_t *old_lambda_ctnts;
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__get_file_contents
- (txn_root, "A/B/lambda", &old_lambda_ctnts, pool));
- if ((! old_lambda_ctnts)
- || (strcmp(old_lambda_ctnts->data,
- "This is the file 'lambda'.\n") != 0))
- {
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "got wrong contents from an old revision tree");
- }
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/G/rho",
- "This is an irrelevant change to 'rho'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- /*********************************************************************/
- /* REVISION 14 */
- /*********************************************************************/
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "theta", "This is the file 'theta'.\n" },
- { "A", 0 },
- { "A/mu", "A new file 'mu'.\n" },
- { "A/sigma", "This is the file 'sigma'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "Change to file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/C/kappa", "This is the file 'kappa'.\n" },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is an irrelevant change to 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/G/xi", "This is the file 'xi'.\n" },
- { "A/D/G/nu", "This is the file 'nu'.\n"},
- { "A/D/I", 0 },
- { "A/D/I/delta", "This is the file 'delta'.\n" },
- { "A/D/I/epsilon", "This is the file 'epsilon'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&revision_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(revision_root,
- expected_entries,
- 23, pool));
- }
- revisions[revision_count++] = after_rev;
- }
- }
-
- /* (1) E exists in both ANCESTOR and A, and refers to the same node
- revision. */
- {
- /* (1) E exists in both ANCESTOR and B, and refers to the same
- node revision. Nothing has happened to ANCESTOR/E, so no
- change is necessary. */
-
- /* This has now been tested about fifty-four trillion times. We
- don't need to test it again here. */
- }
-
- /* E exists in ANCESTOR, but has been deleted from A. E exists in
- both ANCESTOR and B but refers to different revisions of the same
- node. Conflict. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, revisions[1], pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "iota", "New contents for 'iota'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, "/iota", pool));
- SVN_ERR(svn_fs_abort_txn(txn, pool));
-
- return SVN_NO_ERROR;
-}
-
-
-static svn_error_t *
-copy_test(const svn_test_opts_t *opts,
- apr_pool_t *pool)
-{
- svn_fs_t *fs;
- svn_fs_txn_t *txn;
- svn_fs_root_t *txn_root, *rev_root;
- svn_revnum_t after_rev;
-
- /* Prepare a filesystem. */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-copy",
- opts, pool));
-
- /* In first txn, create and commit the greek tree. */
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- /* In second txn, copy the file A/D/G/pi into the subtree A/D/H as
- pi2. Change that file's contents to state its new name. Along
- the way, test that the copy history was preserved both during the
- transaction and after the commit. */
-
- SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_copy(rev_root, "A/D/G/pi",
- txn_root, "A/D/H/pi2",
- pool));
- { /* Check that copy history was preserved. */
- svn_revnum_t rev;
- const char *path;
-
- SVN_ERR(svn_fs_copied_from(&rev, &path, txn_root,
- "A/D/H/pi2", pool));
-
- if (rev != after_rev)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "pre-commit copy history not preserved (rev lost) for A/D/H/pi2");
-
- if (strcmp(path, "/A/D/G/pi") != 0)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "pre-commit copy history not preserved (path lost) for A/D/H/pi2");
- }
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/H/pi2", "This is the file 'pi2'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
-
- { /* Check that copy history is still preserved _after_ the commit. */
- svn_fs_root_t *root;
- svn_revnum_t rev;
- const char *path;
-
- SVN_ERR(svn_fs_revision_root(&root, fs, after_rev, pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "A/D/H/pi2", pool));
-
- if (rev != (after_rev - 1))
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "post-commit copy history wrong (rev) for A/D/H/pi2");
-
- if (strcmp(path, "/A/D/G/pi") != 0)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "post-commit copy history wrong (path) for A/D/H/pi2");
- }
-
- /* Let's copy the copy we just made, to make sure copy history gets
- chained correctly. */
- SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_copy(rev_root, "A/D/H/pi2", txn_root, "A/D/H/pi3", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- { /* Check the copy history. */
- svn_fs_root_t *root;
- svn_revnum_t rev;
- const char *path;
-
- /* Check that the original copy still has its old history. */
- SVN_ERR(svn_fs_revision_root(&root, fs, (after_rev - 1), pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "A/D/H/pi2", pool));
-
- if (rev != (after_rev - 2))
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "first copy history wrong (rev) for A/D/H/pi2");
-
- if (strcmp(path, "/A/D/G/pi") != 0)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "first copy history wrong (path) for A/D/H/pi2");
-
- /* Check that the copy of the copy has the right history. */
- SVN_ERR(svn_fs_revision_root(&root, fs, after_rev, pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "A/D/H/pi3", pool));
-
- if (rev != (after_rev - 1))
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "second copy history wrong (rev) for A/D/H/pi3");
-
- if (strcmp(path, "/A/D/H/pi2") != 0)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "second copy history wrong (path) for A/D/H/pi3");
- }
-
- /* Commit a regular change to a copy, make sure the copy history
- isn't inherited. */
- SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_test__set_file_contents
- (txn_root, "A/D/H/pi3", "This is the file 'pi3'.\n", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- { /* Check the copy history. */
- svn_fs_root_t *root;
- svn_revnum_t rev;
- const char *path;
-
- /* Check that the copy still has its history. */
- SVN_ERR(svn_fs_revision_root(&root, fs, (after_rev - 1), pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "A/D/H/pi3", pool));
-
- if (rev != (after_rev - 2))
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (rev) for A/D/H/pi3");
-
- if (strcmp(path, "/A/D/H/pi2") != 0)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (path) for A/D/H/pi3");
-
- /* Check that the next revision after the copy has no copy history. */
- SVN_ERR(svn_fs_revision_root(&root, fs, after_rev, pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "A/D/H/pi3", pool));
-
- if (rev != SVN_INVALID_REVNUM)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (rev) for A/D/H/pi3");
-
- if (path != NULL)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (path) for A/D/H/pi3");
- }
-
- /* Then, as if that wasn't fun enough, copy the whole subtree A/D/H
- into the root directory as H2! */
- SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_copy(rev_root, "A/D/H", txn_root, "H2", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- { /* Check the copy history. */
- svn_fs_root_t *root;
- svn_revnum_t rev;
- const char *path;
-
- /* Check that the top of the copy has history. */
- SVN_ERR(svn_fs_revision_root(&root, fs, after_rev, pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "H2", pool));
-
- if (rev != (after_rev - 1))
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (rev) for H2");
-
- if (strcmp(path, "/A/D/H") != 0)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (path) for H2");
-
- /* Check that a random file under H2 reports no copy history. */
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "H2/omega", pool));
-
- if (rev != SVN_INVALID_REVNUM)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (rev) for H2/omega");
-
- if (path != NULL)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (path) for H2/omega");
-
- /* Note that H2/pi2 still has copy history, though. See the doc
- string for svn_fs_copied_from() for more on this. */
- }
-
- /* Let's live dangerously. What happens if we copy a path into one
- of its own children. Looping filesystem? Cyclic ancestry?
- Another West Virginia family tree with no branches? We certainly
- hope that's not the case. */
- SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
- SVN_ERR(svn_fs_copy(rev_root, "A/B", txn_root, "A/B/E/B", pool));
- SVN_ERR(test_commit_txn(&after_rev, txn, NULL, pool));
- { /* Check the copy history. */
- svn_fs_root_t *root;
- svn_revnum_t rev;
- const char *path;
-
- /* Check that the copy has history. */
- SVN_ERR(svn_fs_revision_root(&root, fs, after_rev, pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "A/B/E/B", pool));
-
- if (rev != (after_rev - 1))
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (rev) for A/B/E/B");
-
- if (strcmp(path, "/A/B") != 0)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (path) for A/B/E/B");
-
- /* Check that the original does not have copy history. */
- SVN_ERR(svn_fs_revision_root(&root, fs, after_rev, pool));
- SVN_ERR(svn_fs_copied_from(&rev, &path, root, "A/B", pool));
-
- if (rev != SVN_INVALID_REVNUM)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (rev) for A/B");
-
- if (path != NULL)
- return svn_error_create
- (SVN_ERR_FS_GENERAL, NULL,
- "copy history wrong (path) for A/B");
- }
-
- /* After all these changes, let's see if the filesystem looks as we
- would expect it to. */
- {
- static svn_test__tree_entry_t expected_entries[] = {
- /* path, contents (0 = dir) */
- { "iota", "This is the file 'iota'.\n" },
- { "H2", 0 },
- { "H2/chi", "This is the file 'chi'.\n" },
- { "H2/pi2", "This is the file 'pi2'.\n" },
- { "H2/pi3", "This is the file 'pi3'.\n" },
- { "H2/psi", "This is the file 'psi'.\n" },
- { "H2/omega", "This is the file 'omega'.\n" },
- { "A", 0 },
- { "A/mu", "This is the file 'mu'.\n" },
- { "A/B", 0 },
- { "A/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E", 0 },
- { "A/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/E/B", 0 },
- { "A/B/E/B/lambda", "This is the file 'lambda'.\n" },
- { "A/B/E/B/E", 0 },
- { "A/B/E/B/E/alpha", "This is the file 'alpha'.\n" },
- { "A/B/E/B/E/beta", "This is the file 'beta'.\n" },
- { "A/B/E/B/F", 0 },
- { "A/B/F", 0 },
- { "A/C", 0 },
- { "A/D", 0 },
- { "A/D/gamma", "This is the file 'gamma'.\n" },
- { "A/D/G", 0 },
- { "A/D/G/pi", "This is the file 'pi'.\n" },
- { "A/D/G/rho", "This is the file 'rho'.\n" },
- { "A/D/G/tau", "This is the file 'tau'.\n" },
- { "A/D/H", 0 },
- { "A/D/H/chi", "This is the file 'chi'.\n" },
- { "A/D/H/pi2", "This is the file 'pi2'.\n" },
- { "A/D/H/pi3", "This is the file 'pi3'.\n" },
- { "A/D/H/psi", "This is the file 'psi'.\n" },
- { "A/D/H/omega", "This is the file 'omega'.\n" }
- };
- SVN_ERR(svn_fs_revision_root(&rev_root, fs, after_rev, pool));
- SVN_ERR(svn_test__validate_tree(rev_root, expected_entries,
- 34, pool));
- }
-
- return SVN_NO_ERROR;
-}
-
-
-/* This tests deleting of mutable nodes. We build a tree in a
- * transaction, then try to delete various items in the tree. We
- * never commit the tree, so every entry being deleted points to a
- * mutable node.
- *
- * ### todo: this test was written before commits worked. It might
- * now be worthwhile to combine it with delete().
- */
-static svn_error_t *
-delete_mutables(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_error_t *err;
-
- /* Prepare a txn to receive the greek tree. */
- SVN_ERR(svn_test__create_fs(&fs, "test-repo-del-from-dir",
- opts, pool));
- SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
- SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
-
- /* Create the greek tree. */
- SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
-
- /* Baby, it's time to test like you've never tested before. We do
- * the following, in this order:
- *
- * 1. Delete a single file somewhere, succeed.
- * 2. Delete two files of three, then make sure the third remains.
- * 3. Delete the third and last file.
- * 4. Try again to delete the dir, succeed.
- * 5. Delete one of the natively empty dirs, succeed.
- * 6. Try to delete root, fail.
- * 7. Try to delete a top-level file, succeed.
- *
- * Specifically, that's:
- *
- * 1. Delete A/D/gamma.
- * 2. Delete A/D/G/pi, A/D/G/rho.
- * 3. Delete A/D/G/tau.
- * 4. Try again to delete A/D/G, succeed.
- * 5. Delete A/C.
- * 6. Try to delete /, fail.
- * 7. Try to delete iota, succeed.
- *
- * Before and after each deletion or attempted deletion, we probe
- * the affected directory, to make sure everything is as it should
- * be.
- */
-
- /* 1 */
- {
- const svn_fs_id_t *gamma_id;
- SVN_ERR(svn_fs_node_id(&gamma_id, txn_root, "A/D/gamma", pool));
- SVN_ERR(check_entry_present(txn_root, "A/D", "gamma", pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/gamma", pool));
- SVN_ERR(check_entry_absent(txn_root, "A/D", "gamma", pool));
- }
-
- /* 2 */
- {
- const svn_fs_id_t *pi_id, *rho_id, *tau_id;
- SVN_ERR(svn_fs_node_id(&pi_id, txn_root, "A/D/G/pi", pool));
- SVN_ERR(svn_fs_node_id(&rho_id, txn_root, "A/D/G/rho", pool));
- SVN_ERR(svn_fs_node_id(&tau_id, txn_root, "A/D/G/tau", pool));
- SVN_ERR(check_entry_present(txn_root, "A/D/G", "pi", pool));
- SVN_ERR(check_entry_present(txn_root, "A/D/G", "rho", pool));
- SVN_ERR(check_entry_present(txn_root, "A/D/G", "tau", pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/G/pi", pool));
- SVN_ERR(check_entry_absent(txn_root, "A/D/G", "pi", pool));
- SVN_ERR(check_entry_present(txn_root, "A/D/G", "rho", pool));
- SVN_ERR(check_entry_present(txn_root, "A/D/G", "tau", pool));
- SVN_ERR(svn_fs_delete(txn_root, "A/D/G/rho", pool));
[... 4735 lines stripped ...]