summaryrefslogtreecommitdiff
path: root/subversion/tests/cmdline
diff options
context:
space:
mode:
authorJames McCoy <jamessan@debian.org>2018-10-02 21:50:32 -0400
committerJames McCoy <jamessan@debian.org>2018-10-02 21:50:32 -0400
commit784e881a5aaa645a37eda4fb775484f27c81143a (patch)
tree3702672116cb73f976a31fd30a57824e12339050 /subversion/tests/cmdline
parentfb8514369ffb04ec2aea8d8ee7916fdff101b84e (diff)
parentdb2274467e932f2ac8f15a9372bbe32aa4fdfeb1 (diff)
Update to upstream 1.11.0~rc2
[git-debrebase anchor: new upstream 1.11.0~rc2, merge]
Diffstat (limited to 'subversion/tests/cmdline')
-rwxr-xr-xsubversion/tests/cmdline/authz_tests.py34
-rwxr-xr-xsubversion/tests/cmdline/basic_tests.py71
-rwxr-xr-xsubversion/tests/cmdline/blame_tests.py3
-rwxr-xr-xsubversion/tests/cmdline/commit_tests.py3
-rwxr-xr-xsubversion/tests/cmdline/copy_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/dav-mirror-autocheck.sh55
-rwxr-xr-xsubversion/tests/cmdline/dav_tests.py82
-rwxr-xr-xsubversion/tests/cmdline/davautocheck.sh20
-rwxr-xr-xsubversion/tests/cmdline/depth_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/diff_tests.py112
-rwxr-xr-xsubversion/tests/cmdline/entries_tests.py9
-rwxr-xr-xsubversion/tests/cmdline/export_tests.py14
-rwxr-xr-xsubversion/tests/cmdline/externals_tests.py24
-rw-r--r--subversion/tests/cmdline/getopt_tests_data/svn--help_stdout11
-rw-r--r--subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout4
-rw-r--r--subversion/tests/cmdline/getopt_tests_data/svn_help_stdout11
-rwxr-xr-xsubversion/tests/cmdline/iprop_authz_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/lock_tests.py4
-rwxr-xr-xsubversion/tests/cmdline/log_tests.py8
-rwxr-xr-xsubversion/tests/cmdline/merge_authz_tests.py4
-rwxr-xr-xsubversion/tests/cmdline/merge_automatic_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/merge_reintegrate_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/merge_tests.py32
-rwxr-xr-xsubversion/tests/cmdline/merge_tree_conflict_tests.py4
-rwxr-xr-xsubversion/tests/cmdline/mergeinfo_tests.py2
-rwxr-xr-x[-rw-r--r--]subversion/tests/cmdline/mod_dav_svn_tests.py0
-rwxr-xr-xsubversion/tests/cmdline/move_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/patch_tests.py231
-rwxr-xr-xsubversion/tests/cmdline/prop_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/revert_tests.py9
-rwxr-xr-xsubversion/tests/cmdline/shelf_tests.py995
-rwxr-xr-xsubversion/tests/cmdline/shelve_tests.py176
-rwxr-xr-xsubversion/tests/cmdline/special_tests.py5
-rwxr-xr-xsubversion/tests/cmdline/stat_tests.py3
-rwxr-xr-xsubversion/tests/cmdline/svnadmin_tests.py135
-rwxr-xr-xsubversion/tests/cmdline/svnauthz_tests.py10
-rwxr-xr-xsubversion/tests/cmdline/svndumpfilter_tests.py8
-rwxr-xr-xsubversion/tests/cmdline/svnfsfs_tests.py3
-rwxr-xr-xsubversion/tests/cmdline/svnmover_tests.py6
-rwxr-xr-xsubversion/tests/cmdline/svnmucc_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/svnrdump_tests.py6
-rwxr-xr-xsubversion/tests/cmdline/svnsync_authz_tests.py2
-rwxr-xr-xsubversion/tests/cmdline/svnsync_tests.py2
-rw-r--r--subversion/tests/cmdline/svntest/actions.py5
-rw-r--r--subversion/tests/cmdline/svntest/main.py36
-rw-r--r--[-rwxr-xr-x]subversion/tests/cmdline/svntest/mergetrees.py0
-rw-r--r--subversion/tests/cmdline/svntest/sandbox.py24
-rw-r--r--subversion/tests/cmdline/svntest/tree.py15
-rw-r--r--subversion/tests/cmdline/svntest/verify.py103
-rw-r--r--subversion/tests/cmdline/svntest/wc.py3
-rwxr-xr-xsubversion/tests/cmdline/svnversion_tests.py18
-rwxr-xr-xsubversion/tests/cmdline/trans_tests.py6
-rwxr-xr-xsubversion/tests/cmdline/tree_conflict_tests.py49
-rwxr-xr-xsubversion/tests/cmdline/update_tests.py3
-rwxr-xr-xsubversion/tests/cmdline/upgrade_tests.py6
55 files changed, 1991 insertions, 391 deletions
diff --git a/subversion/tests/cmdline/authz_tests.py b/subversion/tests/cmdline/authz_tests.py
index 8878418..e818c65 100755
--- a/subversion/tests/cmdline/authz_tests.py
+++ b/subversion/tests/cmdline/authz_tests.py
@@ -168,7 +168,7 @@ def authz_read_access(sbox):
fws_url = B_url + '/folder with spaces'
fws_empty_folder_url = fws_url + '/empty folder'
- if sbox.repo_url.startswith("http"):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: E170001: Authorization failed.*"
@@ -280,7 +280,7 @@ def authz_write_access(sbox):
write_restrictive_svnserve_conf(sbox.repo_dir)
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: E220004: Access denied.*"
@@ -367,7 +367,7 @@ def authz_checkout_test(sbox):
# 1st part: disable all read access, checkout should fail
# write an authz file with *= on /
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: E170001: Authorization failed.*"
@@ -502,7 +502,7 @@ def authz_log_and_tracing_test(sbox):
write_restrictive_svnserve_conf(sbox.repo_dir)
# write an authz file with *=rw on /
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: E170001: Authorization failed.*"
@@ -533,7 +533,7 @@ def authz_log_and_tracing_test(sbox):
# now disable read access on the first version of rho, keep the copy in
# /A/D readable.
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: E170001: Authorization failed.*"
@@ -551,7 +551,7 @@ def authz_log_and_tracing_test(sbox):
'log', '-r', '2', '--limit', '1',
wc_dir)
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err2 = expected_err
else:
expected_err2 = ".*svn: E220001: ((Unreadable path encountered; " \
@@ -593,7 +593,7 @@ def authz_log_and_tracing_test(sbox):
svntest.actions.run_and_verify_svn(None, expected_err2,
'cat', '-r', '2', D_url+'/rho')
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err2 = expected_err
else:
expected_err2 = ".*svn: E220001: Unreadable path encountered; access denied.*"
@@ -624,7 +624,7 @@ def authz_aliases(sbox):
write_restrictive_svnserve_conf(sbox.repo_dir)
- if sbox.repo_url.startswith("http"):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: E170001: Authorization failed.*"
@@ -669,9 +669,9 @@ def authz_validate(sbox):
write_authz_file(sbox, { "/" : "* = r",
"/A/B" : "@undefined_group = rw" })
- if sbox.repo_url.startswith("http"):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
- elif sbox.repo_url.startswith("svn"):
+ elif svntest.main.is_ra_type_svn():
expected_err = ".*Invalid authz configuration"
else:
expected_err = ".*@undefined_group.*"
@@ -688,9 +688,9 @@ devs1 = @admins, dev1
devs2 = @admins, dev2
devs = @devs1, dev3, dev4""" })
- if sbox.repo_url.startswith("http"):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
- elif sbox.repo_url.startswith("svn"):
+ elif svntest.main.is_ra_type_svn():
expected_err = ".*Invalid authz configuration"
else:
expected_err = ".*Circular dependency.*"
@@ -726,7 +726,7 @@ def authz_locking(sbox):
write_authz_file(sbox, {"/": "", "/A": "jrandom = rw"})
write_restrictive_svnserve_conf(sbox.repo_dir)
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: warning: W170001: Authorization failed.*"
@@ -781,7 +781,7 @@ def authz_locking(sbox):
svntest.actions.run_and_verify_info([{'Lock Token' : None}],
sbox.ospath('A/mu'))
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: warning: W160039: .*([Aa]uth.*perf|[Ff]orbidden).*"
else:
expected_err = ".*svn: warning: W170001: Authorization failed.*"
@@ -863,7 +863,7 @@ def authz_svnserve_anon_access_read(sbox):
# is not really a branch (it's the same URL), but we only care about
# authz here, not the semantics of the merge. (Merges had been
# failing in authz, for the reasons summarized in
- # http://subversion.tigris.org/issues/show_bug.cgi?id=2712#desc13.)
+ # https://issues.apache.org/jira/browse/SVN-2712#desc13.)
svntest.actions.run_and_verify_svn(None, [],
'merge', '-c', '2',
B_url, B_path)
@@ -981,7 +981,7 @@ def multiple_matches(sbox):
sbox.build(create_wc = False)
root_url = sbox.repo_url
write_restrictive_svnserve_conf(sbox.repo_dir)
- if sbox.repo_url.startswith("http"):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
else:
expected_err = ".*svn: E170001: Authorization failed.*"
@@ -1137,7 +1137,7 @@ def case_sensitive_authz(sbox):
# error messages
expected_error_for_commit = ".*Commit failed.*"
- if sbox.repo_url.startswith("http"):
+ if svntest.main.is_ra_type_dav():
expected_error_for_cat = ".*[Ff]orbidden.*"
else:
expected_error_for_cat = ".*svn: E170001: Authorization failed.*"
diff --git a/subversion/tests/cmdline/basic_tests.py b/subversion/tests/cmdline/basic_tests.py
index 4b0b8d5..581a23b 100755
--- a/subversion/tests/cmdline/basic_tests.py
+++ b/subversion/tests/cmdline/basic_tests.py
@@ -3024,16 +3024,19 @@ def peg_rev_on_non_existent_wc_path(sbox):
# setup some history
sbox.simple_move('A', 'A2')
sbox.simple_move('A2/mu', 'A2/mu2')
- open(sbox.ospath('A2/mu2'), 'w').write('r2\n')
+ with open(sbox.ospath('A2/mu2'), 'w') as f:
+ f.write('r2\n')
sbox.simple_commit(message='r2')
#
sbox.simple_move('A2/mu2', 'A2/mu3')
sbox.simple_move('A2', 'A3')
- open(sbox.ospath('A3/mu3'), 'w').write('r3\n')
+ with open(sbox.ospath('A3/mu3'), 'w') as f:
+ f.write('r3\n')
sbox.simple_commit(message='r3')
#
sbox.simple_move('A3/mu3', 'A3/mu4')
- open(sbox.ospath('A3/mu4'), 'w').write('r4\n')
+ with open(sbox.ospath('A3/mu4'), 'w') as f:
+ f.write('r4\n')
sbox.simple_move('A3', 'A4')
sbox.simple_commit(message='r4')
@@ -3121,24 +3124,27 @@ def filtered_ls(sbox):
sbox.build(read_only=True)
path = sbox.repo_url + "/A/D"
- # check plain info
- expected = [ "H/omega\n",
- "gamma\n" ]
+ # with and without externals, because without externals on a 1.10+ server
+ # a server-side code path is used
+ for extra_opts in [ [], ['--include-externals'] ]:
- exit_code, output, error = svntest.actions.run_and_verify_svn(
- expected, [], 'ls', path, '--depth=infinity', '--search=*a')
+ expected = [ "H/omega\n",
+ "gamma\n" ]
- # check case-insensitivity
- exit_code, output, error = svntest.actions.run_and_verify_svn(
- expected, [], 'ls', path, '--depth=infinity', '--search=*A')
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ expected, [], 'ls', path, '--depth=infinity', '--search=*a', *extra_opts)
- expected = [ "H/\n" ]
- exit_code, output, error = svntest.actions.run_and_verify_svn(
- expected, [], 'ls', path, '--depth=infinity', '--search=h')
+ # check case-insensitivity
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ expected, [], 'ls', path, '--depth=infinity', '--search=*A', *extra_opts)
- # we don't match full paths
- exit_code, output, error = svntest.actions.run_and_verify_svn(
- [], [], 'ls', path, '--depth=infinity', '--search=*/*')
+ expected = [ "H/\n" ]
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ expected, [], 'ls', path, '--depth=infinity', '--search=h', *extra_opts)
+
+ # we don't match full paths
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ [], [], 'ls', path, '--depth=infinity', '--search=*/*', *extra_opts)
@Issue(4700)
@XFail(svntest.main.is_fs_type_fsx)
@@ -3197,6 +3203,36 @@ def null_prop_update_last_changed_revision(sbox):
'info', sbox.path('iota'),
'--show-item', 'last-changed-revision')
+@Skip(svntest.main.is_os_windows)
+def filtered_ls_top_level_path(sbox):
+ "filtered 'svn ls' top level path"
+
+ sbox.build(read_only=True, create_wc=False)
+ d_path = sbox.repo_url + "/A/B"
+ f_path = sbox.repo_url + "/A/B/lambda"
+
+ d_expected = svntest.verify.RegexListOutput([
+ r".* \./", # expect '*B*' to match its name which is 'B'
+ r".* E/beta",
+ r".* lambda" ])
+ f_expected = [ "lambda\n" ]
+
+ # with and without externals, because without externals on a 1.10+ server
+ # a server-side code path is used
+ for extra_opts in [ [], ['--include-externals'] ]:
+
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ d_expected, [], 'ls', '-v', d_path, '-R', '--search=*B*', *extra_opts)
+
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ f_expected, [], 'ls', f_path, '--search=lambda', *extra_opts)
+
+ # we don't match full paths, even for the top level path
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ [], [], 'ls', '-v', d_path, '-R', '--search=*/*', *extra_opts)
+ exit_code, output, error = svntest.actions.run_and_verify_svn(
+ [], [], 'ls', f_path, '--search=*/*', *extra_opts)
+
########################################################################
# Run the tests
@@ -3271,6 +3307,7 @@ test_list = [ None,
filtered_ls,
null_update_last_changed_revision,
null_prop_update_last_changed_revision,
+ filtered_ls_top_level_path,
]
if __name__ == '__main__':
diff --git a/subversion/tests/cmdline/blame_tests.py b/subversion/tests/cmdline/blame_tests.py
index f824d25..8620dd4 100755
--- a/subversion/tests/cmdline/blame_tests.py
+++ b/subversion/tests/cmdline/blame_tests.py
@@ -958,7 +958,8 @@ def blame_youngest_to_oldest(sbox):
sbox.simple_commit() #r3
# Delete a line.
- open(iota_moved, 'w').write(line)
+ with open(iota_moved, 'w') as f:
+ f.write(line)
sbox.simple_commit() #r4
expected_output = [
diff --git a/subversion/tests/cmdline/commit_tests.py b/subversion/tests/cmdline/commit_tests.py
index 4f4a6f9..9bdb305 100755
--- a/subversion/tests/cmdline/commit_tests.py
+++ b/subversion/tests/cmdline/commit_tests.py
@@ -2823,7 +2823,8 @@ def commit_add_subadd(sbox):
# prepare targets file
targets = "A/D A/D/H A/D/H/chi A/D/H/omega A/D/H/psi".split()
- open(targets_file, 'w').write("\n".join(targets))
+ with open(targets_file, 'w') as f:
+ f.write("\n".join(targets))
# r2: rm A/D
sbox.simple_rm('A/D')
diff --git a/subversion/tests/cmdline/copy_tests.py b/subversion/tests/cmdline/copy_tests.py
index 3bb8599..c87f36f 100755
--- a/subversion/tests/cmdline/copy_tests.py
+++ b/subversion/tests/cmdline/copy_tests.py
@@ -4333,7 +4333,7 @@ def copy_added_dir_with_copy(sbox):
def copy_broken_symlink(sbox):
"""copy broken symlink"""
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3303. ##
+ ## See https://issues.apache.org/jira/browse/SVN-3303. ##
sbox.build()
wc_dir = sbox.wc_dir
diff --git a/subversion/tests/cmdline/dav-mirror-autocheck.sh b/subversion/tests/cmdline/dav-mirror-autocheck.sh
index 298a8ba..7bc5e11 100755
--- a/subversion/tests/cmdline/dav-mirror-autocheck.sh
+++ b/subversion/tests/cmdline/dav-mirror-autocheck.sh
@@ -31,7 +31,7 @@
#
# The set of changes sent through the system is currently
# just the test case for issue 2939, using svnmucc
-# http://subversion.tigris.org/issues/show_bug.cgi?id=2939
+# https://issues.apache.org/jira/browse/SVN-2939
# But of course, any svn traffic liable to break over
# mirroring would be a good addition.
#
@@ -100,6 +100,7 @@ function setup_config() {
say "setting up config: " $1
cat > "$1" <<__EOF__
+$LOAD_MOD_MPM
$LOAD_MOD_LOG_CONFIG
$LOAD_MOD_MIME
$LOAD_MOD_UNIXD
@@ -114,9 +115,30 @@ $LOAD_MOD_AUTHZ_CORE
$LOAD_MOD_AUTHZ_USER
$LOAD_MOD_AUTHZ_HOST
+__EOF__
+
+if "$HTTPD" -v | grep '/2\.[012]' >/dev/null; then
+ cat >> "$1" <<__EOF__
LockFile lock
User $(id -un)
Group $(id -gn)
+__EOF__
+else
+HTTPD_LOCK="$HTTPD_ROOT/lock"
+mkdir "$HTTPD_LOCK" \
+ || fail "couldn't create lock directory '$HTTPD_LOCK'"
+ cat >> "$1" <<__EOF__
+# worker and prefork MUST have a mpm-accept lockfile in 2.3.0+
+<IfModule worker.c>
+ Mutex "file:$HTTPD_LOCK" mpm-accept
+</IfModule>
+<IfModule prefork.c>
+ Mutex "file:$HTTPD_LOCK" mpm-accept
+</IfModule>
+__EOF__
+fi
+
+cat >> "$1" <<__EOF__
Listen ${TEST_PORT}
ServerName localhost
PidFile "${HTTPD_ROOT}/pid"
@@ -133,6 +155,9 @@ MaxRequestsPerChild 0
<IfModule worker.c>
ThreadsPerChild 8
</IfModule>
+<IfModule event.c>
+ ThreadsPerChild 8
+</IfModule>
MaxClients 16
HostNameLookups Off
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" format
@@ -202,6 +227,12 @@ function usage() {
SCRIPT=$(basename $0)
+NO_TESTS=
+if [ "x$1" = 'x--no-tests' ]; then
+ NO_TESTS=1
+ shift
+fi
+
if [ $# -ne 1 ] ; then
usage
fi
@@ -249,7 +280,7 @@ HTPASSWD=$(get_prog_name htpasswd htpasswd2) \
SVN=$ABS_BUILDDIR/subversion/svn/svn
SVNADMIN=$ABS_BUILDDIR/subversion/svnadmin/svnadmin
SVNSYNC=$ABS_BUILDDIR/subversion/svnsync/svnsync
-SVNMUCC=${SVNMUCC:-$ABS_BUILDDIR/tools/client-side/svnmucc/svnmucc}
+SVNMUCC=$ABS_BUILDDIR/subversion/svnmucc/svnmucc
SVNLOOK=$ABS_BUILDDIR/subversion/svnlook/svnlook
[ -x $HTTPD ] || fail "HTTPD '$HTTPD' not executable"
@@ -259,9 +290,7 @@ SVNLOOK=$ABS_BUILDDIR/subversion/svnlook/svnlook
[ -x $SVNADMIN ] || fail "SVNADMIN $SVNADMIN not built"
[ -x $SVNSYNC ] || fail "SVNSYNC $SVNSYNC not built"
[ -x $SVNLOOK ] || fail "SVNLOOK $SVNLOOK not built"
-[ -x $SVNMUCC ] \
- || fail SVNMUCC $SVNMUCC executable not built, needed for test. \
- \'cd $ABS_BUILDDIR\; make svnmucc\' to fix.
+[ -x $SVNMUCC ] || fail "SVNMUCC $SVNMUCC not built"
say HTTPD: $HTTPD
say SVN: $SVN
@@ -309,6 +338,10 @@ LOAD_MOD_AUTHN_FILE="$(get_loadmodule_config mod_authn_file)" \
LOAD_MOD_AUTHZ_USER="$(get_loadmodule_config mod_authz_user)" \
|| fail "Authz_User module not found."
}
+if [ ${APACHE_MPM:+set} ]; then
+ LOAD_MOD_MPM=$(get_loadmodule_config mod_mpm_$APACHE_MPM) \
+ || fail "MPM module not found"
+fi
if [ ${MODULE_PATH:+set} ]; then
MOD_DAV_SVN="$MODULE_PATH/mod_dav_svn.so"
@@ -365,7 +398,9 @@ $SVNADMIN create "$SLAVE_REPOS" || fail "create slave repos failed"
$SVNADMIN dump "$MASTER_REPOS" | $SVNADMIN load "$SLAVE_REPOS" \
|| fail "duplicate repositories failed"
# make sure uuid's match
-[ `cat "$SLAVE_REPOS/db/uuid"` = `cat "$MASTER_REPOS/db/uuid"` ] \
+read MASTER_UUID < "$MASTER_REPOS/db/uuid"
+read SLAVE_UUID < "$SLAVE_REPOS/db/uuid"
+[ "$SLAVE_UUID" = "$MASTER_UUID" ] \
|| fail "master/slave uuid mismatch"
# setup hooks:
# slave allows revprop changes
@@ -397,12 +432,18 @@ $SVNSYNC initialize --non-interactive "$SYNC_URL" "$MASTER_URL" \
--username=svnsync --password=svnsync \
|| fail "svnsync initialize failed"
+if [ $NO_TESTS ]; then
+ echo "MASTER_URL=$MASTER_URL"
+ echo "SLAVE_URL=$SLAVE_URL"
+ exit
+fi
+
# OK, let's start testing! Commit changes to slave, expect
# them to proxy through to the master, and then
# svnsync back to the slave
#
# reproducible test case from:
-# http://subversion.tigris.org/issues/show_bug.cgi?id=2939
+# https://issues.apache.org/jira/browse/SVN-2939
#
BASE_URL="$SLAVE_URL"
say running svnmucc test to $BASE_URL
diff --git a/subversion/tests/cmdline/dav_tests.py b/subversion/tests/cmdline/dav_tests.py
new file mode 100755
index 0000000..a99cdf5
--- /dev/null
+++ b/subversion/tests/cmdline/dav_tests.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+#
+# dav_tests.py: testing connections to HTTP and DAV servers.
+#
+# Subversion is a tool for revision control.
+# See http://subversion.apache.org for more information.
+#
+# ====================================================================
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+######################################################################
+
+# General modules
+import os, re
+
+# Our testing module
+import svntest
+
+# (abbreviation)
+Skip = svntest.testcase.Skip_deco
+SkipUnless = svntest.testcase.SkipUnless_deco
+XFail = svntest.testcase.XFail_deco
+Issues = svntest.testcase.Issues_deco
+Issue = svntest.testcase.Issue_deco
+Wimp = svntest.testcase.Wimp_deco
+Item = svntest.wc.StateItem
+
+
+######################################################################
+# Tests
+#
+# Each test must return on success or raise on failure.
+
+
+#----------------------------------------------------------------------
+
+@SkipUnless(svntest.main.is_ra_type_dav)
+def connect_plain_http_server(sbox):
+ "connect to a non-DAV HTTP server"
+ expected_errors = svntest.verify.RegexListOutput([
+ "^svn: E170013: Unable to connect to a repository at URL '[^']+'",
+ "^svn: E175003: The server at '[^']+' does not support the HTTP/DAV protocol"
+ ], False)
+ svntest.actions.run_and_verify_svn([], expected_errors,
+ 'info', svntest.main.non_dav_root_url)
+
+@SkipUnless(svntest.main.is_ra_type_dav)
+def connect_other_dav_server(sbox):
+ "connect to a DAV server which is not an SVN server"
+ svntest.actions.run_and_verify_svn([], svntest.verify.AnyOutput,
+ 'info', svntest.main.other_dav_root_url)
+
+########################################################################
+# Run the tests
+
+
+# list all tests here, starting with None:
+test_list = [ None,
+ connect_plain_http_server,
+ connect_other_dav_server,
+ ]
+
+if __name__ == '__main__':
+ svntest.main.run_tests(test_list)
+ # NOTREACHED
+
+
+### End of file.
diff --git a/subversion/tests/cmdline/davautocheck.sh b/subversion/tests/cmdline/davautocheck.sh
index 064feb1..7170b77 100755
--- a/subversion/tests/cmdline/davautocheck.sh
+++ b/subversion/tests/cmdline/davautocheck.sh
@@ -281,6 +281,9 @@ say "Using '$HTPASSWD'..."
LOAD_MOD_DAV=$(get_loadmodule_config mod_dav) \
|| fail "DAV module not found"
+LOAD_MOD_DAV_FS=$(get_loadmodule_config mod_dav_fs) \
+ || fail "Filesystem DAV module not found"
+
LOAD_MOD_LOG_CONFIG=$(get_loadmodule_config mod_log_config) \
|| fail "log_config module not found"
@@ -447,6 +450,7 @@ $LOAD_MOD_MIME
$LOAD_MOD_ALIAS
$LOAD_MOD_UNIXD
$LOAD_MOD_DAV
+$LOAD_MOD_DAV_FS
LoadModule dav_svn_module "$MOD_DAV_SVN"
$LOAD_MOD_AUTH
$LOAD_MOD_AUTHN_CORE
@@ -482,6 +486,13 @@ mkdir "$HTTPD_LOCK" \
__EOF__
fi
+HTTPD_DAV="$HTTPD_ROOT/dav"
+mkdir "$HTTPD_DAV" \
+ || fail "couldn't create DAV lock directory '$HTTPD_DAV'"
+cat >> "$HTTPD_CFG" <<__EOF__
+DavLockDB "$HTTPD_DAV/lock.db"
+__EOF__
+
if [ ${USE_SSL:+set} ]; then
cat >> "$HTTPD_CFG" <<__EOF__
SSLEngine on
@@ -525,6 +536,15 @@ CustomLog "$HTTPD_ROOT/ops" "%t %u %{SVN-REPOS-NAME}e %{SVN-ACTION}e"
#Require all granted
</Directory>
+Alias /nodavroot $ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/nodavroot
+<Directory $ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/nodavroot>
+</Directory>
+
+Alias /fsdavroot $ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/fsdavroot
+<Directory $ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/fsdavroot>
+ DAV filesystem
+</Directory>
+
<Location /svn-test-work/repositories>
__EOF__
location_common() {
diff --git a/subversion/tests/cmdline/depth_tests.py b/subversion/tests/cmdline/depth_tests.py
index 1277594..18ce379 100755
--- a/subversion/tests/cmdline/depth_tests.py
+++ b/subversion/tests/cmdline/depth_tests.py
@@ -1073,7 +1073,7 @@ def commit_depth_immediates(sbox):
# Message-ID: <46968831.2070906@collab.net>
# Date: Thu, 12 Jul 2007 15:59:45 -0400
#
- # See also http://subversion.tigris.org/issues/show_bug.cgi?id=2882.
+ # See also https://issues.apache.org/jira/browse/SVN-2882.
#
# Outline of the test:
# ====================
diff --git a/subversion/tests/cmdline/diff_tests.py b/subversion/tests/cmdline/diff_tests.py
index 905bce3..63caa24 100755
--- a/subversion/tests/cmdline/diff_tests.py
+++ b/subversion/tests/cmdline/diff_tests.py
@@ -36,7 +36,6 @@ from svntest import err, wc
from prop_tests import binary_mime_type_on_text_file_warning
from svntest.verify import make_diff_header, make_no_diff_deleted_header, \
- make_diff_header, make_no_diff_deleted_header, \
make_git_diff_header, make_diff_prop_header, \
make_diff_prop_val, make_diff_prop_deleted, \
make_diff_prop_added, make_diff_prop_modified
@@ -2712,7 +2711,7 @@ def diff_ignore_eolstyle(sbox):
" Bb\n",
"-Cc\n",
"+Cc\n",
- "\ No newline at end of file\n" ]
+ "\\ No newline at end of file\n" ]
svntest.actions.run_and_verify_svn(expected_output, [],
'diff', '-x', '--ignore-eol-style',
@@ -3855,7 +3854,7 @@ def diff_arbitrary_files_and_dirs(sbox):
sbox.build()
wc_dir = sbox.wc_dir
- # diff iota with A/mu
+ # diff files (iota with A/mu)
expected_output = make_diff_header("iota", "working copy", "working copy",
"iota", "A/mu") + [
"@@ -1 +1 @@\n",
@@ -3866,7 +3865,11 @@ def diff_arbitrary_files_and_dirs(sbox):
'diff', '--old', sbox.ospath('iota'),
'--new', sbox.ospath('A/mu'))
- # diff A/B/E with A/D
+ # diff dirs (A/B/E with A/D)
+ # .../gamma is to show as replaced; .../beta is to show as modified
+ sbox.simple_mkdir('A/B/E/gamma')
+ sbox.simple_propset('p', 'v', 'A/B/E/gamma')
+ sbox.simple_add_text("This is a different beta file.\n", 'A/D/beta')
expected_output = make_diff_header("G/pi", "nonexistent", "working copy",
"B/E", "D") + [
"@@ -0,0 +1 @@\n",
@@ -3896,11 +3899,16 @@ def diff_arbitrary_files_and_dirs(sbox):
"@@ -1 +0,0 @@\n",
"-This is the file 'alpha'.\n"
] + make_diff_header("beta", "working copy",
- "nonexistent", "B/E", "D") + [
- "@@ -1 +0,0 @@\n",
- "-This is the file 'beta'.\n"
- ] + make_diff_header("gamma", "nonexistent",
"working copy", "B/E", "D") + [
+ "@@ -1 +1 @@\n",
+ "-This is the file 'beta'.\n",
+ "+This is a different beta file.\n"
+ ] + make_diff_header("gamma", "working copy",
+ "nonexistent", "B/E", "D") \
+ + make_diff_prop_header("gamma") \
+ + make_diff_prop_deleted("p", "v") \
+ + make_diff_header("gamma", "nonexistent",
+ "working copy", "B/E", "D") + [
"@@ -0,0 +1 @@\n",
"+This is the file 'gamma'.\n"
]
@@ -5160,6 +5168,90 @@ def diff_unversioned_files_git(sbox):
'--old', sbox.ospath('foo'),
'--new', sbox.ospath('A/bar'))
+# Summary diff with a repository source side and a local copy target side.
+# This particular combination crashed in 1.10.0 and earlier releases.
+def diff_summary_repo_wc_local_copy(sbox):
+ "diff summary repo wc local copy"
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ sbox.simple_copy('iota', 'iota2')
+ sbox.simple_append('iota2', 'hello\n')
+ expected_diff = svntest.wc.State(wc_dir, {
+ 'iota': Item(status='M '),
+ })
+ svntest.actions.run_and_verify_diff_summarize(
+ expected_diff,
+ '--old=' + sbox.ospath('iota') + '@HEAD',
+ '--new=' + sbox.ospath('iota2'))
+
+# Summary diff with a repository source side and a local copy target side.
+# Svn reported the unmodified copy as modified in 1.10.0 and earlier releases.
+@XFail()
+def diff_summary_repo_wc_local_copy_unmodified(sbox):
+ "diff summary repo wc local copy unmodified"
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ sbox.simple_copy('iota', 'iota2')
+ expected_diff = svntest.wc.State(wc_dir, {
+ })
+ svntest.actions.run_and_verify_diff_summarize(
+ expected_diff,
+ '--old=' + sbox.ospath('iota') + '@HEAD',
+ '--new=' + sbox.ospath('iota2'))
+
+# Fails with "Can't open file '.../iota': Too many levels of symbolic links"
+# on Unix.
+@XFail()
+@Skip(svntest.main.is_os_windows)
+def diff_file_replaced_by_symlink(sbox):
+ "diff base vs working: symlink replaces a file"
+ sbox.build(read_only=True)
+ wc_dir = sbox.wc_dir
+
+ iota_path = sbox.ospath('iota')
+ os.remove(iota_path)
+
+ # create a symlink pointing to itself
+ # alternatively it could point to a non-existing path
+ sbox.simple_symlink('iota', 'iota')
+
+ # TODO: add a full expected output
+ expected_output = svntest.verify.AnyOutput
+ svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir)
+
+# Test 'svn diff --git' with a copy.
+#
+# When this diff is rooted at a path below the repository root directory,
+# it errored out while printing the git diff header, due to confusion of
+# diff-relative and repository-relative copyfrom paths.
+@XFail()
+def diff_git_format_copy(sbox):
+ "diff git format copy"
+ sbox.build(create_wc=False)
+ svntest.actions.run_and_verify_svn(None, [], 'checkout',
+ sbox.repo_url + '/A/B',
+ sbox.wc_dir)
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+ sbox.simple_copy('E/alpha', 'alpha_copied')
+ sbox.simple_append('alpha_copied', "This is a copy of 'alpha'.\n")
+
+ expected_output = \
+ make_git_diff_header('alpha_copied', 'A/B/alpha_copied',
+ "revision 1", "working copy",
+ copyfrom_path="A/B/E/alpha",
+ copyfrom_rev='1', cp=True,
+ text_changes=True) + [
+ "@@ -1 +1,2 @@\n",
+ " This is the file 'alpha'.\n",
+ "+This is a copy of 'alpha'.\n",
+ ]
+
+ svntest.actions.run_and_verify_svn(expected_output, [], 'diff',
+ '--git', '.')
########################################################################
#Run the tests
@@ -5257,6 +5349,10 @@ test_list = [ None,
diff_symlinks,
diff_peg_resolve,
diff_unversioned_files_git,
+ diff_summary_repo_wc_local_copy,
+ diff_summary_repo_wc_local_copy_unmodified,
+ diff_file_replaced_by_symlink,
+ diff_git_format_copy,
]
if __name__ == '__main__':
diff --git a/subversion/tests/cmdline/entries_tests.py b/subversion/tests/cmdline/entries_tests.py
index 0fcdc1a..78ba037 100755
--- a/subversion/tests/cmdline/entries_tests.py
+++ b/subversion/tests/cmdline/entries_tests.py
@@ -121,14 +121,17 @@ def basic_entries(sbox):
G_path, iota_path)
# Add a file over the DELETED 'alpha'. It should be schedule-add.
- open(alpha_path, 'w').write('New alpha contents\n')
+ with open(alpha_path, 'w') as f:
+ f.write('New alpha contents\n')
# Delete 'beta', then add a file over it. Should be schedule-replace.
svntest.actions.run_and_verify_svn(None, [], 'rm', beta_path)
- open(beta_path, 'w').write('New beta contents\n')
+ with open(beta_path, 'w') as f:
+ f.write('New beta contents\n')
# Plain old add. Should have revision == 0.
- open(added_path, 'w').write('Added file contents\n')
+ with open(added_path, 'w') as f:
+ f.write('Added file contents\n')
svntest.actions.run_and_verify_svn(None, [], 'add',
alpha_path, beta_path, added_path)
diff --git a/subversion/tests/cmdline/export_tests.py b/subversion/tests/cmdline/export_tests.py
index a8ac7b8..c524ff3 100755
--- a/subversion/tests/cmdline/export_tests.py
+++ b/subversion/tests/cmdline/export_tests.py
@@ -610,7 +610,8 @@ def export_file_overwrite_fails(sbox):
os.mkdir(tmpdir)
# Run it for source local
- open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+ with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+ f.write(not_iota_contents)
svntest.actions.run_and_verify_svn([], '.*exist.*',
'export', iota_path, tmpdir)
@@ -621,7 +622,8 @@ def export_file_overwrite_fails(sbox):
svntest.actions.verify_disk(tmpdir, expected_disk)
# Run it for source URL
- open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+ with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+ f.write(not_iota_contents)
svntest.actions.run_and_verify_svn([], '.*exist.*',
'export', iota_url, tmpdir)
@@ -721,7 +723,7 @@ def export_working_copy_ignoring_keyword_translation(sbox):
def export_with_url_unsafe_characters(sbox):
"export file with URL unsafe characters"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3683 ##
+ ## See https://issues.apache.org/jira/browse/SVN-3683 ##
sbox.build()
wc_dir = sbox.wc_dir
@@ -904,14 +906,16 @@ def export_file_overwrite_with_force(sbox):
})
# Run it for WC export
- open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+ with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+ f.write(not_iota_contents)
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput,
[], 'export', '--force',
iota_path, tmpdir)
svntest.actions.verify_disk(tmpdir, expected_disk)
# Run it for URL export
- open(os.path.join(tmpdir, 'iota'), 'w').write(not_iota_contents)
+ with open(os.path.join(tmpdir, 'iota'), 'w') as f:
+ f.write(not_iota_contents)
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput,
[], 'export', '--force',
iota_url, tmpdir)
diff --git a/subversion/tests/cmdline/externals_tests.py b/subversion/tests/cmdline/externals_tests.py
index c0ac029..ba1320c 100755
--- a/subversion/tests/cmdline/externals_tests.py
+++ b/subversion/tests/cmdline/externals_tests.py
@@ -1146,7 +1146,7 @@ def external_into_path_with_spaces(sbox):
repo_url = sbox.repo_url
ext = '^/A/D "A/copy of D"\n' +\
- '^/A/D A/another\ copy\ of\ D'
+ '^/A/D A/another\\ copy\\ of\\ D'
change_external(wc_dir, ext)
expected_output = svntest.wc.State(wc_dir, {
@@ -2818,7 +2818,7 @@ def remap_file_external_with_prop_del(sbox):
# Now update to bring the new external down.
# This previously segfaulted as described in
- # http://subversion.tigris.org/issues/show_bug.cgi?id=4093#desc1
+ # https://issues.apache.org/jira/browse/SVN-4093#desc1
svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir)
@@ -3871,12 +3871,14 @@ def copy_pin_externals_whitespace_dir(sbox):
extdef = sbox.get_tempname('extdef')
info = sbox.get_tempname('info')
- open(extdef, 'w').write(
+ with open(extdef, 'w') as f:
+ f.write(
'"' + ss_path +'/deps/sqlite" ext/sqlite\n' +
'"^/deps/A P R" \'ext/A P R\'\n' +
- '^/deps/B\ D\ B\' ext/B\ D\ B\'\n' +
+ '^/deps/B\\ D\\ B\' ext/B\\ D\\ B\'\n' +
repo_url + '/deps/wors%23+t ext/wors#+t')
- open(info, 'w').write('info\n')
+ with open(info, 'w') as f:
+ f.write('info\n')
svntest.actions.run_and_verify_svnmucc(None, [], '-U', repo_url,
'mkdir', 'trunk',
@@ -4408,7 +4410,17 @@ def update_dir_external_exclude(sbox):
# Create an external in r2
sbox.simple_propset('svn:externals', '^/A/D/H X', 'A/B/E')
sbox.simple_commit()
- sbox.simple_update()
+
+ # Update to fetch externals
+ expected_output = svntest.wc.State(sbox.wc_dir, {
+ 'A/B/E/X/chi' : Item(status='A '),
+ 'A/B/E/X/omega' : Item(status='A '),
+ 'A/B/E/X/psi' : Item(status='A '),
+ })
+ svntest.actions.run_and_verify_update(sbox.wc_dir,
+ expected_output, None, None,
+ [], False,
+ sbox.ospath('A/B/E'))
# Now make A/B/E shallow by updating with "--set-depth exclude"
expected_output = svntest.wc.State(sbox.wc_dir, {
diff --git a/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout b/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
index 05f0aa8..ff73b51 100644
--- a/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
+++ b/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
@@ -47,9 +47,14 @@ Available subcommands:
unlock
update (up)
upgrade
- x-shelve (shelve)
- x-unshelve (unshelve)
- x-shelves (shelves)
+ x-shelf-diff
+ x-shelf-drop
+ x-shelf-list (x-shelves)
+ x-shelf-list-by-paths
+ x-shelf-log
+ x-shelf-save
+ x-shelve
+ x-unshelve
Subversion is a tool for version control.
For additional information, see http://subversion.apache.org/
diff --git a/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout b/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
index 5dddc70..2b81052 100644
--- a/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ b/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
@@ -84,6 +84,10 @@ usage: 1. log [PATH][@REV]
was created:
svn log --stop-on-copy --limit 1 -r0:HEAD ^/branches/foo
+ Show all log messages for commits between the tags ^/tags/2.0 and
+ ^/tags/3.0; assuming that tag 2.0 was created in revision 100:
+ svn log -rHEAD:100 ^/tags/3.0
+
If ^/trunk/foo.c was moved to ^/trunk/bar.c' in revision 22, 'svn log -v'
shows a deletion and a copy in its changed paths list, such as:
D /trunk/foo.c
diff --git a/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout b/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
index 05f0aa8..ff73b51 100644
--- a/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
+++ b/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
@@ -47,9 +47,14 @@ Available subcommands:
unlock
update (up)
upgrade
- x-shelve (shelve)
- x-unshelve (unshelve)
- x-shelves (shelves)
+ x-shelf-diff
+ x-shelf-drop
+ x-shelf-list (x-shelves)
+ x-shelf-list-by-paths
+ x-shelf-log
+ x-shelf-save
+ x-shelve
+ x-unshelve
Subversion is a tool for version control.
For additional information, see http://subversion.apache.org/
diff --git a/subversion/tests/cmdline/iprop_authz_tests.py b/subversion/tests/cmdline/iprop_authz_tests.py
index 835cd37..c2a9d10 100755
--- a/subversion/tests/cmdline/iprop_authz_tests.py
+++ b/subversion/tests/cmdline/iprop_authz_tests.py
@@ -105,7 +105,7 @@ def iprops_authz(sbox):
write_authz_file(sbox, {
"/" : svntest.main.wc_author + "=rw",
"/A/D/H/psi" : svntest.main.wc_author + "=",})
- if sbox.repo_url.startswith("http"):
+ if svntest.main.is_ra_type_dav():
expected_err = ".*[Ff]orbidden.*"
else:
expected_err = ".*svn: E170001: Authorization failed.*"
diff --git a/subversion/tests/cmdline/lock_tests.py b/subversion/tests/cmdline/lock_tests.py
index cd8e0d2..3e2952c 100755
--- a/subversion/tests/cmdline/lock_tests.py
+++ b/subversion/tests/cmdline/lock_tests.py
@@ -1571,7 +1571,8 @@ def cp_isnt_ro(sbox):
mu2_path = sbox.ospath('A/mu2')
mu3_path = sbox.ospath('A/mu3')
kappa_path = sbox.ospath('kappa')
- open(kappa_path, 'w').write("This is the file 'kappa'.\n")
+ with open(kappa_path, 'w') as f:
+ f.write("This is the file 'kappa'.\n")
## added file
sbox.simple_add('kappa')
@@ -2251,7 +2252,6 @@ def dav_lock_refresh(sbox):
if r.status != httplib.OK:
raise svntest.Failure('Lock refresh failed: %d %s' % (r.status, r.reason))
-@SkipUnless(svntest.main.is_ra_type_dav)
def delete_locked_file_with_percent(sbox):
"lock and delete a file called 'a %( ) .txt'"
diff --git a/subversion/tests/cmdline/log_tests.py b/subversion/tests/cmdline/log_tests.py
index 484103a..559dfb5 100755
--- a/subversion/tests/cmdline/log_tests.py
+++ b/subversion/tests/cmdline/log_tests.py
@@ -1592,7 +1592,7 @@ def merge_sensitive_log_added_mergeinfo_replaces_inherited(sbox):
# a merge results in added explicit mergeinfo on a path, but that
# path previously inherited mergeinfo (rather than had no explicit
# or inherited mergeinfo). See issue #3235, specifically
- # http://subversion.tigris.org/issues/show_bug.cgi?id=3235#desc8.
+ # https://issues.apache.org/jira/browse/SVN-3235#desc8.
sbox.build()
wc_dir = sbox.wc_dir
@@ -1752,7 +1752,7 @@ def merge_sensitive_log_added_mergeinfo_replaces_inherited(sbox):
def merge_sensitive_log_propmod_merge_inheriting_path(sbox):
"log -g and simple propmod to merge-inheriting path"
- # Issue #3285 (http://subversion.tigris.org/issues/show_bug.cgi?id=3285)
+ # Issue #3285 (https://issues.apache.org/jira/browse/SVN-3285)
sbox.build()
wc_dir = sbox.wc_dir
@@ -2166,13 +2166,13 @@ def log_diff(sbox):
+ [ "@@ -1 +1,2 @@\n",
" This is the file 'beta'.\n",
"+9\n",
- "\ No newline at end of file\n",
+ "\\ No newline at end of file\n",
]
]
r8diff = [ make_diff_header('A2/D/G/rho', 'nonexistent', 'revision 8')
+ [ "@@ -0,0 +1 @@\n",
"+88\n",
- "\ No newline at end of file\n",
+ "\\ No newline at end of file\n",
]
]
log_chain = parse_log_output(output, with_diffs=True)
diff --git a/subversion/tests/cmdline/merge_authz_tests.py b/subversion/tests/cmdline/merge_authz_tests.py
index 8e14089..b26e9c7 100755
--- a/subversion/tests/cmdline/merge_authz_tests.py
+++ b/subversion/tests/cmdline/merge_authz_tests.py
@@ -486,7 +486,7 @@ def mergeinfo_and_skipped_paths(sbox):
def merge_fails_if_subtree_is_deleted_on_src(sbox):
"merge fails if subtree is deleted on src"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2876. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2876. ##
# Create a WC
sbox.build()
@@ -613,7 +613,7 @@ def reintegrate_fails_if_no_root_access(sbox):
# should be able to reintegrate, regardless of what authorization
# they have to parents of the source and target.
#
- # See http://subversion.tigris.org/issues/show_bug.cgi?id=3242#desc78
+ # See https://issues.apache.org/jira/browse/SVN-3242#desc78
# Some paths we'll care about
wc_dir = sbox.wc_dir
diff --git a/subversion/tests/cmdline/merge_automatic_tests.py b/subversion/tests/cmdline/merge_automatic_tests.py
index f4bb231..fa00e04 100755
--- a/subversion/tests/cmdline/merge_automatic_tests.py
+++ b/subversion/tests/cmdline/merge_automatic_tests.py
@@ -1163,7 +1163,7 @@ def effective_sync_results_in_reintegrate(sbox):
# Now try an explicit --reintegrate merge from ^/branch to A.
# This should work because since the resolution of
- # http://subversion.tigris.org/issues/show_bug.cgi?id=3577
+ # https://issues.apache.org/jira/browse/SVN-3577
# if B is *effectively* synced with A, then B can be reintegrated
# to A.
sbox.simple_update()
diff --git a/subversion/tests/cmdline/merge_reintegrate_tests.py b/subversion/tests/cmdline/merge_reintegrate_tests.py
index 7a27373..1479400 100755
--- a/subversion/tests/cmdline/merge_reintegrate_tests.py
+++ b/subversion/tests/cmdline/merge_reintegrate_tests.py
@@ -1363,7 +1363,7 @@ def reintegrate_with_subtree_mergeinfo(sbox):
# how can any prop changes be merged to it? The answer is that
# the merge code does some quiet housekeeping, merging gamma_moved's
# inherited mergeinfo into its incoming mergeinfo, see
- # http://subversion.tigris.org/issues/show_bug.cgi?id=4309
+ # https://issues.apache.org/jira/browse/SVN-4309
# This test is not covering issue #4309 so we let the current
# behavior pass.
# r17 - B) Synch merge from A to A_COPY
diff --git a/subversion/tests/cmdline/merge_tests.py b/subversion/tests/cmdline/merge_tests.py
index a67dada..22b02dd 100755
--- a/subversion/tests/cmdline/merge_tests.py
+++ b/subversion/tests/cmdline/merge_tests.py
@@ -697,7 +697,7 @@ def simple_property_merges(sbox):
def merge_similar_unrelated_trees(sbox):
"merging similar trees ancestrally unrelated"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=1249. ##
+ ## See https://issues.apache.org/jira/browse/SVN-1249. ##
sbox.build()
wc_dir = sbox.wc_dir
@@ -3939,7 +3939,7 @@ def avoid_repeated_merge_on_subtree_with_merge_info(sbox):
check_props=True)
# Test for part of Issue #2821, see
- # http://subversion.tigris.org/issues/show_bug.cgi?id=2821#desc22
+ # https://issues.apache.org/jira/browse/SVN-2821#desc22
#
# Revert all local changes.
svntest.actions.run_and_verify_svn(None, [], 'revert', '-R', wc_dir)
@@ -6007,7 +6007,7 @@ def foreign_repos_does_not_update_mergeinfo(sbox):
def avoid_reflected_revs(sbox):
"avoid repeated merges for cyclic merging"
- # See <http://subversion.tigris.org/issues/show_bug.cgi?id=2897>.
+ # See <https://issues.apache.org/jira/browse/SVN-2897>.
#
# This test cherry-picks some changes (all of them, in fact) from the
# parent branch 'A' to the child branch 'A_COPY', and then tries to
@@ -8294,7 +8294,7 @@ def cherry_picking(sbox):
def propchange_of_subdir_raises_conflict(sbox):
"merge of propchange on subdir raises conflict"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2969. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2969. ##
# Create a WC with a single branch
sbox.build()
@@ -8515,7 +8515,7 @@ def reverse_merge_prop_add_on_child(sbox):
def merge_target_with_non_inheritable_mergeinfo(sbox):
"merge target with non inheritable mergeinfo"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2970. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2970. ##
# Create a WC with a single branch
sbox.build()
@@ -8547,7 +8547,7 @@ def merge_target_with_non_inheritable_mergeinfo(sbox):
expected_output = wc.State(A_COPY_B_path, {
'lambda' : Item(status='U '),
})
- # Issue #3642 http://subversion.tigris.org/issues/show_bug.cgi?id=3642
+ # Issue #3642 https://issues.apache.org/jira/browse/SVN-3642
#
# We don't expect A_COPY/B/F to have mergeinfo recorded on it because
# not only is it unaffected by the merge at depth immediates, it could
@@ -8820,7 +8820,7 @@ def merge_from_renamed_branch_fails_while_avoiding_repeat_merge(sbox):
#Merge r4 from A/RENAMED_C to A/C
#Merge r2:5 from A/RENAMED_C to A/C <-- This fails tracked via #3032.
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3032. ##
+ ## See https://issues.apache.org/jira/browse/SVN-3032. ##
# Create a WC with a single branch
sbox.build()
@@ -9250,7 +9250,7 @@ def new_subtrees_should_not_break_merge(sbox):
# so we expect only subtree merges on A_COPY/D, A_COPY_D_H, and
# A_COPY/D/H/nu. The fact that A/D/H/nu doesn't exist at r6 should not cause
# the merge to fail -- see
- # http://subversion.tigris.org/issues/show_bug.cgi?id=3067#desc7.
+ # https://issues.apache.org/jira/browse/SVN-3067#desc7.
expected_output = wc.State(A_COPY_path, {
'D/H/omega': Item(status='U '),
})
@@ -10495,7 +10495,7 @@ def reverse_merge_away_all_mergeinfo(sbox):
# Another test for issue #3067: 'subtrees with intersecting mergeinfo,
# that don't exist at the start of a merge range shouldn't break the
# merge'. Specifically see
-# http://subversion.tigris.org/issues/show_bug.cgi?id=3067#desc5
+# https://issues.apache.org/jira/browse/SVN-3067#desc5
@SkipUnless(server_has_mergeinfo)
@Issues(3138,3067,4217)
def dont_merge_revs_into_subtree_that_predate_it(sbox):
@@ -10614,7 +10614,7 @@ def dont_merge_revs_into_subtree_that_predate_it(sbox):
# Cherry harvest all eligible revisions from 'A/D/H' to 'H_COPY'.
#
# This is where we see the problem described in
- # http://subversion.tigris.org/issues/show_bug.cgi?id=3067#desc5.
+ # https://issues.apache.org/jira/browse/SVN-3067#desc5.
#
# Use run_and_verify_svn() because run_and_verify_merge*() require
# explicit revision ranges.
@@ -11786,7 +11786,7 @@ def subtree_source_missing_in_requested_range(sbox):
# Another test for issue #3067: 'subtrees that don't exist at the start
# or end of a merge range shouldn't break the merge'
#
-# See http://subversion.tigris.org/issues/show_bug.cgi?id=3067#desc34
+# See https://issues.apache.org/jira/browse/SVN-3067#desc34
@Issue(3067)
@SkipUnless(server_has_mergeinfo)
def subtrees_with_empty_mergeinfo(sbox):
@@ -13305,7 +13305,7 @@ def no_self_referential_filtering_on_added_path(sbox):
# how can any prop changes be merged to it? The answer is that
# the merge code does some quiet housekeeping, merging C_MOVED's
# inherited mergeinfo into its incoming mergeinfo, see
- # http://subversion.tigris.org/issues/show_bug.cgi?id=4309
+ # https://issues.apache.org/jira/browse/SVN-4309
# This test is not covering issue #4309 so we let the current
# behavior pass.
expected_mergeinfo_output = wc.State(A_COPY_2_path, {
@@ -13374,7 +13374,7 @@ def no_self_referential_filtering_on_added_path(sbox):
#----------------------------------------------------------------------
# Test for issue #3324
-# http://subversion.tigris.org/issues/show_bug.cgi?id=3324
+# https://issues.apache.org/jira/browse/SVN-3324
@Issue(3324)
@SkipUnless(server_has_mergeinfo)
def merge_range_prior_to_rename_source_existence(sbox):
@@ -13881,7 +13881,7 @@ def dont_merge_gaps_in_history(sbox):
#----------------------------------------------------------------------
# Test for issue #3432 'Merge can record mergeinfo from natural history
-# gaps'. See http://subversion.tigris.org/issues/show_bug.cgi?id=3432
+# gaps'. See https://issues.apache.org/jira/browse/SVN-3432
@Issue(3432)
@SkipUnless(server_has_mergeinfo)
def handle_gaps_in_implicit_mergeinfo(sbox):
@@ -15122,7 +15122,7 @@ def foreign_repos_del_and_props(sbox):
#----------------------------------------------------------------------
# Test for issue #3642 'immediate depth merges don't create proper subtree
-# mergeinfo'. See http://subversion.tigris.org/issues/show_bug.cgi?id=3642
+# mergeinfo'. See https://issues.apache.org/jira/browse/SVN-3642
@Issue(3642)
def immediate_depth_merge_creates_minimal_subtree_mergeinfo(sbox):
"no spurious mergeinfo from immediate depth merges"
@@ -15817,7 +15817,7 @@ def subtree_merges_inherit_invalid_working_mergeinfo(sbox):
#----------------------------------------------------------------------
# Test for issue #3686 'executable flag not correctly set on merge'
-# See http://subversion.tigris.org/issues/show_bug.cgi?id=3686
+# See https://issues.apache.org/jira/browse/SVN-3686
@Issue(3686)
@SkipUnless(server_has_mergeinfo)
@SkipUnless(svntest.main.is_posix_os)
diff --git a/subversion/tests/cmdline/merge_tree_conflict_tests.py b/subversion/tests/cmdline/merge_tree_conflict_tests.py
index 4f1805b..344c2d2 100755
--- a/subversion/tests/cmdline/merge_tree_conflict_tests.py
+++ b/subversion/tests/cmdline/merge_tree_conflict_tests.py
@@ -540,7 +540,7 @@ def merge_add_over_versioned_file_conflicts(sbox):
def mergeinfo_recording_in_skipped_merge(sbox):
"mergeinfo recording in skipped merge"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2829. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2829. ##
# Create a WC with a single branch
sbox.build()
@@ -705,7 +705,7 @@ def del_differing_file(sbox):
def tree_conflicts_and_obstructions(sbox):
"tree conflicts and obstructions"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3146. ##
+ ## See https://issues.apache.org/jira/browse/SVN-3146. ##
sbox.build()
wc_dir = sbox.wc_dir
diff --git a/subversion/tests/cmdline/mergeinfo_tests.py b/subversion/tests/cmdline/mergeinfo_tests.py
index 328a9f2..fccf5fb 100755
--- a/subversion/tests/cmdline/mergeinfo_tests.py
+++ b/subversion/tests/cmdline/mergeinfo_tests.py
@@ -196,7 +196,7 @@ def mergeinfo_on_unknown_url(sbox):
# Test for issue #3126 'svn mergeinfo shows too few or too many
# eligible revisions'. Specifically
-# http://subversion.tigris.org/issues/show_bug.cgi?id=3126#desc5.
+# https://issues.apache.org/jira/browse/SVN-3126#desc5.
@SkipUnless(server_has_mergeinfo)
@Issue(3126)
def non_inheritable_mergeinfo(sbox):
diff --git a/subversion/tests/cmdline/mod_dav_svn_tests.py b/subversion/tests/cmdline/mod_dav_svn_tests.py
index db30533..db30533 100644..100755
--- a/subversion/tests/cmdline/mod_dav_svn_tests.py
+++ b/subversion/tests/cmdline/mod_dav_svn_tests.py
diff --git a/subversion/tests/cmdline/move_tests.py b/subversion/tests/cmdline/move_tests.py
index 1542af9..6da4a1d 100755
--- a/subversion/tests/cmdline/move_tests.py
+++ b/subversion/tests/cmdline/move_tests.py
@@ -1261,7 +1261,7 @@ def nested_replaces(sbox):
' D /A/B/C/Y',
]))
expected_output = svntest.verify.UnorderedRegexListOutput(escaped
- + [ '^-', '^r2', '^-', '^Changed paths:', ])
+ + [ '^--*', '^r2.*', '^--*', '^Changed paths:', ])
svntest.actions.run_and_verify_svn(expected_output, [],
'log', '-qvr2', repo_url)
diff --git a/subversion/tests/cmdline/patch_tests.py b/subversion/tests/cmdline/patch_tests.py
index 5d41dd6..3cd4dd7 100755
--- a/subversion/tests/cmdline/patch_tests.py
+++ b/subversion/tests/cmdline/patch_tests.py
@@ -4246,7 +4246,7 @@ def patch_git_with_index_line(sbox):
"+++ b/src/tools/ConsoleRunner/hi.txt\n",
"@@ -0,0 +1 @@\n",
"+hihihihihihi\n",
- "\ No newline at end of file\n",
+ "\\ No newline at end of file\n",
]
svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
@@ -4413,7 +4413,7 @@ def patch_replace_dir_with_file_and_vv(sbox):
"+++ A/D\t(working copy)\n",
"@@ -0,0 +1 @@\n",
"+New file\n",
- "\ No newline at end of file\n",
+ "\\ No newline at end of file\n",
# Add iota as directory
"Index: iota\n",
@@ -4426,7 +4426,7 @@ def patch_replace_dir_with_file_and_vv(sbox):
"Added: k\n",
"## -0,0 +1 ##\n",
"+v\n",
- "\ No newline at end of property\n",
+ "\\ No newline at end of property\n",
]))
expected_output = wc.State(wc_dir, {
@@ -6541,7 +6541,7 @@ def patch_prop_madness(sbox):
"Property: del_n\n"
"## -1,1 +0,0 ##\n"
"-no-eol\n"
- "\ No newline at end of property\n"
+ "\\ No newline at end of property\n"
% (sbox.path('iota'),
sbox.path('iota'))),
})
@@ -7791,6 +7791,225 @@ def patch_merge(sbox):
expected_disk, None,
expected_skip)
+def patch_mergeinfo_in_regular_prop_format(sbox):
+ "patch mergeinfo in regular prop format"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ strip_count = wc_dir.count(os.path.sep)+1
+
+ sbox.simple_copy('A/B/E', 'E')
+ sbox.simple_append('A/B/E/alpha', 'extra\nlines\n')
+ sbox.simple_commit()
+
+ sbox.simple_propset('a', 'A', 'E') # 'a' < 'svn:mergeinfo'
+ sbox.simple_propset('z', 'Z', 'E') # 'z' > 'svn:mergeinfo'
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'merge', '^/A/B/E', sbox.ospath('E'))
+ # Rename 'svn:mergeinfo' to 'svn_mergeinfo' so that 'diff' doesn't
+ # pretty-print it; then rename it back before we run it through 'patch'.
+ # (Alternatively, we could disable pretty-printing when we implement a
+ # command-line switch to do so.)
+ mergeinfo_value = sbox.simple_propget('svn:mergeinfo', 'E')
+ sbox.simple_propdel('svn:mergeinfo', 'E')
+ sbox.simple_propset('svn_mergeinfo', mergeinfo_value, 'E')
+
+ _, diff, _ = svntest.actions.run_and_verify_svn(None, [],
+ 'diff', wc_dir)
+ diff = re.sub('svn_mergeinfo', 'svn:mergeinfo', ''.join(diff))
+
+ sbox.simple_revert('E', 'E/alpha')
+
+ patch = sbox.get_tempname('recurse.patch')
+ svntest.main.file_write(patch, diff, mode='wb')
+
+ expected_output = wc.State(wc_dir, {
+ 'E' : Item(status=' U'),
+ 'E/alpha' : Item(status='U '),
+ })
+ expected_skip = wc.State(wc_dir, {})
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({
+ 'E' : Item(status=' M', wc_rev='2'),
+ 'E/alpha' : Item(status='M ', wc_rev='2'),
+ 'E/beta' : Item(status=' ', wc_rev='2'),
+ })
+ expected_status.tweak('A/B/E/alpha', wc_rev=2)
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.tweak('A/B/E/alpha', contents="This is the file 'alpha'.\nextra\nlines\n")
+ expected_disk.add({
+ 'E' : Item(props={'a': 'A',
+ # here is the correctly patched mergeinfo
+ 'svn:mergeinfo': '/A/B/E:2',
+ 'z': 'Z'}),
+ 'E/beta' : Item(contents="This is the file 'beta'.\n"),
+ 'E/alpha' : Item(contents="This is the file 'alpha'.\nextra\nlines\n"),
+ })
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch,
+ expected_output, expected_disk,
+ expected_status, expected_skip,
+ [], True, True,
+ '--strip', strip_count)
+
+@XFail()
+def patch_empty_prop(sbox):
+ "patch empty prop"
+ sbox.build(empty=True)
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+ wc_dir = ''
+
+ # start with a file with an empty prop
+ sbox.simple_add_text('', 'f')
+ sbox.simple_propset('p', '', 'f')
+ sbox.simple_commit()
+
+ # a patch that modifies the prop to a non-empty value
+ unidiff_patch = [
+ "--- f\n",
+ "+++ f\n",
+ "\n",
+ "Property changes on: f\n",
+ "___________________________________________________________________\n",
+ "Modified: p\n",
+ "## -0,0 +1 ##\n",
+ "+v\n",
+ ]
+
+ trailing_eol = False
+ if trailing_eol:
+ value = "v\n"
+ else:
+ value = "v"
+ unidiff_patch += ['\ No newline at end of property\n']
+
+ patch_file_path = sbox.get_tempname('my.patch')
+ svntest.main.file_write(patch_file_path, ''.join(unidiff_patch), 'wb')
+
+ expected_output = [
+ ' U %s\n' % sbox.ospath('f'),
+ ]
+
+ expected_disk = svntest.wc.State(wc_dir, {})
+ expected_disk.add({'f': Item(props={'p' : value})})
+ expected_status = svntest.wc.State(wc_dir, {})
+ expected_status.add({'f': Item(status=' M')})
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+ expected_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, # expected err
+ 1, # check-props
+ False, # dry-run
+ )
+
+ svntest.actions.check_prop('p', wc_dir, [value.encode()])
+
+ os.chdir(was_cwd)
+
+# Test that 'patch' can apply a patch that modifies properties on the root
+# of a WC and/or the root of a repository. This test uses the format of
+# diff output produced by 'svn diff --git' in svn <= 1.10.0: paths are given
+# as 'a/' and 'b/' and 'Property changes on: ' (with no following '.').
+#
+# See dev@ email thread 2018-07-09 from Dmitry Pavlenko,
+# '[PATCH] can't "svn patch" working copy root if the patch is in --git format',
+# https://lists.apache.org/thread.html/d1d9811ca36fac8cabb9339634840099e22811beac505be2ea59f19f@%3Cdev.subversion.apache.org%3E
+@XFail()
+def patch_git_wcroot(sbox):
+ "patch working copy root"
+ sbox.build(empty=True)
+ wc_dir = sbox.wc_dir
+
+ git_patch = [ "Index: .\n",
+ "===================================================================\n",
+ "diff --git a/ b/\n",
+ "--- a/ (revision 0)\n",
+ "+++ b/ (working copy)\n",
+ "Property changes on: \n",
+ "___________________________________________________________________\n",
+ "Added: p\n",
+ "## -0,0 +1 ##\n",
+ "+v\n",
+ "\\ No newline at end of property\n",
+ ]
+ value = 'v'
+
+ patch_file_path = sbox.get_tempname('my.patch')
+ svntest.main.file_write(patch_file_path, ''.join(git_patch), 'wb')
+
+ expected_output = wc.State(wc_dir, {
+ '.' : Item(status=' U'),
+ })
+ expected_disk = svntest.wc.State('', {})
+ expected_disk.add({'': Item(props={'p' : value })})
+ expected_status = svntest.wc.State(wc_dir, {})
+ expected_status.add({'': Item(status=' M', wc_rev='0')})
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+ expected_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, # expected err
+ True, # check-props
+ False, # dry-run
+ )
+
+ svntest.actions.check_prop('p', wc_dir, [value.encode()])
+
+# Test that 'patch' can apply a patch that modifies properties on the root
+# of a WC and/or the root of a repository. This test performs a round-trip
+# through 'diff --git' and 'patch' rather than assuming any particular
+# variant of the patch format.
+#
+# See dev@ email thread 2018-07-09 from Dmitry Pavlenko,
+# '[PATCH] can't "svn patch" working copy root if the patch is in --git format',
+# https://lists.apache.org/thread.html/d1d9811ca36fac8cabb9339634840099e22811beac505be2ea59f19f@%3Cdev.subversion.apache.org%3E
+@XFail()
+def patch_git_wcroot2(sbox):
+ "patch working copy root"
+ sbox.build(empty=True)
+ wc_dir = sbox.wc_dir
+
+ value = 'v'
+ sbox.simple_propset('p', value, '')
+ exit_code, git_patch, err_output = svntest.main.run_svn(None, 'diff',
+ '--git', wc_dir)
+
+ patch_file_path = sbox.get_tempname('my.patch')
+ svntest.main.file_write(patch_file_path, ''.join(git_patch), 'wb')
+
+ sbox.simple_revert('')
+
+ expected_output = wc.State(wc_dir, {
+ '.' : Item(status=' U'),
+ })
+ expected_disk = svntest.wc.State('', {})
+ expected_disk.add({'': Item(props={'p' : value })})
+ expected_status = svntest.wc.State(wc_dir, {})
+ expected_status.add({'': Item(status=' M', wc_rev='0')})
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, patch_file_path,
+ expected_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, # expected err
+ True, # check-props
+ False, # dry-run
+ )
+
+ svntest.actions.check_prop('p', wc_dir, [value.encode()])
+
########################################################################
#Run the tests
@@ -7874,6 +8093,10 @@ test_list = [ None,
missing_trailing_context,
patch_missed_trail,
patch_merge,
+ patch_mergeinfo_in_regular_prop_format,
+ patch_empty_prop,
+ patch_git_wcroot,
+ patch_git_wcroot2,
]
if __name__ == '__main__':
diff --git a/subversion/tests/cmdline/prop_tests.py b/subversion/tests/cmdline/prop_tests.py
index 3709b20..ada2e09 100755
--- a/subversion/tests/cmdline/prop_tests.py
+++ b/subversion/tests/cmdline/prop_tests.py
@@ -1768,7 +1768,7 @@ def rm_of_replaced_file(sbox):
'proplist', '-v',
mu_path + '@base')
expected_output = svntest.verify.UnorderedRegexListOutput([
- 'Properties on',
+ 'Properties on.*',
' yellow',
' submarine',
' orange',
diff --git a/subversion/tests/cmdline/revert_tests.py b/subversion/tests/cmdline/revert_tests.py
index 39ce3c6..5bb6870 100755
--- a/subversion/tests/cmdline/revert_tests.py
+++ b/subversion/tests/cmdline/revert_tests.py
@@ -1550,11 +1550,14 @@ def revert_with_unversioned_targets(sbox):
psi_contents = "modified psi\n"
# touch delta
- open(delta_path, 'w').write(delta_contents)
+ with open(delta_path, 'w') as f:
+ f.write(delta_contents)
# modify chi psi
- open(chi_path, 'w').write(chi_contents)
- open(psi_path, 'w').write(psi_contents)
+ with open(chi_path, 'w') as f:
+ f.write(chi_contents)
+ with open(psi_path, 'w') as f:
+ f.write(psi_contents)
# revert
expected_output = svntest.verify.UnorderedOutput([
diff --git a/subversion/tests/cmdline/shelf_tests.py b/subversion/tests/cmdline/shelf_tests.py
new file mode 100755
index 0000000..899d250
--- /dev/null
+++ b/subversion/tests/cmdline/shelf_tests.py
@@ -0,0 +1,995 @@
+#!/usr/bin/env python
+#
+# shelf_tests.py: testing shelving
+#
+# Subversion is a tool for revision control.
+# See http://subversion.apache.org for more information.
+#
+# ====================================================================
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+######################################################################
+
+# General modules
+import shutil, stat, re, os, logging
+
+logger = logging.getLogger()
+
+# Our testing module
+import svntest
+from svntest import wc
+from svntest.verify import make_diff_header, make_no_diff_deleted_header, \
+ make_git_diff_header, make_diff_prop_header, \
+ make_diff_prop_val, make_diff_prop_deleted, \
+ make_diff_prop_added, make_diff_prop_modified
+
+# (abbreviation)
+Skip = svntest.testcase.Skip_deco
+SkipUnless = svntest.testcase.SkipUnless_deco
+XFail = svntest.testcase.XFail_deco
+Issues = svntest.testcase.Issues_deco
+Issue = svntest.testcase.Issue_deco
+Wimp = svntest.testcase.Wimp_deco
+Item = wc.StateItem
+
+#----------------------------------------------------------------------
+
+def state_from_status(wc_dir,
+ v=True, u=True, q=True):
+ opts = ()
+ if v:
+ opts += ('-v',)
+ if u:
+ opts += ('-u',)
+ if q:
+ opts += ('-q',)
+ _, output, _ = svntest.main.run_svn(None, 'status', wc_dir, *opts)
+ return svntest.wc.State.from_status(output, wc_dir)
+
+def get_wc_state(wc_dir):
+ """Return a description of the WC state. Include as much info as shelving
+ should be capable of restoring.
+ """
+ return (state_from_status(wc_dir),
+ svntest.wc.State.from_wc(wc_dir, load_props=True),
+ )
+
+def check_wc_state(wc_dir, expected):
+ """Check a description of the WC state. Include as much info as shelving
+ should be capable of restoring.
+ """
+ expect_st, expect_wc = expected
+ actual_st, actual_wc = get_wc_state(wc_dir)
+
+ # Verify actual status against expected status.
+ try:
+ expect_st.compare_and_display('status', actual_st)
+ except svntest.tree.SVNTreeError:
+ svntest.actions._log_tree_state("EXPECT STATUS TREE:", expect_st.old_tree(),
+ wc_dir)
+ svntest.actions._log_tree_state("ACTUAL STATUS TREE:", actual_st.old_tree(),
+ wc_dir)
+ raise
+
+ # Verify actual WC against expected WC.
+ try:
+ expect_wc.compare_and_display('status', actual_wc)
+ except svntest.tree.SVNTreeError:
+ svntest.actions._log_tree_state("EXPECT WC TREE:", expect_wc.old_tree(),
+ wc_dir)
+ svntest.actions._log_tree_state("ACTUAL WC TREE:", actual_wc.old_tree(),
+ wc_dir)
+ raise
+
+def shelve_unshelve_verify(sbox, modifier, cannot_shelve=False):
+ """Round-trip: shelve; verify all changes are reverted;
+ unshelve; verify all changes are restored.
+ """
+
+ wc_dir = sbox.wc_dir
+ virginal_state = get_wc_state(wc_dir)
+
+ # Make some changes to the working copy
+ modifier(sbox)
+
+ # Save the modified state
+ modified_state = get_wc_state(wc_dir)
+
+ if cannot_shelve:
+ svntest.actions.run_and_verify_svn(None, '.* could not be shelved.*',
+ 'x-shelve', 'foo')
+ return
+
+ # Shelve; check there are no longer any modifications
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelve', 'foo')
+ check_wc_state(wc_dir, virginal_state)
+
+ # List; ensure the shelf is listed
+ expected_output = svntest.verify.RegexListOutput(
+ [r'foo\s*version \d+.*',
+ r' ',
+ ])
+ svntest.actions.run_and_verify_svn(expected_output, [], 'x-shelves')
+
+ # Unshelve; check the original modifications are here again
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-unshelve', 'foo')
+ check_wc_state(wc_dir, modified_state)
+
+#----------------------------------------------------------------------
+
+def shelve_unshelve(sbox, modifier, cannot_shelve=False):
+ """Round-trip: build 'sbox'; apply changes by calling 'modifier(sbox)';
+ shelve and unshelve; verify changes are fully reverted and restored.
+ """
+
+ if not sbox.is_built():
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+ shelve_unshelve_verify(sbox, modifier, cannot_shelve)
+
+ os.chdir(was_cwd)
+
+######################################################################
+# Tests
+#
+# Each test must return on success or raise on failure.
+
+def shelve_text_mods(sbox):
+ "shelve text mods"
+
+ def modifier(sbox):
+ sbox.simple_append('A/mu', 'appended mu text')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_prop_changes(sbox):
+ "shelve prop changes"
+
+ def modifier(sbox):
+ sbox.simple_propset('p', 'v', 'A')
+ sbox.simple_propset('p', 'v', 'A/mu')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_adds(sbox):
+ "shelve adds"
+
+ def modifier(sbox):
+ sbox.simple_add_text('A new file\n', 'A/new')
+ sbox.simple_add_text('A new file\n', 'A/new2')
+ sbox.simple_propset('p', 'v', 'A/new2')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+@Issue(4709)
+def shelve_deletes(sbox):
+ "shelve deletes"
+
+ def modifier(sbox):
+ sbox.simple_rm('A/mu')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_replace(sbox):
+ "shelve replace"
+
+ def modifier(sbox):
+ sbox.simple_rm('A/mu')
+ sbox.simple_add_text('Replacement\n', 'A/mu')
+ sbox.simple_propset('p', 'v', 'A/mu')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_empty_adds(sbox):
+ "shelve empty adds"
+ sbox.build(empty=True)
+
+ def modifier(sbox):
+ sbox.simple_add_text('', 'empty')
+ sbox.simple_add_text('', 'empty-with-prop')
+ sbox.simple_propset('p', 'v', 'empty-with-prop')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_empty_deletes(sbox):
+ "shelve empty deletes"
+ sbox.build(empty=True)
+ sbox.simple_add_text('', 'empty')
+ sbox.simple_add_text('', 'empty-with-prop')
+ sbox.simple_propset('p', 'v', 'empty-with-prop')
+ sbox.simple_commit()
+
+ def modifier(sbox):
+ sbox.simple_rm('empty', 'empty-with-prop')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_from_inner_path(sbox):
+ "shelve from inner path"
+
+ def modifier(sbox):
+ sbox.simple_append('A/mu', 'appended mu text')
+
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.ospath('A'))
+ sbox.wc_dir = '..'
+
+ shelve_unshelve_verify(sbox, modifier)
+
+ os.chdir(was_cwd)
+
+#----------------------------------------------------------------------
+
+def save_revert_restore(sbox, modifier1, modifier2):
+ "Save 2 checkpoints; revert; restore 1st"
+
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+ wc_dir = ''
+
+ initial_state = get_wc_state(wc_dir)
+
+ # Make some changes to the working copy
+ modifier1(sbox)
+
+ # Remember the modified state
+ modified_state1 = get_wc_state(wc_dir)
+
+ # Save a checkpoint; check nothing changed
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelf-save', 'foo')
+ check_wc_state(wc_dir, modified_state1)
+
+ # Modify again; remember the state; save a checkpoint
+ modifier2(sbox)
+ modified_state2 = get_wc_state(wc_dir)
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelf-save', 'foo')
+ check_wc_state(wc_dir, modified_state2)
+
+ # Revert
+ svntest.actions.run_and_verify_svn(None, [],
+ 'revert', '-R', '.')
+ check_wc_state(wc_dir, initial_state)
+
+ # Restore; check the original modifications are here again
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-unshelve', 'foo', '1')
+ check_wc_state(wc_dir, modified_state1)
+
+ os.chdir(was_cwd)
+
+#----------------------------------------------------------------------
+
+def checkpoint_basic(sbox):
+ "checkpoint basic"
+
+ def modifier1(sbox):
+ sbox.simple_append('A/mu', 'appended mu text\n')
+
+ def modifier2(sbox):
+ sbox.simple_append('iota', 'appended iota text\n')
+ sbox.simple_append('A/mu', 'appended another line\n')
+
+ save_revert_restore(sbox, modifier1, modifier2)
+
+#----------------------------------------------------------------------
+
+@Issue(3747)
+def shelve_mergeinfo(sbox):
+ "shelve mergeinfo"
+
+ def modifier(sbox):
+ sbox.simple_propset('svn:mergeinfo', '/trunk/A:1-3,10', 'A')
+ sbox.simple_propset('svn:mergeinfo', '/trunk/A/mu:1-3,10', 'A/mu')
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def unshelve_refuses_if_conflicts(sbox):
+ "unshelve refuses if conflicts"
+
+ def modifier1(sbox):
+ sbox.simple_append('alpha', 'A-mod1\nB\nC\nD\n', truncate=True)
+ sbox.simple_append('beta', 'A-mod1\nB\nC\nD\n', truncate=True)
+
+ def modifier2(sbox):
+ sbox.simple_append('beta', 'A-mod2\nB\nC\nD\n', truncate=True)
+
+ sbox.build(empty=True)
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+ wc_dir = ''
+
+ sbox.simple_add_text('A\nB\nC\nD\n', 'alpha')
+ sbox.simple_add_text('A\nB\nC\nD\n', 'beta')
+ sbox.simple_commit()
+ initial_state = get_wc_state(wc_dir)
+
+ # Make initial mods; remember this modified state
+ modifier1(sbox)
+ modified_state1 = get_wc_state(wc_dir)
+ assert modified_state1 != initial_state
+
+ # Shelve; check there are no longer any local mods
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelve', 'foo')
+ check_wc_state(wc_dir, initial_state)
+
+ # Make a different local mod that will conflict with the shelf
+ modifier2(sbox)
+ modified_state2 = get_wc_state(wc_dir)
+
+ # Try to unshelve; check it fails with an error about a conflict
+ svntest.actions.run_and_verify_svn(None, '.*[Cc]onflict.*',
+ 'x-unshelve', 'foo')
+ # Check nothing changed in the attempt
+ check_wc_state(wc_dir, modified_state2)
+
+#----------------------------------------------------------------------
+
+def shelve_binary_file_mod(sbox):
+ "shelve binary file mod"
+
+ sbox.build(empty=True)
+
+ existing_files = ['A/B/existing']
+ mod_files = ['bin', 'A/B/bin']
+
+ sbox.simple_mkdir('A', 'A/B')
+ for f in existing_files + mod_files:
+ sbox.simple_add_text('\0\1\2\3\4\5', f)
+ sbox.simple_commit()
+
+ def modifier(sbox):
+ for f in mod_files:
+ sbox.simple_append(f, '\6\5\4\3\2\1\0', truncate=True)
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_binary_file_add(sbox):
+ "shelve binary file add"
+
+ sbox.build(empty=True)
+
+ existing_files = ['A/B/existing']
+ mod_files = ['bin', 'A/B/bin']
+
+ sbox.simple_mkdir('A', 'A/B')
+ for f in existing_files:
+ sbox.simple_add_text('\0\1\2\3\4\5', f)
+ sbox.simple_commit()
+
+ def modifier(sbox):
+ for f in mod_files:
+ sbox.simple_add_text('\0\1\2\3\4\5', f)
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_binary_file_del(sbox):
+ "shelve binary file del"
+
+ sbox.build(empty=True)
+
+ existing_files = ['A/B/existing']
+ mod_files = ['bin', 'A/B/bin']
+
+ sbox.simple_mkdir('A', 'A/B')
+ for f in existing_files + mod_files:
+ sbox.simple_add_text('\0\1\2\3\4\5', f)
+ sbox.simple_commit()
+
+ def modifier(sbox):
+ for f in mod_files:
+ sbox.simple_rm(f)
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_binary_file_replace(sbox):
+ "shelve binary file replace"
+
+ sbox.build(empty=True)
+
+ existing_files = ['A/B/existing']
+ mod_files = ['bin', 'A/B/bin']
+
+ sbox.simple_mkdir('A', 'A/B')
+ for f in existing_files + mod_files:
+ sbox.simple_add_text('\0\1\2\3\4\5', f)
+ sbox.simple_commit()
+
+ def modifier(sbox):
+ for f in mod_files:
+ sbox.simple_rm(f)
+ sbox.simple_add_text('\6\5\4\3\2\1\0', f)
+
+ shelve_unshelve(sbox, modifier)
+
+#----------------------------------------------------------------------
+
+def shelve_with_log_message(sbox):
+ "shelve with log message"
+
+ sbox.build(empty=True)
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+ sbox.simple_add_text('New file', 'f')
+ log_message = 'Log message for foo'
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelve', 'foo', '-m', log_message)
+ expected_output = svntest.verify.RegexListOutput(
+ ['foo .*',
+ ' ' + log_message
+ ])
+ svntest.actions.run_and_verify_svn(expected_output, [],
+ 'x-shelf-list')
+
+ os.chdir(was_cwd)
+
+#----------------------------------------------------------------------
+
+def run_and_verify_status(wc_dir_name, status_tree, changelists=[]):
+ """Run 'status' on WC_DIR_NAME and compare it with the
+ expected STATUS_TREE.
+ Returns on success, raises on failure."""
+
+ if not isinstance(status_tree, wc.State):
+ raise TypeError('wc.State tree expected')
+
+ cl_opts = ('--cl=' + cl for cl in changelists)
+ exit_code, output, errput = svntest.main.run_svn(None, 'status', '-q',
+ wc_dir_name, *cl_opts)
+
+ actual_status = svntest.wc.State.from_status(output, wc_dir=wc_dir_name)
+
+ # Verify actual output against expected output.
+ try:
+ status_tree.compare_and_display('status', actual_status)
+ except svntest.tree.SVNTreeError:
+ svntest.actions._log_tree_state("ACTUAL STATUS TREE:", actual_status.old_tree(),
+ wc_dir_name)
+ raise
+
+def run_and_verify_shelf_status(wc_dir, expected_status, shelf):
+ run_and_verify_status(wc_dir, expected_status,
+ changelists=['svn:shelf:' + shelf])
+
+def shelf_status(sbox):
+ "shelf status"
+
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+ sbox.simple_add_text('New file', 'f')
+ sbox.simple_append('iota', 'New text')
+ sbox.simple_propset('p', 'v', 'A/mu')
+ sbox.simple_rm('A/B/lambda')
+ # Not yet supported:
+ #sbox.simple_rm('A/B/E')
+ expected_status = state_from_status(sbox.wc_dir, v=False, u=False, q=False)
+ run_and_verify_status(sbox.wc_dir, expected_status)
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelve', 'foo')
+ run_and_verify_shelf_status(sbox.wc_dir, expected_status, shelf='foo')
+
+ os.chdir(was_cwd)
+
+#----------------------------------------------------------------------
+
+def shelve_mkdir(sbox):
+ "shelve mkdir"
+
+ sbox.build()
+
+ def modifier(sbox):
+ sbox.simple_mkdir('D', 'D/D2')
+ sbox.simple_propset('p', 'v', 'D', 'D/D2')
+
+ shelve_unshelve(sbox, modifier, cannot_shelve=True)
+
+#----------------------------------------------------------------------
+
+def shelve_rmdir(sbox):
+ "shelve rmdir"
+
+ sbox.build()
+ sbox.simple_propset('p', 'v', 'A/C')
+ sbox.simple_commit()
+
+ def modifier(sbox):
+ sbox.simple_rm('A/C', 'A/D/G')
+
+ shelve_unshelve(sbox, modifier, cannot_shelve=True)
+
+#----------------------------------------------------------------------
+
+def shelve_replace_dir(sbox):
+ "shelve replace dir"
+
+ sbox.build()
+ sbox.simple_propset('p', 'v', 'A/C')
+ sbox.simple_commit()
+
+ def modifier(sbox):
+ sbox.simple_rm('A/C', 'A/D/G')
+ sbox.simple_mkdir('A/C', 'A/C/D2')
+
+ shelve_unshelve(sbox, modifier, cannot_shelve=True)
+
+#----------------------------------------------------------------------
+
+def shelve_file_copy(sbox):
+ "shelve file copy"
+
+ sbox.build()
+
+ def modifier(sbox):
+ sbox.simple_copy('iota', 'A/ii')
+ sbox.simple_propset('p', 'v', 'A/ii')
+
+ shelve_unshelve(sbox, modifier, cannot_shelve=True)
+
+#----------------------------------------------------------------------
+
+def shelve_dir_copy(sbox):
+ "shelve dir copy"
+
+ sbox.build()
+
+ def modifier(sbox):
+ sbox.simple_copy('A/B', 'BB')
+ sbox.simple_propset('p', 'v', 'BB')
+
+ shelve_unshelve(sbox, modifier, cannot_shelve=True)
+
+#----------------------------------------------------------------------
+
+def list_shelves(sbox):
+ "list_shelves"
+
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+ # an empty list
+ svntest.actions.run_and_verify_svn([], [],
+ 'x-shelf-list', '-q')
+
+ # make two shelves
+ sbox.simple_append('A/mu', 'appended mu text')
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelf-save', 'foo')
+ sbox.simple_append('A/mu', 'appended more text')
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelf-save', 'foo', '-m', 'log msg')
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelf-save', 'bar', '-m', 'log msg')
+
+ # We don't check for time-ordering of the shelves. If we want to do so, we
+ # would need to sleep for timestamps to differ, between creating them.
+
+ # a quiet list
+ expected_out = svntest.verify.UnorderedRegexListOutput(['foo', 'bar'])
+ svntest.actions.run_and_verify_svn(expected_out, [],
+ 'x-shelf-list', '-q')
+
+ # a detailed list
+ expected_out = svntest.verify.UnorderedRegexListOutput(['foo .* 1 path.*',
+ ' log msg',
+ 'bar .* 1 path.*',
+ ' log msg'])
+ svntest.actions.run_and_verify_svn(expected_out, [],
+ 'x-shelf-list')
+
+ os.chdir(was_cwd)
+
+#----------------------------------------------------------------------
+
+def refuse_to_shelve_conflict(sbox):
+ "refuse to shelve conflict"
+
+ sbox.build(empty=True)
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+ # create a tree conflict victim at an unversioned path
+ sbox.simple_mkdir('topdir')
+ sbox.simple_commit()
+ sbox.simple_mkdir('topdir/subdir')
+ sbox.simple_commit()
+ sbox.simple_update()
+ sbox.simple_rm('topdir')
+ sbox.simple_commit()
+ sbox.simple_update()
+ svntest.actions.run_and_verify_svn(
+ None, [],
+ 'merge', '-c2', '.', '--ignore-ancestry', '--accept', 'postpone')
+ svntest.actions.run_and_verify_svn(
+ None, 'svn: E155015:.*existing.*conflict.*',
+ 'merge', '-c1', '.', '--ignore-ancestry', '--accept', 'postpone')
+
+ # attempt to shelve
+ expected_out = svntest.verify.RegexListOutput([
+ r'--- .*',
+ r'--- .*',
+ r'\? C topdir',
+ r' > .*',
+ r' > not shelved'])
+ svntest.actions.run_and_verify_svn(expected_out,
+ '.* 1 path could not be shelved',
+ 'x-shelf-save', 'foo')
+
+ os.chdir(was_cwd)
+
+#----------------------------------------------------------------------
+
+def unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state):
+ """Run a test scenario in which 'unshelve' needs to merge some shelved
+ changes made by modifier1() with some committed changes made by
+ modifier2(). tweak_expected_state() must produce the expected WC state.
+ """
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+ wc_dir = sbox.wc_dir
+
+ setup(sbox)
+ sbox.simple_commit()
+ initial_state = get_wc_state(wc_dir)
+
+ # Make some changes to the working copy
+ modifier1(sbox)
+ modified_state = get_wc_state(wc_dir)
+
+ # Shelve; check there are no longer any modifications
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelve', 'foo')
+ check_wc_state(wc_dir, initial_state)
+
+ # Make a different change, with which we shall merge
+ modifier2(sbox)
+ sbox.simple_commit()
+ modified_state[0].tweak('A/mu', wc_rev='3')
+
+ # Unshelve; check the expected result of the merge
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-unshelve', 'foo')
+ tweak_expected_state(modified_state)
+ check_wc_state(wc_dir, modified_state)
+
+ os.chdir(was_cwd)
+
+def unshelve_text_mod_merge(sbox):
+ "unshelve text mod merge"
+
+ orig_contents='A\nB\nC\nD\nE\n'
+ mod1_contents='A\nBB\nC\nD\nE\n'
+ mod2_contents='A\nB\nC\nDD\nE\n'
+ merged_contents='A\nBB\nC\nDD\nE\n'
+
+ def setup(sbox):
+ sbox.simple_append('A/mu', orig_contents, truncate=True)
+
+ def modifier1(sbox):
+ sbox.simple_append('A/mu', mod1_contents, truncate=True)
+
+ def modifier2(sbox):
+ sbox.simple_append('A/mu', mod2_contents, truncate=True)
+
+ def tweak_expected_state(modified_state):
+ modified_state[1].tweak('A/mu', contents=merged_contents)
+
+ unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state)
+
+#----------------------------------------------------------------------
+
+def unshelve_text_mod_conflict(sbox):
+ "unshelve text mod conflict"
+
+ orig_contents='A\nB\nC\nD\nE\n'
+ mod1_contents='A\nBB\nC\nD\nE\n'
+ mod2_contents='A\nBCD\nC\nD\nE\n'
+ merged_contents = 'A\n<<<<<<< .working\nBCD\n||||||| .merge-left\nB\n=======\nBB\n>>>>>>> .merge-right\nC\nD\nE\n'
+
+ def setup(sbox):
+ sbox.simple_append('A/mu', orig_contents, truncate=True)
+
+ def modifier1(sbox):
+ sbox.simple_append('A/mu', mod1_contents, truncate=True)
+
+ def modifier2(sbox):
+ sbox.simple_append('A/mu', mod2_contents, truncate=True)
+
+ def tweak_expected_state(modified_state):
+ modified_state[0].tweak('A/mu', status='C ')
+ modified_state[1].tweak('A/mu', contents=merged_contents)
+ modified_state[1].add({
+ 'A/mu.merge-left': Item(contents=orig_contents),
+ 'A/mu.merge-right': Item(contents=mod1_contents),
+ 'A/mu.working': Item(contents=mod2_contents),
+ })
+
+ unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state)
+
+#----------------------------------------------------------------------
+
+def unshelve_undeclared_binary_mod_conflict(sbox):
+ "unshelve undeclared binary mod conflict"
+
+ orig_contents='\1\2\3\4\5'
+ mod1_contents='\1\2\2\3\4\5'
+ mod2_contents='\1\2\3\4\3\4\5'
+ merged_contents = '<<<<<<< .working\n' + mod2_contents + '||||||| .merge-left\n' + orig_contents + '=======\n' + mod1_contents + '>>>>>>> .merge-right\n'
+
+ def setup(sbox):
+ sbox.simple_append('A/mu', orig_contents, truncate=True)
+
+ def modifier1(sbox):
+ sbox.simple_append('A/mu', mod1_contents, truncate=True)
+
+ def modifier2(sbox):
+ sbox.simple_append('A/mu', mod2_contents, truncate=True)
+
+ def tweak_expected_state(modified_state):
+ modified_state[0].tweak('A/mu', status='C ')
+ modified_state[1].tweak('A/mu', contents=merged_contents)
+ modified_state[1].add({
+ 'A/mu.merge-left': Item(contents=orig_contents),
+ 'A/mu.merge-right': Item(contents=mod1_contents),
+ 'A/mu.working': Item(contents=mod2_contents),
+ })
+
+ unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state)
+
+#----------------------------------------------------------------------
+
+def unshelve_binary_mod_conflict(sbox):
+ "unshelve binary mod conflict"
+
+ orig_contents='\1\2\3\4\5'
+ mod1_contents='\1\2\2\3\4\5'
+ mod2_contents='\1\2\3\4\3\4\5'
+
+ def setup(sbox):
+ sbox.simple_append('A/mu', orig_contents, truncate=True)
+ sbox.simple_propset('svn:mime-type', 'application/octet-stream', 'A/mu')
+
+ def modifier1(sbox):
+ sbox.simple_append('A/mu', mod1_contents, truncate=True)
+
+ def modifier2(sbox):
+ sbox.simple_append('A/mu', mod2_contents, truncate=True)
+
+ def tweak_expected_state(modified_state):
+ modified_state[0].tweak('A/mu', status='C ')
+ modified_state[1].tweak('A/mu', contents=mod2_contents)
+ modified_state[1].add({
+ 'A/mu.merge-left': Item(contents=orig_contents),
+ 'A/mu.merge-right': Item(contents=mod1_contents),
+ })
+
+ unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state)
+
+#----------------------------------------------------------------------
+
+def unshelve_text_prop_merge(sbox):
+ "unshelve text prop merge"
+
+ def setup(sbox):
+ sbox.simple_propset('p1', 'v', 'A/mu')
+ sbox.simple_propset('p2', 'v', 'A/mu')
+
+ def modifier1(sbox):
+ sbox.simple_propset('p1', 'changed', 'A/mu')
+
+ def modifier2(sbox):
+ sbox.simple_propset('p2', 'changed', 'A/mu')
+
+ def tweak_expected_state(wc_state):
+ wc_state[1].tweak('A/mu', props={'p1':'changed',
+ 'p2':'changed'})
+
+ unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state)
+
+#----------------------------------------------------------------------
+
+def unshelve_text_prop_conflict(sbox):
+ "unshelve text prop conflict"
+
+ orig_contents='A'
+ mod1_contents='B'
+ mod2_contents='C'
+ merged_contents='C'
+ prej_contents='''Trying to change property 'p'
+but the local property value conflicts with the incoming change.
+<<<<<<< (local property value)
+C||||||| (incoming 'changed from' value)
+A=======
+B>>>>>>> (incoming 'changed to' value)
+'''
+
+ def setup(sbox):
+ sbox.simple_propset('p', orig_contents, 'A/mu')
+
+ def modifier1(sbox):
+ sbox.simple_propset('p', mod1_contents, 'A/mu')
+
+ def modifier2(sbox):
+ sbox.simple_propset('p', mod2_contents, 'A/mu')
+
+ def tweak_expected_state(wc_state):
+ wc_state[0].tweak('A/mu', status=' C')
+ wc_state[1].tweak('A/mu', props={'p':merged_contents})
+ wc_state[1].add({
+ 'A/mu.prej': Item(contents=prej_contents),
+ })
+
+ unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state)
+
+#----------------------------------------------------------------------
+
+def run_and_verify_shelf_diff_summarize(output_tree, shelf, *args):
+ """Run 'svn shelf-diff --summarize' with the arguments *ARGS.
+
+ The subcommand output will be verified against OUTPUT_TREE. Returns
+ on success, raises on failure.
+ """
+
+ if isinstance(output_tree, wc.State):
+ output_tree = output_tree.old_tree()
+
+ exit_code, output, errput = svntest.actions.run_and_verify_svn(
+ None, [],
+ 'x-shelf-diff', '--summarize', shelf, *args)
+
+ actual = svntest.tree.build_tree_from_diff_summarize(output)
+
+ # Verify actual output against expected output.
+ try:
+ svntest.tree.compare_trees("output", actual, output_tree)
+ except svntest.tree.SVNTreeError:
+ svntest.verify.display_trees(None, 'DIFF OUTPUT TREE', output_tree, actual)
+ raise
+
+# Exercise a very basic case of shelf-diff.
+def shelf_diff_simple(sbox):
+ "shelf diff simple"
+
+ sbox.build()
+ was_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+ wc_dir = sbox.wc_dir
+
+ def setup(sbox):
+ sbox.simple_propset('p1', 'v', 'A/mu')
+ sbox.simple_propset('p2', 'v', 'A/mu')
+
+ def modifier1(sbox):
+ sbox.simple_append('A/mu', 'New line.\n')
+ sbox.simple_propset('p1', 'changed', 'A/mu')
+
+ setup(sbox)
+ sbox.simple_commit()
+ initial_state = get_wc_state(wc_dir)
+
+ # Make some changes to the working copy
+ modifier1(sbox)
+ modified_state = get_wc_state(wc_dir)
+
+ svntest.actions.run_and_verify_svn(None, [],
+ 'x-shelf-save', 'foo')
+
+ # basic svn-style diff
+ expected_output = make_diff_header('A/mu', 'revision 2', 'working copy') + [
+ "@@ -1 +1,2 @@\n",
+ " This is the file 'mu'.\n",
+ "+New line.\n",
+ ] + make_diff_prop_header('A/mu') \
+ + make_diff_prop_modified('p1', 'v', 'changed')
+ svntest.actions.run_and_verify_svn(expected_output, [],
+ 'x-shelf-diff', 'foo')
+
+ # basic summary diff
+ expected_diff = svntest.wc.State(wc_dir, {
+ 'A/mu': Item(status='MM'),
+ })
+ run_and_verify_shelf_diff_summarize(expected_diff, 'foo')
+
+
+########################################################################
+# Run the tests
+
+# list all tests here, starting with None:
+test_list = [ None,
+ shelve_text_mods,
+ shelve_prop_changes,
+ shelve_adds,
+ shelve_deletes,
+ shelve_replace,
+ shelve_empty_adds,
+ shelve_empty_deletes,
+ shelve_from_inner_path,
+ checkpoint_basic,
+ shelve_mergeinfo,
+ unshelve_refuses_if_conflicts,
+ shelve_binary_file_mod,
+ shelve_binary_file_add,
+ shelve_binary_file_del,
+ shelve_binary_file_replace,
+ shelve_with_log_message,
+ shelf_status,
+ shelve_mkdir,
+ shelve_rmdir,
+ shelve_replace_dir,
+ shelve_file_copy,
+ shelve_dir_copy,
+ list_shelves,
+ refuse_to_shelve_conflict,
+ unshelve_text_mod_merge,
+ unshelve_text_mod_conflict,
+ unshelve_undeclared_binary_mod_conflict,
+ unshelve_binary_mod_conflict,
+ unshelve_text_prop_merge,
+ unshelve_text_prop_conflict,
+ shelf_diff_simple,
+ ]
+
+if __name__ == '__main__':
+ svntest.main.run_tests(test_list)
+ # NOTREACHED
+
+
+### End of file.
diff --git a/subversion/tests/cmdline/shelve_tests.py b/subversion/tests/cmdline/shelve_tests.py
deleted file mode 100755
index a71ddbb..0000000
--- a/subversion/tests/cmdline/shelve_tests.py
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/env python
-#
-# shelve_tests.py: testing shelving
-#
-# Subversion is a tool for revision control.
-# See http://subversion.apache.org for more information.
-#
-# ====================================================================
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-######################################################################
-
-# General modules
-import shutil, stat, re, os, logging
-
-logger = logging.getLogger()
-
-# Our testing module
-import svntest
-from svntest import wc
-
-# (abbreviation)
-Skip = svntest.testcase.Skip_deco
-SkipUnless = svntest.testcase.SkipUnless_deco
-XFail = svntest.testcase.XFail_deco
-Issues = svntest.testcase.Issues_deco
-Issue = svntest.testcase.Issue_deco
-Wimp = svntest.testcase.Wimp_deco
-Item = wc.StateItem
-
-#----------------------------------------------------------------------
-
-def shelve_unshelve_verify(sbox):
- """Round-trip: shelve; verify all changes are reverted;
- unshelve; verify all changes are restored.
- """
-
- wc_dir = sbox.wc_dir
-
- # Save the modified state
- _, output, _ = svntest.main.run_svn(None, 'status', '-v', '-u', '-q',
- wc_dir)
- modified_state = svntest.wc.State.from_status(output, wc_dir)
-
- # Shelve; check there are no longer any modifications
- svntest.actions.run_and_verify_svn(None, [],
- 'shelve', 'foo')
- virginal_state = svntest.actions.get_virginal_state(wc_dir, 1)
- svntest.actions.run_and_verify_status(wc_dir, virginal_state)
-
- # Unshelve; check the original modifications are here again
- svntest.actions.run_and_verify_svn(None, [],
- 'unshelve', 'foo')
- svntest.actions.run_and_verify_status(wc_dir, modified_state)
-
-#----------------------------------------------------------------------
-
-def shelve_unshelve(sbox, modifier):
- """Round-trip: build 'sbox'; apply changes by calling 'modifier(sbox)';
- shelve and unshelve; verify changes are fully reverted and restored.
- """
-
- sbox.build()
- was_cwd = os.getcwd()
- os.chdir(sbox.wc_dir)
- sbox.wc_dir = ''
-
- # Make some changes to the working copy
- modifier(sbox)
-
- shelve_unshelve_verify(sbox)
-
- os.chdir(was_cwd)
-
-######################################################################
-# Tests
-#
-# Each test must return on success or raise on failure.
-
-def shelve_text_mods(sbox):
- "shelve text mods"
-
- def modifier(sbox):
- sbox.simple_append('A/mu', 'appended mu text')
-
- shelve_unshelve(sbox, modifier)
-
-#----------------------------------------------------------------------
-
-def shelve_prop_changes(sbox):
- "shelve prop changes"
-
- def modifier(sbox):
- sbox.simple_propset('p', 'v', 'A')
- sbox.simple_propset('p', 'v', 'A/mu')
-
- shelve_unshelve(sbox, modifier)
-
-#----------------------------------------------------------------------
-
-def shelve_adds(sbox):
- "shelve adds"
-
- def modifier(sbox):
- sbox.simple_append('A/new', 'A new file\n')
- sbox.simple_add('A/new')
- sbox.simple_append('A/new2', 'A new file\n')
- sbox.simple_add('A/new2')
- sbox.simple_propset('p', 'v', 'A/new2')
-
- shelve_unshelve(sbox, modifier)
-
-#----------------------------------------------------------------------
-
-@XFail()
-@Issue(4709)
-def shelve_deletes(sbox):
- "shelve deletes"
-
- def modifier(sbox):
- sbox.simple_rm('A/mu')
-
- shelve_unshelve(sbox, modifier)
-
-#----------------------------------------------------------------------
-
-def shelve_from_inner_path(sbox):
- "shelve from inner path"
-
- def modifier(sbox):
- sbox.simple_append('A/mu', 'appended mu text')
-
- sbox.build()
- was_cwd = os.getcwd()
- os.chdir(sbox.ospath('A'))
- sbox.wc_dir = '..'
-
- modifier(sbox)
- shelve_unshelve_verify(sbox)
-
- os.chdir(was_cwd)
-
-#----------------------------------------------------------------------
-
-########################################################################
-# Run the tests
-
-# list all tests here, starting with None:
-test_list = [ None,
- shelve_text_mods,
- shelve_prop_changes,
- shelve_adds,
- shelve_deletes,
- shelve_from_inner_path,
- ]
-
-if __name__ == '__main__':
- svntest.main.run_tests(test_list)
- # NOTREACHED
-
-
-### End of file.
diff --git a/subversion/tests/cmdline/special_tests.py b/subversion/tests/cmdline/special_tests.py
index db612c1..2ec22cb 100755
--- a/subversion/tests/cmdline/special_tests.py
+++ b/subversion/tests/cmdline/special_tests.py
@@ -535,7 +535,7 @@ def diff_symlink_to_dir(sbox):
"+++ link\t(working copy)\n",
"@@ -0,0 +1 @@\n",
"+link A/D\n",
- "\ No newline at end of file\n",
+ "\\ No newline at end of file\n",
"\n",
"Property changes on: link\n",
"___________________________________________________________________\n",
@@ -730,7 +730,8 @@ def unrelated_changed_special_status(sbox):
os.chdir(os.path.join(sbox.wc_dir, 'A/D/H'))
- open('chi', 'a').write('random local mod')
+ with open('chi', 'a') as f:
+ f.write('random local mod')
os.unlink('psi')
os.symlink('omega', 'psi') # omega is versioned!
svntest.main.run_svn(None, 'changelist', 'chi cl', 'chi')
diff --git a/subversion/tests/cmdline/stat_tests.py b/subversion/tests/cmdline/stat_tests.py
index afab961..e0f1306 100755
--- a/subversion/tests/cmdline/stat_tests.py
+++ b/subversion/tests/cmdline/stat_tests.py
@@ -1949,7 +1949,8 @@ def modified_modulo_translation(sbox):
sbox.simple_commit()
# CRLF it.
- open(sbox.ospath('iota'), 'wb').write("This is the file 'iota'.\r\n")
+ with open(sbox.ospath('iota'), 'wb') as f:
+ f.write("This is the file 'iota'.\r\n")
# Run status. Expect some output.
# TODO: decide how such files should show in the output; whether they
diff --git a/subversion/tests/cmdline/svnadmin_tests.py b/subversion/tests/cmdline/svnadmin_tests.py
index 40b5e97..4d5303c 100755
--- a/subversion/tests/cmdline/svnadmin_tests.py
+++ b/subversion/tests/cmdline/svnadmin_tests.py
@@ -53,6 +53,23 @@ Wimp = svntest.testcase.Wimp_deco
SkipDumpLoadCrossCheck = svntest.testcase.SkipDumpLoadCrossCheck_deco
Item = svntest.wc.StateItem
+def read_rep_cache(repo_dir):
+ """Return the rep-cache contents as a dict {hash: (rev, index, ...)}.
+ """
+ db_path = os.path.join(repo_dir, 'db', 'rep-cache.db')
+ db1 = svntest.sqlite3.connect(db_path)
+ schema1 = db1.execute("pragma user_version").fetchone()[0]
+ # Can't test newer rep-cache schemas with an old built-in SQLite.
+ if schema1 >= 2 and svntest.sqlite3.sqlite_version_info < (3, 8, 2):
+ raise svntest.Failure("Can't read rep-cache schema %d using old "
+ "Python-SQLite version %s < (3,8,2)" %
+ (schema1,
+ svntest.sqlite3.sqlite_version_info))
+
+ content = { row[0]: row[1:] for row in
+ db1.execute("select * from rep_cache") }
+ return content
+
def check_hotcopy_bdb(src, dst):
"Verify that the SRC BDB repository has been correctly copied to DST."
### TODO: This function should be extended to verify all hotcopied files,
@@ -256,7 +273,8 @@ def patch_format(repo_dir, shard_size):
new_contents = b"\n".join(processed_lines)
os.chmod(format_path, svntest.main.S_ALL_RW)
- open(format_path, 'wb').write(new_contents)
+ with open(format_path, 'wb') as f:
+ f.write(new_contents)
def is_sharded(repo_dir):
"""Return whether the FSFS repository REPO_DIR is sharded."""
@@ -777,9 +795,13 @@ def verify_windows_paths_in_repos(sbox):
def fsfs_file(repo_dir, kind, rev):
if svntest.main.options.server_minor_version >= 5:
if svntest.main.options.fsfs_sharding is None:
+ if svntest.main.is_fs_type_fsx():
+ rev = 'r' + rev
return os.path.join(repo_dir, 'db', kind, '0', rev)
else:
shard = int(rev) // svntest.main.options.fsfs_sharding
+ if svntest.main.is_fs_type_fsx():
+ rev = 'r' + rev
path = os.path.join(repo_dir, 'db', kind, str(shard), rev)
if svntest.main.options.fsfs_packing is None or kind == 'revprops':
@@ -1043,7 +1065,7 @@ def fsfs_recover_old_db_current(sbox):
def load_with_parent_dir(sbox):
"'svnadmin load --parent-dir' reparents mergeinfo"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2983. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2983. ##
sbox.build(empty=True)
dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
@@ -1134,7 +1156,7 @@ def set_uuid(sbox):
def reflect_dropped_renumbered_revs(sbox):
"reflect dropped renumbered revs in svn:mergeinfo"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3020. ##
+ ## See https://issues.apache.org/jira/browse/SVN-3020. ##
sbox.build(empty=True)
@@ -1326,7 +1348,7 @@ def verify_with_invalid_revprops(sbox):
# 2) Dump 'SOURCE-REPOS' in a series of incremental dumps and load
# each of them to 'TARGET-REPOS'.
#
-# See http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc13
+# See https://issues.apache.org/jira/browse/SVN-3020#desc13
@Issue(3020)
def dont_drop_valid_mergeinfo_during_incremental_loads(sbox):
"don't filter mergeinfo revs from incremental dump"
@@ -1512,7 +1534,7 @@ def dont_drop_valid_mergeinfo_during_incremental_loads(sbox):
# Check the resulting mergeinfo. We expect the exact same results
# as Part 3.
- # See http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16.
+ # See https://issues.apache.org/jira/browse/SVN-3020#desc16.
svntest.actions.run_and_verify_svn(expected_output, [],
'propget', 'svn:mergeinfo', '-R',
sbox.repo_url)
@@ -1523,7 +1545,7 @@ def dont_drop_valid_mergeinfo_during_incremental_loads(sbox):
def hotcopy_symlink(sbox):
"'svnadmin hotcopy' replicates symlink"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2591. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2591. ##
# Create a repository.
sbox.build(create_wc=False, empty=True)
@@ -1629,9 +1651,9 @@ text
sbox.build(empty=True)
# Try to load the dumpstream, expecting a failure (because of mixed EOLs).
- exp_err = svntest.verify.RegexListOutput(['svnadmin: E125005',
- 'svnadmin: E125005',
- 'svnadmin: E125017'],
+ exp_err = svntest.verify.RegexListOutput(['svnadmin: E125005:.*',
+ 'svnadmin: E125005:.*',
+ 'svnadmin: E125017:.*'],
match_all=False)
load_and_verify_dumpstream(sbox, [], exp_err, dumpfile_revisions,
False, dump_str, '--ignore-uuid')
@@ -1760,10 +1782,10 @@ def test_lslocks_and_rmlocks(sbox):
def expected_output_list(path):
return [
"Path: " + path,
- "UUID Token: opaquelocktoken",
+ "UUID Token: opaquelocktoken:.*",
"Owner: jrandom",
- "Created:",
- "Expires:",
+ "Created:.*",
+ "Expires:.*",
"Comment \(1 line\):",
"Locking files",
"\n", # empty line
@@ -1814,7 +1836,7 @@ def test_lslocks_and_rmlocks(sbox):
def load_ranges(sbox):
"'svnadmin load --revision X:Y'"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3734. ##
+ ## See https://issues.apache.org/jira/browse/SVN-3734. ##
sbox.build(empty=True)
dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
@@ -2165,7 +2187,7 @@ def verify_keep_going(sbox):
sbox.repo_dir)
if (svntest.main.is_fs_log_addressing()):
- exp_out = svntest.verify.RegexListOutput([".*Verifying metadata at revision 0"])
+ exp_out = svntest.verify.RegexListOutput([".*Verifying metadata at revision 0.*"])
else:
exp_out = svntest.verify.RegexListOutput([".*Verified revision 0.",
".*Verified revision 1."])
@@ -2856,10 +2878,7 @@ def verify_quickly(sbox):
"verify quickly using metadata"
sbox.build(create_wc = False)
- if svntest.main.is_fs_type_fsfs():
- rev_file = open(fsfs_file(sbox.repo_dir, 'revs', '1'), 'r+b')
- else:
- rev_file = open(fsfs_file(sbox.repo_dir, 'revs', 'r1'), 'r+b')
+ rev_file = open(fsfs_file(sbox.repo_dir, 'revs', '1'), 'r+b')
# set new contents
rev_file.seek(8)
@@ -3458,7 +3477,8 @@ def load_from_file(sbox):
sbox.build(empty=True)
file = sbox.get_tempname()
- open(file, 'wb').writelines(clean_dumpfile())
+ with open(file, 'wb') as f:
+ f.writelines(clean_dumpfile())
svntest.actions.run_and_verify_svnadmin2(None, [],
0, 'load', '--file', file,
'--ignore-uuid', sbox.repo_dir)
@@ -3762,7 +3782,7 @@ def dump_exclude_all_rev_changes(sbox):
# Check log. Revision properties ('svn:log' etc.) should be empty for r2.
expected_output = svntest.verify.RegexListOutput([
'-+\\n',
- 'r3\ |\ jrandom\ |\ .*\ |\ 1\ line\\n',
+ 'r3 | jrandom | .* | 1 line\\n',
re.escape('Changed paths:'),
re.escape(' A /r3a'),
re.escape(' A /r3b'),
@@ -3774,7 +3794,7 @@ def dump_exclude_all_rev_changes(sbox):
'',
'',
'-+\\n',
- 'r1\ |\ jrandom\ |\ .*\ |\ 1\ line\\n',
+ 'r1 | jrandom | .* | 1 line\\n',
re.escape('Changed paths:'),
re.escape(' A /r1a'),
re.escape(' A /r1b'),
@@ -3823,6 +3843,76 @@ def load_issue4725(sbox):
sbox2.build(create_wc=False, empty=True)
load_and_verify_dumpstream(sbox2, None, [], None, False, dump, '-M100')
+@Issue(4767)
+def dump_no_canonicalize_svndate(sbox):
+ "svnadmin dump shouldn't canonicalize svn:date"
+
+ sbox.build(create_wc=False, empty=True)
+ svntest.actions.enable_revprop_changes(sbox.repo_dir)
+
+ # set svn:date in a non-canonical format (not six decimal places)
+ propval = "2015-01-01T00:00:00.0Z"
+ svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
+ "propset", "--revprop", "-r0", "svn:date",
+ propval,
+ sbox.repo_url)
+
+ dump_lines = svntest.actions.run_and_verify_dump(sbox.repo_dir)
+ assert propval + '\n' in dump_lines
+
+def check_recover_prunes_rep_cache(sbox, enable_rep_sharing):
+ """Check 'recover' prunes the rep-cache while enable-rep-sharing is
+ true/false.
+ """
+ # Remember the initial rep cache content.
+ rep_cache_r1 = read_rep_cache(sbox.repo_dir)
+ #print '\n'.join([h + ": " + repr(ref) for h, ref in rep_cache_r1.items()])
+
+ # Commit one new rep and check the rep-cache is extended.
+ sbox.simple_append('iota', 'New line.\n')
+ sbox.simple_commit()
+ rep_cache_r2 = read_rep_cache(sbox.repo_dir)
+ assert len(rep_cache_r2) == len(rep_cache_r1) + 1
+
+ # To test 'recover' while rep-sharing is disabled, disable it now.
+ if not enable_rep_sharing:
+ fsfs_conf = svntest.main.get_fsfs_conf_file_path(sbox.repo_dir)
+ svntest.main.file_append(fsfs_conf,
+ "[rep-sharing]\n"
+ "enable-rep-sharing = false\n")
+
+ # Break r2 in such a way that 'recover' will discard it
+ head_rev_path = fsfs_file(sbox.repo_dir, 'revs', '2')
+ os.remove(head_rev_path)
+ current_path = os.path.join(sbox.repo_dir, 'db', 'current')
+ svntest.main.file_write(current_path, '1\n')
+
+ # Recover back to r1.
+ svntest.actions.run_and_verify_svnadmin(None, [],
+ "recover", sbox.repo_dir)
+
+ # Check the rep-cache is pruned.
+ rep_cache_recovered = read_rep_cache(sbox.repo_dir)
+ assert rep_cache_recovered == rep_cache_r1
+
+@Issue(4077)
+@SkipUnless(svntest.main.is_fs_type_fsfs)
+@SkipUnless(svntest.main.python_sqlite_can_read_without_rowid)
+def recover_prunes_rep_cache_when_enabled(sbox):
+ "recover prunes rep cache when enabled"
+ sbox.build()
+
+ check_recover_prunes_rep_cache(sbox, enable_rep_sharing=True)
+
+@Issue(4077)
+@SkipUnless(svntest.main.is_fs_type_fsfs)
+@SkipUnless(svntest.main.python_sqlite_can_read_without_rowid)
+def recover_prunes_rep_cache_when_disabled(sbox):
+ "recover prunes rep cache when disabled"
+ sbox.build()
+
+ check_recover_prunes_rep_cache(sbox, enable_rep_sharing=False)
+
########################################################################
# Run the tests
@@ -3897,6 +3987,9 @@ test_list = [ None,
dump_exclude_all_rev_changes,
dump_invalid_filtering_option,
load_issue4725,
+ dump_no_canonicalize_svndate,
+ recover_prunes_rep_cache_when_enabled,
+ recover_prunes_rep_cache_when_disabled,
]
if __name__ == '__main__':
diff --git a/subversion/tests/cmdline/svnauthz_tests.py b/subversion/tests/cmdline/svnauthz_tests.py
index fd1de40..ac6a375 100755
--- a/subversion/tests/cmdline/svnauthz_tests.py
+++ b/subversion/tests/cmdline/svnauthz_tests.py
@@ -197,9 +197,8 @@ def svnauthz_validate_txn_test(sbox):
svntest.main.create_python_hook_script(pre_commit_hook, hook_instance)
svntest.main.file_append(authz_path, 'x')
expected_status.tweak('A/authz', status=' ', wc_rev=4)
- if svntest.actions.run_and_verify_commit(wc_dir, expected_output,
- expected_status):
- raise svntest.Failure
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ expected_status)
expected_data = svntest.verify.ExpectedOutput("Exit 2\n", match_all=False)
verify_logfile(logfilepath, expected_data)
@@ -275,9 +274,8 @@ def svnauthz_accessof_repo_test(sbox):
expected_status.add({
'A/authz' : Item(status=' ', wc_rev=2),
})
- if svntest.actions.run_and_verify_commit(wc_dir, expected_output,
- expected_status):
- raise svntest.Failure
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ expected_status)
# Anonymous access with no path, and no repository should be rw
# since it returns the highest level of access granted anywhere.
diff --git a/subversion/tests/cmdline/svndumpfilter_tests.py b/subversion/tests/cmdline/svndumpfilter_tests.py
index 7ee09a4..a45b50b 100755
--- a/subversion/tests/cmdline/svndumpfilter_tests.py
+++ b/subversion/tests/cmdline/svndumpfilter_tests.py
@@ -83,7 +83,7 @@ def filter_and_return_output(dump, bufsize=0, *varargs):
def reflect_dropped_renumbered_revs(sbox):
"reflect dropped renumbered revs in svn:mergeinfo"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2982. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2982. ##
# Test svndumpfilter with include option
sbox.build(empty=True)
@@ -134,7 +134,7 @@ def svndumpfilter_loses_mergeinfo(sbox):
"svndumpfilter loses mergeinfo"
#svndumpfilter loses mergeinfo if invoked without --renumber-revs
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3181. ##
+ ## See https://issues.apache.org/jira/browse/SVN-3181. ##
sbox.build(empty=True)
dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
@@ -217,7 +217,7 @@ def _simple_dumpfilter_test(sbox, dumpfile, *dumpargs):
@Issue(2697)
def dumpfilter_with_targets(sbox):
"svndumpfilter --targets blah"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2697. ##
+ ## See https://issues.apache.org/jira/browse/SVN-2697. ##
sbox.build(empty=True)
@@ -677,7 +677,7 @@ def accepts_deltas(sbox):
@Issue(4234)
def dumpfilter_targets_expect_leading_slash_prefixes(sbox):
"dumpfilter targets expect leading '/' in prefixes"
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=4234. ##
+ ## See https://issues.apache.org/jira/browse/SVN-4234. ##
sbox.build(empty=True)
diff --git a/subversion/tests/cmdline/svnfsfs_tests.py b/subversion/tests/cmdline/svnfsfs_tests.py
index e1fd73d..aff3c2f 100755
--- a/subversion/tests/cmdline/svnfsfs_tests.py
+++ b/subversion/tests/cmdline/svnfsfs_tests.py
@@ -94,7 +94,8 @@ def patch_format(repo_dir, shard_size):
new_contents = b"\n".join(processed_lines)
os.chmod(format_path, svntest.main.S_ALL_RW)
- open(format_path, 'wb').write(new_contents)
+ with open(format_path, 'wb') as f:
+ f.write(new_contents)
######################################################################
# Tests
diff --git a/subversion/tests/cmdline/svnmover_tests.py b/subversion/tests/cmdline/svnmover_tests.py
index bfdbb1f..6c98b64 100755
--- a/subversion/tests/cmdline/svnmover_tests.py
+++ b/subversion/tests/cmdline/svnmover_tests.py
@@ -469,7 +469,7 @@ rm A/B/C/Y
' D /top0/A/B/C/Y',
]))
expected_output = svntest.verify.UnorderedRegexListOutput(escaped
- + ['^-', '^r2', '^-', '^Changed paths:',])
+ + ['^--*', '^r2.*', '^--*', '^Changed paths:',])
svntest.actions.run_and_verify_svn(expected_output, [],
'log', '-qvr2', repo_url)
@@ -755,7 +755,7 @@ def simple_moves_within_a_branch(sbox):
'mv lib/foo/y2 y2')
# move and rename, dir with children
test_svnmover2(sbox, '/trunk',
- reported_br_diff('') +
+ reported_br_diff('trunk') +
reported_add('subdir') +
reported_move('lib', 'subdir/lib2'),
'mkdir subdir',
@@ -765,7 +765,7 @@ def simple_moves_within_a_branch(sbox):
# moves and renames together
# (put it all back to how it was, in one commit)
test_svnmover2(sbox, '/trunk',
- reported_br_diff('') +
+ reported_br_diff('trunk') +
reported_move('subdir/lib2/README.txt', 'README') +
reported_move('subdir/lib2', 'lib') +
reported_move('y2', 'lib/foo/y') +
diff --git a/subversion/tests/cmdline/svnmucc_tests.py b/subversion/tests/cmdline/svnmucc_tests.py
index f95c558..3159ec2 100755
--- a/subversion/tests/cmdline/svnmucc_tests.py
+++ b/subversion/tests/cmdline/svnmucc_tests.py
@@ -458,7 +458,7 @@ rm A/B/C/Y
' D /A/B/C/Y',
]))
expected_output = svntest.verify.UnorderedRegexListOutput(excaped
- + ['^-', '^r3', '^-', '^Changed paths:',])
+ + ['^--*', '^r3.*', '^--*', '^Changed paths:',])
svntest.actions.run_and_verify_svn(expected_output, [],
'log', '-qvr3', repo_url)
diff --git a/subversion/tests/cmdline/svnrdump_tests.py b/subversion/tests/cmdline/svnrdump_tests.py
index ae6a7e0..b6d4c6f 100755
--- a/subversion/tests/cmdline/svnrdump_tests.py
+++ b/subversion/tests/cmdline/svnrdump_tests.py
@@ -80,7 +80,7 @@ def compare_repos_dumps(sbox, other_dumpfile,
### This call kind-of assumes EXPECTED is first and ACTUAL is second.
svntest.verify.compare_dump_files(
- "Dump files", "DUMP", other_dumpfile, sbox_dumpfile)
+ None, None, other_dumpfile, sbox_dumpfile)
def run_dump_test(sbox, dumpfile_name, expected_dumpfile_name = None,
subdir = None, bypass_prop_validation = False,
@@ -455,7 +455,7 @@ def reflect_dropped_renumbered_revs(sbox):
# 2) Dump 'SOURCE-REPOS' in a series of incremental dumps and load
# each of them to 'TARGET-REPOS'.
#
-# See http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc13
+# See https://issues.apache.org/jira/browse/SVN-3020#desc13
#
# This test replicates svnadmin_tests.py 20 'don't filter mergeinfo revs
# from incremental dump' but uses 'svnrdump [dump|load]' in place of
@@ -704,7 +704,7 @@ def dont_drop_valid_mergeinfo_during_incremental_svnrdump_loads(sbox):
# Check the resulting mergeinfo. We expect the exact same results
# as Part 3.
- # See http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16.
+ # See https://issues.apache.org/jira/browse/SVN-3020#desc16.
svntest.actions.run_and_verify_svn(expected_output, [],
'propget', 'svn:mergeinfo', '-R',
sbox.repo_url)
diff --git a/subversion/tests/cmdline/svnsync_authz_tests.py b/subversion/tests/cmdline/svnsync_authz_tests.py
index e8b9444..e464cde 100755
--- a/subversion/tests/cmdline/svnsync_authz_tests.py
+++ b/subversion/tests/cmdline/svnsync_authz_tests.py
@@ -415,7 +415,7 @@ def specific_deny_authz(sbox):
# For mod_dav_svn's parent path setup we need per-repos permissions in
# the authz file...
- if sbox.repo_url.startswith('http'):
+ if svntest.main.is_ra_type_dav():
src_authz = sbox.authz_name()
dst_authz = dest_sbox.authz_name()
write_authz_file(sbox, None,
diff --git a/subversion/tests/cmdline/svnsync_tests.py b/subversion/tests/cmdline/svnsync_tests.py
index ba55fb5..744fbbb 100755
--- a/subversion/tests/cmdline/svnsync_tests.py
+++ b/subversion/tests/cmdline/svnsync_tests.py
@@ -167,7 +167,7 @@ def verify_mirror(dest_sbox, exp_dump_file_contents):
dest_dump = svntest.actions.run_and_verify_dump(dest_sbox.repo_dir)
svntest.verify.compare_dump_files(
- "Dump files", "DUMP", exp_dump_file_contents, dest_dump)
+ None, None, exp_dump_file_contents, dest_dump)
def run_test(sbox, dump_file_name, subdir=None, exp_dump_file_name=None,
bypass_prop_validation=False, source_prop_encoding=None,
diff --git a/subversion/tests/cmdline/svntest/actions.py b/subversion/tests/cmdline/svntest/actions.py
index 8930b63..1051844 100644
--- a/subversion/tests/cmdline/svntest/actions.py
+++ b/subversion/tests/cmdline/svntest/actions.py
@@ -74,6 +74,11 @@ def setup_pristine_greek_repository():
if not os.path.exists(main.general_repo_dir):
os.makedirs(main.general_repo_dir) # this also creates all the intermediate dirs
+ if not os.path.exists(main.other_dav_root_dir):
+ os.makedirs(main.other_dav_root_dir)
+ if not os.path.exists(main.non_dav_root_dir):
+ os.makedirs(main.non_dav_root_dir)
+
# If there's no pristine repos, create one.
if not os.path.exists(main.pristine_greek_repos_dir):
if main.options.fsfs_version is not None:
diff --git a/subversion/tests/cmdline/svntest/main.py b/subversion/tests/cmdline/svntest/main.py
index 09a9722..4aa6041 100644
--- a/subversion/tests/cmdline/svntest/main.py
+++ b/subversion/tests/cmdline/svntest/main.py
@@ -56,7 +56,7 @@ import svntest
from svntest import Failure
from svntest import Skip
-SVN_VER_MINOR = 10
+SVN_VER_MINOR = 11
######################################################################
#
@@ -224,6 +224,10 @@ SVN_PROP_INHERITABLE_IGNORES = "svn:global-ignores"
general_repo_dir = os.path.join(work_dir, "repositories")
general_wc_dir = os.path.join(work_dir, "working_copies")
+# Directories used for DAV tests
+other_dav_root_dir = os.path.join(work_dir, "fsdavroot")
+non_dav_root_dir = os.path.join(work_dir, "nodavroot")
+
# temp directory in which we will create our 'pristine' local
# repository and other scratch data. This should be removed when we
# quit and when we startup.
@@ -978,7 +982,8 @@ def file_write(path, contents, mode='w'):
which is (w)rite by default."""
if sys.version_info < (3, 0):
- open(path, mode).write(contents)
+ with open(path, mode) as f:
+ f.write(contents)
else:
# Python 3: Write data in the format required by MODE, i.e. byte arrays
# to 'b' files, utf-8 otherwise."""
@@ -990,9 +995,11 @@ def file_write(path, contents, mode='w'):
contents = contents.decode("utf-8")
if isinstance(contents, str):
- codecs.open(path, mode, "utf-8").write(contents)
+ with codecs.open(path, mode, "utf-8") as f:
+ f.write(contents)
else:
- open(path, mode).write(contents)
+ with open(path, mode) as f:
+ f.write(contents)
# For making local mods to files
def file_append(path, new_text):
@@ -1008,7 +1015,8 @@ def file_append_binary(path, new_text):
def file_substitute(path, contents, new_contents):
"""Replace the CONTENTS in the file at PATH using the NEW_CONTENTS"""
fcontent = open(path, 'r').read().replace(contents, new_contents)
- open(path, 'w').write(fcontent)
+ with open(path, 'w') as f:
+ f.write(fcontent)
# For setting up authz, hooks and making other tweaks to created repos
def _post_create_repos(path, minor_version = None):
@@ -1035,7 +1043,8 @@ def _post_create_repos(path, minor_version = None):
users += (crosscheck_username + " = " + crosscheck_password + "\n")
file_append(os.path.join(path, "conf", "passwd"), users)
- if options.fs_type is None or options.fs_type == 'fsfs':
+ if options.fs_type is None or options.fs_type == 'fsfs' or \
+ options.fs_type == 'fsx':
# fsfs.conf file
if (minor_version is None or minor_version >= 6):
confpath = get_fsfs_conf_file_path(path)
@@ -1633,6 +1642,15 @@ def server_has_atomic_revprop():
def server_has_reverse_get_file_revs():
return options.server_caps.has_reverse_get_file_revs
+def python_sqlite_can_read_our_wc_db():
+ """Check if the Python builtin is capable enough to peek into wc.db"""
+ # Currently enough (1.7-1.9)
+ return svntest.sqlite3.sqlite_version_info >= (3, 6, 18)
+
+def python_sqlite_can_read_without_rowid():
+ """Check if the Python builtin is capable enough to read new rep-cache"""
+ return svntest.sqlite3.sqlite_version_info >= (3, 8, 2)
+
def is_plaintext_password_storage_disabled():
try:
predicate = re.compile("^WARNING: Plaintext password storage is enabled!")
@@ -2335,6 +2353,8 @@ def execute_tests(test_list, serial_only = False, test_name = None,
global pristine_url
global pristine_greek_repos_url
+ global other_dav_root_url
+ global non_dav_root_url
global svn_binary
global svnadmin_binary
global svnlook_binary
@@ -2414,6 +2434,10 @@ def execute_tests(test_list, serial_only = False, test_name = None,
pristine_greek_repos_dir.replace(
os.path.sep, '/'))
+ other_dav_root_url = options.test_area_url + '/fsdavroot'
+ non_dav_root_url = options.test_area_url + '/nodavroot'
+
+
if options.use_jsvn:
if options.svn_bin is None:
options.svn_bin = ''
diff --git a/subversion/tests/cmdline/svntest/mergetrees.py b/subversion/tests/cmdline/svntest/mergetrees.py
index 0cee3d2..0cee3d2 100755..100644
--- a/subversion/tests/cmdline/svntest/mergetrees.py
+++ b/subversion/tests/cmdline/svntest/mergetrees.py
diff --git a/subversion/tests/cmdline/svntest/sandbox.py b/subversion/tests/cmdline/svntest/sandbox.py
index b1c9861..cc8df2e 100644
--- a/subversion/tests/cmdline/svntest/sandbox.py
+++ b/subversion/tests/cmdline/svntest/sandbox.py
@@ -168,7 +168,8 @@ class Sandbox:
or open(self.authz_file,'r').read() != default_authz)):
tmp_authz_file = os.path.join(svntest.main.work_dir, "authz-" + self.name)
- open(tmp_authz_file, 'w').write(default_authz)
+ with open(tmp_authz_file, 'w') as f:
+ f.write(default_authz)
shutil.move(tmp_authz_file, self.authz_file)
def authz_name(self, repo_dir=None):
@@ -492,7 +493,8 @@ class Sandbox:
if not svnrdump_headers_always.match(l)]
# Ignore differences in number of blank lines between node records,
# as svnrdump puts 3 whereas svnadmin puts 2 after a replace-with-copy.
- svntest.verify.compare_dump_files(None, None,
+ svntest.verify.compare_dump_files('svnadmin dump, tweaked',
+ 'svnrdump dump, tweaked',
dumpfile_a_d_cmp,
dumpfile_r_d_cmp,
ignore_number_of_blank_lines=True)
@@ -523,20 +525,22 @@ class Sandbox:
reloaded_dumpfile_a_n = svntest.actions.run_and_verify_dump(repo_dir_a_n)
reloaded_dumpfile_a_d = svntest.actions.run_and_verify_dump(repo_dir_a_d)
reloaded_dumpfile_r_d = svntest.actions.run_and_verify_dump(repo_dir_r_d)
- svntest.verify.compare_dump_files(None, None,
+ svntest.verify.compare_dump_files('svnadmin dump no delta, loaded, dumped',
+ 'svnadmin dump --deltas, loaded, dumped',
reloaded_dumpfile_a_n,
reloaded_dumpfile_a_d,
ignore_uuid=True)
- svntest.verify.compare_dump_files(None, None,
+ svntest.verify.compare_dump_files('svnadmin dump, loaded, dumped',
+ 'svnrdump dump, loaded, dumped',
reloaded_dumpfile_a_d,
reloaded_dumpfile_r_d,
ignore_uuid=True)
# Run each dump through svndumpfilter and check for no further change.
- for dumpfile in [dumpfile_a_n,
- dumpfile_a_d,
- dumpfile_r_d
- ]:
+ for dumpfile, dumpfile_desc in [(dumpfile_a_n, 'svnadmin dump'),
+ (dumpfile_a_d, 'svnadmin dump --deltas'),
+ (dumpfile_r_d, 'svnrdump dump'),
+ ]:
### No buffer size seems to work for update_tests-2. So skip that test?
### (Its dumpfile size is ~360 KB non-delta, ~180 KB delta.)
if len(''.join(dumpfile)) > 100000:
@@ -550,7 +554,9 @@ class Sandbox:
# svndumpfilter strips them.
# Ignore differences in number of blank lines between node records,
# as svndumpfilter puts 3 instead of 2 after an add or delete record.
- svntest.verify.compare_dump_files(None, None, dumpfile, dumpfile2,
+ svntest.verify.compare_dump_files(dumpfile_desc,
+ 'after svndumpfilter include /',
+ dumpfile, dumpfile2,
expect_content_length_always=True,
ignore_empty_prop_sections=True,
ignore_number_of_blank_lines=True)
diff --git a/subversion/tests/cmdline/svntest/tree.py b/subversion/tests/cmdline/svntest/tree.py
index 6c34238..fbcbcfc 100644
--- a/subversion/tests/cmdline/svntest/tree.py
+++ b/subversion/tests/cmdline/svntest/tree.py
@@ -267,19 +267,8 @@ class SVNTreeNode:
line += "%-20s: Item(" % ("'%s'" % path.replace(os.sep, '/'))
comma = False
- mime_type = self.props.get("svn:mime-type")
- if not mime_type or mime_type.startswith("text/"):
- if self.contents is not None:
- # Escape some characters for nicer script and readability.
- # (This is error output. I guess speed is no consideration here.)
- line += "contents=\"%s\"" % (self.contents
- .replace('\n','\\n')
- .replace('"','\\"')
- .replace('\r','\\r')
- .replace('\t','\\t'))
- comma = True
- else:
- line += 'content is binary data'
+ if self.contents is not None:
+ line += "contents=" + repr(self.contents)
comma = True
if self.props:
diff --git a/subversion/tests/cmdline/svntest/verify.py b/subversion/tests/cmdline/svntest/verify.py
index 904a044..0fb7bcd 100644
--- a/subversion/tests/cmdline/svntest/verify.py
+++ b/subversion/tests/cmdline/svntest/verify.py
@@ -150,8 +150,9 @@ class ExpectedOutput(object):
MESSAGE unless it is None, the expected lines, the ACTUAL lines,
and a diff, all labeled with LABEL.
"""
- display_lines(message, self.expected, actual, label, label)
- display_lines_diff(self.expected, actual, label, label)
+ e_label = label + ' (match_all=%s)' % (self.match_all,)
+ display_lines(message, self.expected, actual, e_label, label)
+ display_lines_diff(self.expected, actual, e_label, label)
class AnyOutput(ExpectedOutput):
@@ -181,12 +182,36 @@ class AnyOutput(ExpectedOutput):
logger.warn(message)
+def re_fullmatch(pattern, string, flags=0):
+ """If the whole STRING matches the regular expression PATTERN,
+ return a corresponding match object.
+ Based on re.fullmatch() in Python 3.4.
+ """
+ if pattern.endswith('$'):
+ return re.match(pattern, string, flags)
+
+ return re.match(pattern + '$', string, flags)
+
+def regex_fullmatch(rx, string):
+ """If the whole STRING matches the compiled regular expression RX,
+ return a corresponding match object.
+ Based on regex.fullmatch() in Python 3.4.
+ """
+ if rx.pattern.endswith('$'):
+ return rx.match(string)
+
+ return re_fullmatch(rx.pattern, string, rx.flags)
+
class RegexOutput(ExpectedOutput):
"""Matches a single regular expression.
If MATCH_ALL is true, every actual line must match the RE. If
MATCH_ALL is false, at least one actual line must match the RE. In
any case, there must be at least one line of actual output.
+
+ The RE must match a prefix of the actual line, in contrast to the
+ RegexListOutput and UnorderedRegexListOutput classes which match
+ whole lines.
"""
def __init__(self, expected, match_all=True):
@@ -212,7 +237,8 @@ class RegexOutput(ExpectedOutput):
return any(self.expected_re.match(line) for line in actual)
def display_differences(self, message, label, actual):
- display_lines(message, self.expected, actual, label + ' (regexp)', label)
+ e_label = label + ' (regexp, match_all=%s)' % (self.match_all,)
+ display_lines(message, self.expected, actual, e_label, label)
def insert(self, index, line):
self.expected.insert(index, line)
@@ -228,6 +254,9 @@ class RegexListOutput(ExpectedOutput):
ones.
In any case, there must be at least one line of actual output.
+
+ The REs must match whole actual lines, in contrast to the RegexOutput
+ class which matches a prefix of the actual line.
"""
def __init__(self, expected, match_all=True):
@@ -243,18 +272,37 @@ class RegexListOutput(ExpectedOutput):
if self.match_all:
return (len(self.expected_res) == len(actual) and
- all(e.match(a) for e, a in zip(self.expected_res, actual)))
+ all(regex_fullmatch(e, a) for e, a in zip(self.expected_res, actual)))
i_expected = 0
for actual_line in actual:
- if self.expected_res[i_expected].match(actual_line):
+ if regex_fullmatch(self.expected_res[i_expected], actual_line):
i_expected += 1
if i_expected == len(self.expected_res):
return True
return False
def display_differences(self, message, label, actual):
- display_lines(message, self.expected, actual, label + ' (regexp)', label)
+ e_label = label + ' (regexp, match_all=%s)' % (self.match_all,)
+ display_lines(message, self.expected, actual, e_label, label)
+
+ assert actual is not None
+ if not isinstance(actual, list):
+ actual = [actual]
+
+ if self.match_all:
+ logger.warn('DIFF ' + label + ':')
+ if len(self.expected) != len(actual):
+ logger.warn('# Expected %d lines; actual %d lines' %
+ (len(self.expected), len(actual)))
+ for e, a in map(None, self.expected_res, actual):
+ if e is not None and a is not None and regex_fullmatch(e, a):
+ logger.warn("| " + a.rstrip())
+ else:
+ if e is not None:
+ logger.warn("| -" + repr(e.pattern))
+ if a is not None:
+ logger.warn("| +" + repr(a))
def insert(self, index, line):
self.expected.insert(index, line)
@@ -279,8 +327,9 @@ class UnorderedOutput(ExpectedOutput):
return sorted(self.expected) == sorted(actual)
def display_differences(self, message, label, actual):
- display_lines(message, self.expected, actual, label + ' (unordered)', label)
- display_lines_diff(self.expected, actual, label + ' (unordered)', label)
+ e_label = label + ' (unordered)'
+ display_lines(message, self.expected, actual, e_label, label)
+ display_lines_diff(sorted(self.expected), sorted(actual), e_label, label)
class UnorderedRegexListOutput(ExpectedOutput):
@@ -295,6 +344,9 @@ class UnorderedRegexListOutput(ExpectedOutput):
expressions. The implementation matches each expression in turn to
the first unmatched actual line that it can match, and does not try
all the permutations when there are multiple possible matches.
+
+ The REs must match whole actual lines, in contrast to the RegexOutput
+ class which matches a prefix of the actual line.
"""
def __init__(self, expected):
@@ -305,13 +357,16 @@ class UnorderedRegexListOutput(ExpectedOutput):
assert actual is not None
if not isinstance(actual, list):
actual = [actual]
+ else:
+ # copy the list so we can remove elements without affecting caller
+ actual = actual[:]
if len(self.expected) != len(actual):
return False
for e in self.expected:
expect_re = re.compile(e)
for actual_line in actual:
- if expect_re.match(actual_line):
+ if regex_fullmatch(expect_re, actual_line):
actual.remove(actual_line)
break
else:
@@ -320,9 +375,30 @@ class UnorderedRegexListOutput(ExpectedOutput):
return True
def display_differences(self, message, label, actual):
- display_lines(message, self.expected, actual,
- label + ' (regexp) (unordered)', label)
+ e_label = label + ' (regexp) (unordered)'
+ display_lines(message, self.expected, actual, e_label, label)
+
+ assert actual is not None
+ if not isinstance(actual, list):
+ actual = [actual]
+ else:
+ # copy the list so we can remove elements without affecting caller
+ actual = actual[:]
+ logger.warn('DIFF ' + label + ':')
+ if len(self.expected) != len(actual):
+ logger.warn('# Expected %d lines; actual %d lines' %
+ (len(self.expected), len(actual)))
+ for e in self.expected:
+ expect_re = re.compile(e)
+ for actual_line in actual:
+ if regex_fullmatch(expect_re, actual_line):
+ actual.remove(actual_line)
+ break
+ else:
+ logger.warn("| -" + expect_re.pattern.rstrip())
+ for a in actual:
+ logger.warn("| +" + a.rstrip())
class AlternateOutput(ExpectedOutput):
"""Matches any one of a list of ExpectedOutput instances.
@@ -730,7 +806,8 @@ class DumpParser:
self.parse_all_revisions()
return self.parsed
-def compare_dump_files(message, label, expected, actual,
+def compare_dump_files(label_expected, label_actual,
+ expected, actual,
ignore_uuid=False,
expect_content_length_always=False,
ignore_empty_prop_sections=False,
@@ -772,6 +849,8 @@ def compare_dump_files(message, label, expected, actual,
if parsed_expected != parsed_actual:
print('DIFF of raw dumpfiles (including expected differences)')
+ print('--- ' + (label_expected or 'expected'))
+ print('+++ ' + (label_actual or 'actual'))
print(''.join(ndiff(expected, actual)))
raise svntest.Failure('DIFF of parsed dumpfiles (ignoring expected differences)\n'
+ '\n'.join(ndiff(
diff --git a/subversion/tests/cmdline/svntest/wc.py b/subversion/tests/cmdline/svntest/wc.py
index f805dc9..ddfc439 100644
--- a/subversion/tests/cmdline/svntest/wc.py
+++ b/subversion/tests/cmdline/svntest/wc.py
@@ -1092,8 +1092,7 @@ def svn_uri_quote(url):
def python_sqlite_can_read_wc():
"""Check if the Python builtin is capable enough to peek into wc.db"""
- # Currently enough (1.7-1.9)
- return svntest.sqlite3.sqlite_version_info >= (3, 6, 18)
+ return svntest.main.python_sqlite_can_read_our_wc_db()
def open_wc_db(local_path):
"""Open the SQLite DB for the WC path LOCAL_PATH.
diff --git a/subversion/tests/cmdline/svnversion_tests.py b/subversion/tests/cmdline/svnversion_tests.py
index 2ed6e46..e9d0927 100755
--- a/subversion/tests/cmdline/svnversion_tests.py
+++ b/subversion/tests/cmdline/svnversion_tests.py
@@ -71,9 +71,8 @@ def svnversion_test(sbox):
expected_output = wc.State(wc_dir, {'A/mu' : Item(verb='Sending')})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/mu', wc_rev=2)
- if svntest.actions.run_and_verify_commit(wc_dir,
- expected_output, expected_status):
- raise svntest.Failure
+ svntest.actions.run_and_verify_commit(wc_dir,
+ expected_output, expected_status)
# Unmodified, mixed
svntest.actions.run_and_verify_svnversion(wc_dir, repo_url,
@@ -98,13 +97,12 @@ def svnversion_test(sbox):
+ 'appended mu text')
expected_disk.tweak('iota',
contents=expected_disk.desc['A/D/gamma'].contents)
- if svntest.actions.run_and_verify_switch(wc_dir, iota_path, gamma_url,
- expected_output,
- expected_disk,
- expected_status,
- [],
- False, '--ignore-ancestry'):
- raise svntest.Failure
+ svntest.actions.run_and_verify_switch(wc_dir, iota_path, gamma_url,
+ expected_output,
+ expected_disk,
+ expected_status,
+ [],
+ False, '--ignore-ancestry')
# Prop modified, mixed, part wc switched
svntest.actions.run_and_verify_svnversion(wc_dir, repo_url,
diff --git a/subversion/tests/cmdline/trans_tests.py b/subversion/tests/cmdline/trans_tests.py
index 0cab75e..71ca45e 100755
--- a/subversion/tests/cmdline/trans_tests.py
+++ b/subversion/tests/cmdline/trans_tests.py
@@ -814,7 +814,8 @@ def props_only_file_update(sbox):
]
# Create r2 with iota's contents and svn:keywords modified
- open(iota_path, 'w').writelines(content)
+ with open(iota_path, 'w') as f:
+ f.writelines(content)
svntest.main.run_svn(None, 'propset', 'svn:keywords', 'Author', iota_path)
expected_output = wc.State(wc_dir, {
@@ -831,7 +832,8 @@ def props_only_file_update(sbox):
# Create r3 that drops svn:keywords
# put the content back to its untranslated form
- open(iota_path, 'w').writelines(content)
+ with open(iota_path, 'w') as f:
+ f.writelines(content)
svntest.main.run_svn(None, 'propdel', 'svn:keywords', iota_path)
diff --git a/subversion/tests/cmdline/tree_conflict_tests.py b/subversion/tests/cmdline/tree_conflict_tests.py
index b3335b2..61f3231 100755
--- a/subversion/tests/cmdline/tree_conflict_tests.py
+++ b/subversion/tests/cmdline/tree_conflict_tests.py
@@ -473,6 +473,7 @@ def ensure_tree_conflict(sbox, operation,
run_and_verify_svn(expected_stdout, [],
'merge',
'--allow-mixed-revisions',
+ '--accept=postpone',
'-r', str(source_left_rev) + ':' + str(source_right_rev),
source_url, target_path)
else:
@@ -1096,13 +1097,15 @@ def at_directory_external(sbox):
svntest.main.run_svn(None, 'update', wc_dir)
# r3: modify ^/A/B/E/alpha
- open(sbox.ospath('A/B/E/alpha'), 'a').write('This is still A/B/E/alpha.\n')
+ with open(sbox.ospath('A/B/E/alpha'), 'a') as f:
+ f.write('This is still A/B/E/alpha.\n')
svntest.main.run_svn(None, 'commit', '-m', 'file mod', wc_dir)
svntest.main.run_svn(None, 'update', wc_dir)
merge_rev = svntest.main.youngest(sbox.repo_dir)
# r4: create ^/A/B/E/alpha2
- open(sbox.ospath('A/B/E/alpha2'), 'a').write("This is the file 'alpha2'.\n")
+ with open(sbox.ospath('A/B/E/alpha2'), 'a') as f:
+ f.write("This is the file 'alpha2'.\n")
svntest.main.run_svn(None, 'add', sbox.ospath('A/B/E/alpha2'))
svntest.main.run_svn(None, 'commit', '-m', 'file add', wc_dir)
svntest.main.run_svn(None, 'update', wc_dir)
@@ -1503,6 +1506,47 @@ def update_delete_mixed_rev(sbox):
}
run_and_verify_info([expected_info], sbox.repo_url + '/A/B/E/alpha2')
+# NB: This test will run forever if the bug it is testing for is present!
+def local_missing_dir_endless_loop(sbox):
+ "endless loop when resolving local-missing dir"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ sbox.simple_copy('A', 'A1')
+ sbox.simple_commit()
+ sbox.simple_update()
+ sbox.simple_move('A/B', 'A/B2')
+ sbox.simple_commit()
+ sbox.simple_update()
+ main.file_append_binary(sbox.ospath("A/B2/lambda"), "This is more content.\n")
+ sbox.simple_commit()
+ sbox.simple_update()
+
+ # Create a config which enables the interactive conflict resolver
+ config_contents = '''\
+[auth]
+password-stores =
+
+[miscellany]
+interactive-conflicts = true
+'''
+ config_dir = sbox.create_config_dir(config_contents)
+
+ # Bug: 'svn' keeps retrying interactive conflict resolution while the library
+ # keeps signalling 'SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE' -> endless loop
+ main.run_svn("Tree conflict on '%s'" % sbox.ospath("A1/B2"),
+ 'merge', '-c4', '^/A', sbox.ospath('A1'),
+ '--config-dir', config_dir, '--force-interactive')
+
+ # If everything works as expected the resolver will recommended a
+ # resolution option and 'svn' will resolve the conflict automatically.
+ # Verify that 'A1/B/lambda' contains the merged content:
+ contents = open(sbox.ospath('A1/B/lambda'), 'rb').readlines()
+ svntest.verify.compare_and_display_lines(
+ "A1/B/lambda has unexpectected contents", sbox.ospath("A1/B/lambda"),
+ [ "This is the file 'lambda'.\n", "This is more content.\n"], contents)
+
+
#######################################################################
# Run the tests
@@ -1534,6 +1578,7 @@ test_list = [ None,
actual_only_node_behaviour,
update_dir_with_not_present,
update_delete_mixed_rev,
+ local_missing_dir_endless_loop,
]
if __name__ == '__main__':
diff --git a/subversion/tests/cmdline/update_tests.py b/subversion/tests/cmdline/update_tests.py
index 16c7237..185fcb1 100755
--- a/subversion/tests/cmdline/update_tests.py
+++ b/subversion/tests/cmdline/update_tests.py
@@ -480,7 +480,7 @@ def update_to_rev_zero(sbox):
def receive_overlapping_same_change(sbox):
"overlapping identical changes should not conflict"
- ### (See http://subversion.tigris.org/issues/show_bug.cgi?id=682.)
+ ### (See https://issues.apache.org/jira/browse/SVN-682.)
###
### How this test works:
###
@@ -6719,6 +6719,7 @@ def update_conflict_details(sbox):
# Keywords should be updated in local file even if text change is shortcut
# (due to the local change being the same as the incoming change, for example).
@XFail()
+@Issue(4585)
def update_keywords_on_shortcut(sbox):
"update_keywords_on_shortcut"
diff --git a/subversion/tests/cmdline/upgrade_tests.py b/subversion/tests/cmdline/upgrade_tests.py
index 43258f6..c60dab5 100755
--- a/subversion/tests/cmdline/upgrade_tests.py
+++ b/subversion/tests/cmdline/upgrade_tests.py
@@ -392,7 +392,8 @@ def xml_entries_relocate(path, from_url, to_url):
entries = os.path.join(path, adm_name, 'entries')
txt = open(entries).read().replace('url="' + from_url, 'url="' + to_url)
os.chmod(entries, svntest.main.S_ALL_RWX)
- open(entries, 'w').write(txt)
+ with open(entries, 'w') as f:
+ f.write(txt)
for dirent in os.listdir(path):
item_path = os.path.join(path, dirent)
@@ -410,7 +411,8 @@ def simple_entries_replace(path, from_url, to_url):
entries = os.path.join(path, adm_name, 'entries')
txt = open(entries).read().replace(from_url, to_url)
os.chmod(entries, svntest.main.S_ALL_RWX)
- open(entries, 'wb').write(txt.encode())
+ with open(entries, 'wb') as f:
+ f.write(txt.encode())
for dirent in os.listdir(path):
item_path = os.path.join(path, dirent)