summaryrefslogtreecommitdiff
path: root/subversion/tests/cmdline/svntest
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/tests/cmdline/svntest')
-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
7 files changed, 144 insertions, 42 deletions
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.