diff options
Diffstat (limited to 'subversion/tests/cmdline/svntest')
-rw-r--r-- | subversion/tests/cmdline/svntest/actions.py | 5 | ||||
-rw-r--r-- | subversion/tests/cmdline/svntest/main.py | 36 | ||||
-rw-r--r--[-rwxr-xr-x] | subversion/tests/cmdline/svntest/mergetrees.py | 0 | ||||
-rw-r--r-- | subversion/tests/cmdline/svntest/sandbox.py | 24 | ||||
-rw-r--r-- | subversion/tests/cmdline/svntest/tree.py | 15 | ||||
-rw-r--r-- | subversion/tests/cmdline/svntest/verify.py | 103 | ||||
-rw-r--r-- | subversion/tests/cmdline/svntest/wc.py | 3 |
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. |