Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/mergetrees.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/mergetrees.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/mergetrees.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/mergetrees.py Tue Oct 11 09:11:50 2016 @@ -29,7 +29,7 @@ import shutil, sys, re, os import time # Our testing module -import main, wc, verify, actions, testcase +from svntest import main, wc, verify, actions, testcase from prop_tests import binary_mime_type_on_text_file_warning
Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/objects.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/objects.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/objects.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/objects.py Tue Oct 11 09:11:50 2016 @@ -127,7 +127,7 @@ def locate_db_dump(): try: if subprocess.Popen([db_dump_name, "-V"]).wait() == 0: return db_dump_name - except OSError, e: + except OSError as e: pass return 'none' Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/sandbox.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/sandbox.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/sandbox.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/sandbox.py Tue Oct 11 09:11:50 2016 @@ -434,7 +434,8 @@ class Sandbox: def simple_append(self, dest, contents, truncate=False): """Append CONTENTS to file DEST, optionally truncating it first. DEST is a relpath relative to the WC.""" - open(self.ospath(dest), truncate and 'wb' or 'ab').write(contents) + svntest.main.file_write(self.ospath(dest), contents, + truncate and 'wb' or 'ab') def simple_lock(self, *targets): """Lock TARGETS in the WC. Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/testcase.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/testcase.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/testcase.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/testcase.py Tue Oct 11 09:11:50 2016 @@ -141,9 +141,9 @@ class FunctionTestCase(TestCase): # docstring on it. assert isinstance(func, types.FunctionType) - name = func.func_name + name = func.__name__ - assert func.func_code.co_argcount == 1, \ + assert func.__code__.co_argcount == 1, \ '%s must take an sbox argument' % name doc = func.__doc__.strip() @@ -165,13 +165,13 @@ class FunctionTestCase(TestCase): self.skip_cross_check = skip_cross_check def get_function_name(self): - return self.func.func_name + return self.func.__name__ def get_sandbox_name(self): """Base the sandbox's name on the name of the file in which the function was defined.""" - filename = self.func.func_code.co_filename + filename = self.func.__code__.co_filename return os.path.splitext(os.path.basename(filename))[0] def run(self, sandbox): Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/tree.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/tree.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/tree.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/tree.py Tue Oct 11 09:11:50 2016 @@ -499,6 +499,7 @@ def create_from_path(path, contents=None eol_re = re.compile(r'(\r\n|\r)') +eol_re_binary = re.compile(br'(\r\n|\r)') # helper for build_tree_from_wc() def get_props(paths): @@ -544,7 +545,10 @@ def get_props(paths): # contains a CR character XML-encoded as ' '. The XML # parser converts it back into a CR character. So again convert # all end-of-line variants into a single LF: - value = eol_re.sub('\n', value) + if isinstance(value, str): + value = eol_re.sub('\n', value) + else: + value = eol_re_binary.sub(b'\n', value) file_props[name] = value files[filename] = file_props @@ -715,7 +719,7 @@ def _dump_tree(n,indent="",stream=sys.st the SVNTreeNode N. Prefix each line with the string INDENT.""" # Code partially stolen from Dave Beazley - tmp_children = sorted(n.children or []) + tmp_children = sorted(n.children or [], key=SVNTreeNode.get_printable_path) if n.name == root_node_name: stream.write("%s%s\n" % (indent, "ROOT")) @@ -862,10 +866,16 @@ def build_tree_from_diff_summarize(lines # process for every file and dir in the working copy! -def build_tree_from_wc(wc_path, load_props=0, ignore_svn=1): +def build_tree_from_wc(wc_path, load_props=0, ignore_svn=1, keep_eol_style=False): """Takes WC_PATH as the path to a working copy. Walks the tree below that path, and creates the tree based on the actual found files. If IGNORE_SVN is true, then exclude SVN admin dirs from the tree. - If LOAD_PROPS is true, the props will be added to the tree.""" + If LOAD_PROPS is true, the props will be added to the tree. + + If KEEP_EOL_STYLE is set, don't let Python normalize the EOL when + reading working copy contents as text files. It has no effect on + binary files. + """ - return svntest.wc.State.from_wc(wc_path, load_props, ignore_svn).old_tree() + return svntest.wc.State.from_wc(wc_path, load_props, ignore_svn, + keep_eol_style).old_tree() Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/verify.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/verify.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/verify.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/verify.py Tue Oct 11 09:11:50 2016 @@ -189,7 +189,7 @@ class RegexOutput(ExpectedOutput): def __init__(self, expected, match_all=True): "EXPECTED is a regular expression string." - assert isinstance(expected, str) + assert isinstance(expected, str) or isinstance(expected, bytes) ExpectedOutput.__init__(self, expected, match_all) self.expected_re = re.compile(expected) @@ -416,9 +416,10 @@ def compare_and_display_lines(message, l if not isinstance(expected, ExpectedOutput): expected = ExpectedOutput(expected) - if isinstance(actual, str): - actual = [actual] - actual = svntest.main.filter_dbg(actual) + actual = svntest.main.ensure_list(actual) + if len(actual) > 0: + is_binary = not isinstance(actual[0], str) + actual = svntest.main.filter_dbg(actual, is_binary) if not expected.matches(actual): expected.display_differences(message, label, actual) @@ -484,7 +485,7 @@ class DumpParser: return m.group(1) def parse_blank(self, required=True): - if self.lines[self.current] != '\n': # Works on Windows + if self.lines[self.current] != b'\n': # Works on Windows if required: raise SVNDumpParseError("expected blank at line %d\n%s" % (self.current, self.lines[self.current])) @@ -494,7 +495,7 @@ class DumpParser: return True def parse_header(self, header): - regex = '([^:]*): (.*)$' + regex = b'([^:]*): (.*)$' m = re.match(regex, self.lines[self.current]) if not m: raise SVNDumpParseError("expected a header at line %d, but found:\n%s" @@ -504,80 +505,80 @@ class DumpParser: def parse_headers(self): headers = [] - while self.lines[self.current] != '\n': + while self.lines[self.current] != b'\n': key, val = self.parse_header(self) headers.append((key, val)) return headers def parse_boolean(self, header, required): - return self.parse_line(header + ': (false|true)$', required) + return self.parse_line(header + b': (false|true)$', required) def parse_format(self): - return self.parse_line('SVN-fs-dump-format-version: ([0-9]+)$') + return self.parse_line(b'SVN-fs-dump-format-version: ([0-9]+)$') def parse_uuid(self): - return self.parse_line('UUID: ([0-9a-z-]+)$') + return self.parse_line(b'UUID: ([0-9a-z-]+)$') def parse_revision(self): - return self.parse_line('Revision-number: ([0-9]+)$') + return self.parse_line(b'Revision-number: ([0-9]+)$') def parse_prop_delta(self): - return self.parse_line('Prop-delta: (false|true)$', required=False) + return self.parse_line(b'Prop-delta: (false|true)$', required=False) def parse_prop_length(self, required=True): - return self.parse_line('Prop-content-length: ([0-9]+)$', required) + return self.parse_line(b'Prop-content-length: ([0-9]+)$', required) def parse_content_length(self, required=True): - return self.parse_line('Content-length: ([0-9]+)$', required) + return self.parse_line(b'Content-length: ([0-9]+)$', required) def parse_path(self): - path = self.parse_line('Node-path: (.*)$', required=False) + path = self.parse_line(b'Node-path: (.*)$', required=False) return path def parse_kind(self): - return self.parse_line('Node-kind: (.+)$', required=False) + return self.parse_line(b'Node-kind: (.+)$', required=False) def parse_action(self): - return self.parse_line('Node-action: ([0-9a-z-]+)$') + return self.parse_line(b'Node-action: ([0-9a-z-]+)$') def parse_copyfrom_rev(self): - return self.parse_line('Node-copyfrom-rev: ([0-9]+)$', required=False) + return self.parse_line(b'Node-copyfrom-rev: ([0-9]+)$', required=False) def parse_copyfrom_path(self): - path = self.parse_line('Node-copyfrom-path: (.+)$', required=False) + path = self.parse_line(b'Node-copyfrom-path: (.+)$', required=False) if not path and self.lines[self.current] == 'Node-copyfrom-path: \n': self.current += 1 path = '' return path def parse_copy_md5(self): - return self.parse_line('Text-copy-source-md5: ([0-9a-z]+)$', required=False) + return self.parse_line(b'Text-copy-source-md5: ([0-9a-z]+)$', required=False) def parse_copy_sha1(self): - return self.parse_line('Text-copy-source-sha1: ([0-9a-z]+)$', required=False) + return self.parse_line(b'Text-copy-source-sha1: ([0-9a-z]+)$', required=False) def parse_text_md5(self): - return self.parse_line('Text-content-md5: ([0-9a-z]+)$', required=False) + return self.parse_line(b'Text-content-md5: ([0-9a-z]+)$', required=False) def parse_text_sha1(self): - return self.parse_line('Text-content-sha1: ([0-9a-z]+)$', required=False) + return self.parse_line(b'Text-content-sha1: ([0-9a-z]+)$', required=False) def parse_text_delta(self): - return self.parse_line('Text-delta: (false|true)$', required=False) + return self.parse_line(b'Text-delta: (false|true)$', required=False) def parse_text_delta_base_md5(self): - return self.parse_line('Text-delta-base-md5: ([0-9a-f]+)$', required=False) + return self.parse_line(b'Text-delta-base-md5: ([0-9a-f]+)$', required=False) def parse_text_delta_base_sha1(self): - return self.parse_line('Text-delta-base-sha1: ([0-9a-f]+)$', required=False) + return self.parse_line(b'Text-delta-base-sha1: ([0-9a-f]+)$', required=False) def parse_text_length(self): - return self.parse_line('Text-content-length: ([0-9]+)$', required=False) + return self.parse_line(b'Text-content-length: ([0-9]+)$', required=False) def get_props(self): props = [] - while not re.match('PROPS-END$', self.lines[self.current]): + while not re.match(b'PROPS-END$', self.lines[self.current]): props.append(self.lines[self.current]) self.current += 1 self.current += 1 @@ -593,7 +594,7 @@ class DumpParser: curprop[0] += 1 # key / value - key = '' + key = b'' while len(key) != klen + 1: key += props[curprop[0]] curprop[0] += 1 @@ -601,10 +602,10 @@ class DumpParser: return key - if props[curprop[0]].startswith('K'): + if props[curprop[0]].startswith(b'K'): key = read_key_or_value(curprop) value = read_key_or_value(curprop) - elif props[curprop[0]].startswith('D'): + elif props[curprop[0]].startswith(b'D'): key = read_key_or_value(curprop) value = None else: @@ -614,7 +615,7 @@ class DumpParser: return prophash def get_content(self, length): - content = '' + content = b'' while len(content) < length: content += self.lines[self.current] self.current += 1 @@ -637,22 +638,22 @@ class DumpParser: headers = dict(headers_list) # Content-length must be last, if present - if 'Content-length' in headers and headers_list[-1][0] != 'Content-length': + if b'Content-length' in headers and headers_list[-1][0] != b'Content-length': raise SVNDumpParseError("'Content-length' header is not last, " "in header block ending at line %d" % (self.current,)) # parse the remaining optional headers and store in specific keys in NODE for key, header, regex in [ - ('copyfrom_rev', 'Node-copyfrom-rev', '([0-9]+)$'), - ('copyfrom_path', 'Node-copyfrom-path', '(.*)$'), - ('copy_md5', 'Text-copy-source-md5', '([0-9a-z]+)$'), - ('copy_sha1', 'Text-copy-source-sha1','([0-9a-z]+)$'), - ('prop_length', 'Prop-content-length', '([0-9]+)$'), - ('text_length', 'Text-content-length', '([0-9]+)$'), - ('text_md5', 'Text-content-md5', '([0-9a-z]+)$'), - ('text_sha1', 'Text-content-sha1', '([0-9a-z]+)$'), - ('content_length', 'Content-length', '([0-9]+)$'), + ('copyfrom_rev', b'Node-copyfrom-rev', b'([0-9]+)$'), + ('copyfrom_path', b'Node-copyfrom-path', b'(.*)$'), + ('copy_md5', b'Text-copy-source-md5', b'([0-9a-z]+)$'), + ('copy_sha1', b'Text-copy-source-sha1',b'([0-9a-z]+)$'), + ('prop_length', b'Prop-content-length', b'([0-9]+)$'), + ('text_length', b'Text-content-length', b'([0-9]+)$'), + ('text_md5', b'Text-content-md5', b'([0-9a-z]+)$'), + ('text_sha1', b'Text-content-sha1', b'([0-9a-z]+)$'), + ('content_length', b'Content-length', b'([0-9]+)$'), ]: if not header in headers: node[key] = None @@ -743,7 +744,7 @@ def compare_dump_files(message, label, e for parsed in [parsed_expected, parsed_actual]: for rev_name, rev_record in parsed.items(): #print "Found %s" % (rev_name,) - if 'nodes' in rev_record: + if b'nodes' in rev_record: #print "Found %s.%s" % (rev_name, 'nodes') for path_name, path_record in rev_record['nodes'].items(): #print "Found %s.%s.%s" % (rev_name, 'nodes', path_name) @@ -765,8 +766,8 @@ def compare_dump_files(message, label, e action_record['blanks'] = 0 if parsed_expected != parsed_actual: - print 'DIFF of raw dumpfiles (including expected differences)' - print ''.join(ndiff(expected, actual)) + print('DIFF of raw dumpfiles (including expected differences)') + print(''.join(ndiff(expected, actual))) raise svntest.Failure('DIFF of parsed dumpfiles (ignoring expected differences)\n' + '\n'.join(ndiff( pprint.pformat(parsed_expected).splitlines(), Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/wc.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/wc.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/wc.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/wc.py Tue Oct 11 09:11:50 2016 @@ -26,16 +26,17 @@ import os import sys import re -import urllib import logging import pprint if sys.version_info[0] >= 3: # Python >=3.0 from io import StringIO + from urllib.parse import quote as urllib_quote else: # Python <3.0 from cStringIO import StringIO + from urllib import quote as urllib_quote import svntest @@ -172,7 +173,7 @@ class State: "Remove PATHS recursively from the state (the paths must exist)." for subtree_path in paths: subtree_path = to_relpath(subtree_path) - for path, item in self.desc.items(): + for path, item in svntest.main.ensure_list(self.desc.items()): if path == subtree_path or path[:len(subtree_path) + 1] == subtree_path + '/': del self.desc[path] @@ -201,7 +202,7 @@ class State: for path in args: try: path_ref = self.desc[to_relpath(path)] - except KeyError, e: + except KeyError as e: e.args = ["Path '%s' not present in WC state descriptor" % path] raise path_ref.tweak(**kw) @@ -225,13 +226,13 @@ class State: """ temp = {} - for src, dst in sorted(moves.items(), key=lambda (src, dst): src)[::-1]: + for src, dst in sorted(moves.items(), key=lambda pair: pair[0])[::-1]: temp[src] = {} - for path, item in self.desc.items(): + for path, item in svntest.main.ensure_list(self.desc.items()): if path == src or path[:len(src) + 1] == src + '/': temp[src][path] = item; del self.desc[path] - for src, dst in sorted(moves.items(), key=lambda (src, dst): dst): + for src, dst in sorted(moves.items(), key=lambda pair: pair[1]): for path, item in temp[src].items(): if path == src: new_path = dst @@ -273,7 +274,7 @@ class State: os.makedirs(dirpath) # write out the file contents now - open(fullpath, 'wb').write(item.contents) + svntest.main.file_write(fullpath, item.contents, 'wb') def normalize(self): """Return a "normalized" version of self. @@ -380,7 +381,7 @@ class State: def tweak_for_entries_compare(self): for path, item in self.desc.copy().items(): - if item.status: + if item.status and path in self.desc: # If this is an unversioned tree-conflict, remove it. # These are only in their parents' THIS_DIR, they don't have entries. if item.status[0] in '!?' and item.treeconflict == 'C' and \ @@ -656,13 +657,18 @@ class State: return cls('', desc) @classmethod - def from_wc(cls, base, load_props=False, ignore_svn=True): + def from_wc(cls, base, load_props=False, ignore_svn=True, + keep_eol_style=False): """Create a State object from a working copy. Walks the tree at PATH, building a State based on the actual files and directories found. If LOAD_PROPS is True, then the properties will be loaded for all nodes (Very Expensive!). If IGNORE_SVN is True, then the .svn subdirectories will be excluded from the State. + + If KEEP_EOL_STYLE is set, don't let Python normalize the EOL when + reading working copy contents as text files. It has no effect on + binary files. """ if not base: # we're going to walk the base, and the OS wants "." @@ -678,7 +684,13 @@ class State: for name in dirs + files: node = os.path.join(dirpath, name) if os.path.isfile(node): - contents = open(node, 'r').read() + try: + if keep_eol_style: + contents = open(node, 'r', newline='').read() + else: + contents = open(node, 'r').read() + except: + contents = open(node, 'rb').read() else: contents = None desc[repos_join(parent, name)] = StateItem(contents=contents) @@ -1073,7 +1085,7 @@ def repos_join(base, path): def svn_uri_quote(url): # svn defines a different set of "safe" characters than Python does, so # we need to avoid escaping them. see subr/path.c:uri_char_validity[] - return urllib.quote(url, "!$&'()*+,-./:=@_~") + return urllib_quote(url, "!$&'()*+,-./:=@_~") # ------------ Modified: subversion/branches/ra-git/subversion/tests/cmdline/trans_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/trans_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/trans_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/trans_tests.py Tue Oct 11 09:11:50 2016 @@ -562,9 +562,9 @@ def eol_change_is_text_mod(sbox): foo_path = os.path.join(wc_dir, 'foo') f = open(foo_path, 'wb') if svntest.main.windows: - f.write("1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n") + f.write(b"1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n") else: - f.write("1\n2\n3\n4\n5\n6\n7\n8\n9\n") + f.write(b"1\n2\n3\n4\n5\n6\n7\n8\n9\n") f.close() # commit the file @@ -591,10 +591,10 @@ def eol_change_is_text_mod(sbox): # check 2: do the files have the right contents now? contents = open(foo_path, 'rb').read() if svntest.main.windows: - if contents != "1\n2\n3\n4\n5\n6\n7\n8\n9\n": + if contents != b"1\n2\n3\n4\n5\n6\n7\n8\n9\n": raise svntest.Failure else: - if contents != "1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n": + if contents != b"1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n": raise svntest.Failure foo_base_path = svntest.wc.text_base_path(foo_path) Modified: subversion/branches/ra-git/subversion/tests/cmdline/tree_conflict_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/tree_conflict_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/tree_conflict_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/tree_conflict_tests.py Tue Oct 11 09:11:50 2016 @@ -1339,7 +1339,7 @@ def actual_only_node_behaviour(sbox): "relocate", A_copy_url + "/foo", foo_path) # resolve - expected_stdout = "Resolved conflicted state of.*foo.*" + expected_stdout = "Tree conflict at.*foo.*marked as resolved" expected_stderr = [] run_and_verify_svn(expected_stdout, expected_stderr, "resolve", "--accept", "working", foo_path) Modified: subversion/branches/ra-git/subversion/tests/cmdline/update_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/update_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/update_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/update_tests.py Tue Oct 11 09:11:50 2016 @@ -92,7 +92,7 @@ def update_binary_file(sbox): # Make a change to the binary file in the original working copy svntest.main.file_append(theta_path, "revision 3 text") - theta_contents_r3 = theta_contents + "revision 3 text" + theta_contents_r3 = theta_contents + b"revision 3 text" # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { @@ -113,7 +113,7 @@ def update_binary_file(sbox): # Make a local mod to theta svntest.main.file_append(theta_backup_path, "extra theta text") - theta_contents_local = theta_contents + "extra theta text" + theta_contents_local = theta_contents + b"extra theta text" # Create expected output tree for an update of wc_backup. expected_output = svntest.wc.State(wc_backup, { @@ -196,9 +196,9 @@ def update_binary_file_2(sbox): # Make some mods to the binary files. svntest.main.file_append(theta_path, "foobar") - new_theta_contents = theta_contents + "foobar" + new_theta_contents = theta_contents + b"foobar" svntest.main.file_append(zeta_path, "foobar") - new_zeta_contents = zeta_contents + "foobar" + new_zeta_contents = zeta_contents + b"foobar" # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { @@ -286,7 +286,7 @@ def update_binary_file_3(sbox): # Make some mods to the binary files. svntest.main.file_append(theta_path, "foobar") - new_theta_contents = theta_contents + "foobar" + new_theta_contents = theta_contents + b"foobar" # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { @@ -1657,6 +1657,9 @@ def conflict_markers_matching_eol(sbox): else: crlf = '\r\n' + # Strict EOL style matching breaks Windows tests at least with Python 2 + keep_eol_style = not svntest.main.is_os_windows() + # Checkout a second working copy wc_backup = sbox.add_wc_path('backup') svntest.actions.run_and_verify_svn(None, [], 'checkout', @@ -1757,10 +1760,11 @@ def conflict_markers_matching_eol(sbox): expected_backup_status.tweak(wc_rev = cur_rev) # Do the update and check the results in three ways. - svntest.actions.run_and_verify_update(wc_backup, - expected_backup_output, - expected_backup_disk, - expected_backup_status) + svntest.actions.run_and_verify_update2(wc_backup, + expected_backup_output, + expected_backup_disk, + expected_backup_status, + keep_eol_style=keep_eol_style) # cleanup for next run svntest.main.run_svn(None, 'revert', '-R', wc_backup) @@ -1788,6 +1792,9 @@ def update_eolstyle_handling(sbox): else: crlf = '\r\n' + # Strict EOL style matching breaks Windows tests at least with Python 2 + keep_eol_style = not svntest.main.is_os_windows() + # Checkout a second working copy wc_backup = sbox.add_wc_path('backup') svntest.actions.run_and_verify_svn(None, [], 'checkout', @@ -1814,10 +1821,11 @@ def update_eolstyle_handling(sbox): expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 2) expected_backup_status.tweak('A/mu', status='M ') - svntest.actions.run_and_verify_update(wc_backup, - expected_backup_output, - expected_backup_disk, - expected_backup_status) + svntest.actions.run_and_verify_update2(wc_backup, + expected_backup_output, + expected_backup_disk, + expected_backup_status, + keep_eol_style=keep_eol_style) # Test 2: now change the eol-style property to another value and commit, # update the still changed mu in the second working copy; there should be @@ -1839,10 +1847,11 @@ def update_eolstyle_handling(sbox): expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 3) expected_backup_status.tweak('A/mu', status='M ') - svntest.actions.run_and_verify_update(wc_backup, - expected_backup_output, - expected_backup_disk, - expected_backup_status) + svntest.actions.run_and_verify_update2(wc_backup, + expected_backup_output, + expected_backup_disk, + expected_backup_status, + keep_eol_style=keep_eol_style) # Test 3: now delete the eol-style property and commit, update the still # changed mu in the second working copy; there should be no conflict! @@ -1863,10 +1872,11 @@ def update_eolstyle_handling(sbox): expected_backup_status = svntest.actions.get_virginal_state(wc_backup, 4) expected_backup_status.tweak('A/mu', status='M ') - svntest.actions.run_and_verify_update(wc_backup, - expected_backup_output, - expected_backup_disk, - expected_backup_status) + svntest.actions.run_and_verify_update2(wc_backup, + expected_backup_output, + expected_backup_disk, + expected_backup_status, + keep_eol_style=keep_eol_style) # Bug in which "update" put a bogus revision number on a schedule-add file, # causing the wrong version of it to be committed. @@ -2710,6 +2720,7 @@ def update_with_obstructing_additions(sb expected_disk, expected_status, [], True, + '--adds-as-modification', wc_backup, extra_files=extra_files) # Some obstructions are still not permitted: @@ -2820,6 +2831,7 @@ def update_with_obstructing_additions(sb svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status, [], False, + '--adds-as-modification', A_path) # Resolve the tree conflict. @@ -2839,7 +2851,7 @@ def update_with_obstructing_additions(sb svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status, [], False, - wc_dir, '-N') + wc_dir, '-N', '--adds-as-modification') # Resolve the tree conflict. svntest.main.run_svn(None, 'resolved', omicron_path) @@ -3610,7 +3622,7 @@ def update_output_with_conflicts(rev, ta lines += ['Updated to revision %d.\n' % rev] if resolved: for path in paths: - lines += ["Resolved conflicted state of '%s'\n" % path] + lines += ["Merge conflicts in '%s' marked as resolved.\n" % path] lines += svntest.main.summary_of_conflicts(text_resolved=len(paths)) else: lines += svntest.main.summary_of_conflicts(text_conflicts=len(paths)) @@ -6343,28 +6355,37 @@ def windows_update_backslash(sbox): 'mkdir', 'A/completely\\unusable\\dir') # No error and a proper skip + recording in the working copy would also - # be a good result. This just verifies current behavior. - - if sbox.repo_url.startswith('http'): - # Apache Httpd doesn't allow paths with '\\' in them on Windows, so the - # test if a user is allowed to read them returns a failure. This makes - # mod_dav_svn report the path as server excluded (aka absent), which - # doesn't produce output when updating. - expected_output = [ - "Updating '%s':\n" % wc_dir, - "At revision 2.\n" - ] - expected_err = [] - else: - expected_output = None - expected_err = 'svn: E155000: .* is not valid.*' - - svntest.actions.run_and_verify_svn(expected_output, expected_err, - 'up', wc_dir) - - if sbox.repo_url.startswith('http'): + # be a good result. This just verifies current behavior: + # + # - Error via file://, svn:// or http:// with SVNPathAuthz short_circuit + # + # - No error via http:// with SVNPathAuthz on + # (The reason is that Apache Httpd doesn't allow paths with '\\' in + # them on Windows, and a subrequest-based access check returns 404. + # This makes mod_dav_svn report the path as server excluded (aka + # absent), which doesn't produce output when updating.) + # + # Since https://issues.apache.org/jira/browse/SVN-3288 is about a crash, + # we're fine with either result -- that is, if `svn update' finished + # without an error, we expect specific stdout and proper wc state. + # If it failed, we expect to get the following error: + # + # svn: E155000: 'completely\unusable\dir' is not valid as filename + # in directory [...] + # + exit_code, output, errput = svntest.main.run_svn(1, 'up', wc_dir) + if exit_code == 0: + verify.verify_outputs("Unexpected output", output, errput, [ + "Updating '%s':\n" % wc_dir, + "At revision 2.\n" + ], []) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) svntest.actions.run_and_verify_status(wc_dir, expected_status) + elif exit_code == 1: + verify.verify_outputs("Unexpected output", output, errput, + None, 'svn: E155000: .* is not valid.*') + else: + raise verify.SVNUnexpectedExitCode(exit_code) def update_moved_away(sbox): "update subtree of moved away" @@ -6614,7 +6635,9 @@ def update_conflict_details(sbox): prev_status=' ', prev_treeconflict='C'), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, - None, expected_status) + None, expected_status, + [], False, + '--adds-as-modification', wc_dir) # Update can't pass source as none at a specific URL@revision, # because it doesn't know... the working copy could be mixed Modified: subversion/branches/ra-git/subversion/tests/cmdline/upgrade_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/upgrade_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/upgrade_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/upgrade_tests.py Tue Oct 11 09:11:50 2016 @@ -36,6 +36,7 @@ import sys import tarfile import tempfile import logging +import stat logger = logging.getLogger() @@ -63,7 +64,7 @@ def replace_sbox_with_tarfile(sbox, tar_ dir=None): try: svntest.main.safe_rmtree(sbox.wc_dir) - except OSError, e: + except OSError as e: pass if not dir: @@ -81,7 +82,7 @@ def replace_sbox_with_tarfile(sbox, tar_ def replace_sbox_repo_with_tarfile(sbox, tar_filename, dir=None): try: svntest.main.safe_rmtree(sbox.repo_dir) - except OSError, e: + except OSError as e: pass if not dir: @@ -130,7 +131,7 @@ def check_dav_cache(dir_path, wc_id, exp # Check if python's sqlite can read our db c.execute('select sqlite_version()') - sqlite_ver = map(int, c.fetchone()[0].split('.')) + sqlite_ver = svntest.main.ensure_list(map(int, c.fetchone()[0].split('.'))) # SQLite versions have 3 or 4 number groups major = sqlite_ver[0] @@ -157,7 +158,7 @@ def check_dav_cache(dir_path, wc_id, exp if row is None: raise svntest.Failure("no dav cache for '%s'" % (local_relpath)) dav_cache = str(row[0]) - if dav_cache != expected_dav_cache: + if dav_cache != str(expected_dav_cache): raise svntest.Failure( "wrong dav cache for '%s'\n Found: '%s'\n Expected: '%s'" % (local_relpath, dav_cache, expected_dav_cache)) @@ -378,9 +379,9 @@ def upgrade_wcprops(sbox): # to be. (This could be smarter.) expected_dav_caches = { '' : - '(svn:wc:ra_dav:version-url 41 /svn-test-work/local_tmp/repos/!svn/ver/1)', + b'(svn:wc:ra_dav:version-url 41 /svn-test-work/local_tmp/repos/!svn/ver/1)', 'iota' : - '(svn:wc:ra_dav:version-url 46 /svn-test-work/local_tmp/repos/!svn/ver/1/iota)', + b'(svn:wc:ra_dav:version-url 46 /svn-test-work/local_tmp/repos/!svn/ver/1/iota)', } check_dav_cache(sbox.wc_dir, 1, expected_dav_caches) @@ -390,7 +391,7 @@ def xml_entries_relocate(path, from_url, adm_name = svntest.main.get_admin_name() entries = os.path.join(path, adm_name, 'entries') txt = open(entries).read().replace('url="' + from_url, 'url="' + to_url) - os.chmod(entries, 0777) + os.chmod(entries, svntest.main.S_ALL_RWX) open(entries, 'w').write(txt) for dirent in os.listdir(path): @@ -408,8 +409,8 @@ def simple_entries_replace(path, from_ur adm_name = svntest.main.get_admin_name() entries = os.path.join(path, adm_name, 'entries') txt = open(entries).read().replace(from_url, to_url) - os.chmod(entries, 0777) - open(entries, 'wb').write(txt) + os.chmod(entries, svntest.main.S_ALL_RWX) + open(entries, 'wb').write(txt.encode()) for dirent in os.listdir(path): item_path = os.path.join(path, dirent) @@ -1143,21 +1144,21 @@ def upgrade_file_externals(sbox): svntest.main.run_svnadmin('setuuid', sbox.repo_dir, '07146bbd-0b64-4aaf-ab70-cd76a0df2d41') - expected_output = svntest.verify.RegexOutput('r2 committed.*') + expected_output = svntest.verify.RegexOutput(b'r2 committed.*') svntest.actions.run_and_verify_svnmucc(expected_output, [], '-m', 'r2', 'propset', 'svn:externals', '^/A/B/E EX\n^/A/mu muX', sbox.repo_url + '/A/B/F') - expected_output = svntest.verify.RegexOutput('r3 committed.*') + expected_output = svntest.verify.RegexOutput(b'r3 committed.*') svntest.actions.run_and_verify_svnmucc(expected_output, [], '-m', 'r3', 'propset', 'svn:externals', '^/A/B/F FX\n^/A/B/lambda lambdaX', sbox.repo_url + '/A/C') - expected_output = svntest.verify.RegexOutput('r4 committed.*') + expected_output = svntest.verify.RegexOutput(b'r4 committed.*') svntest.actions.run_and_verify_svnmucc(expected_output, [], '-m', 'r4', 'propset', 'pname1', 'pvalue1', @@ -1260,12 +1261,17 @@ def upgrade_not_present_replaced(sbox): sbox.wc_dir) expected_output = svntest.wc.State(sbox.wc_dir, { - 'A/B/E' : Item(status='E '), - 'A/B/E/alpha' : Item(status='A '), - 'A/B/E/beta' : Item(status='A '), - 'A/B/lambda' : Item(status='E '), + 'A/B/E' : Item(status=' ', treeconflict='C'), + 'A/B/E/beta' : Item(status=' ', treeconflict='A'), + 'A/B/E/alpha' : Item(status=' ', treeconflict='A'), + 'A/B/lambda' : Item(status=' ', treeconflict='C'), }) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) + expected_status.tweak('A/B/E', status='R ', treeconflict='C'), + expected_status.tweak('A/B/E/beta', status='D '), + expected_status.tweak('A/B/E/alpha', status='D '), + expected_status.tweak('A/B/lambda', status='R ', treeconflict='C'), + svntest.actions.run_and_verify_update(sbox.wc_dir, expected_output, None, expected_status) @@ -1462,14 +1468,15 @@ def auto_analyze(sbox): # svntest.main.chmod_tree will not reset it.) for path, subdirs, files in os.walk(sbox.wc_dir): for d in subdirs: - os.chmod(os.path.join(path, d), 0555) + os.chmod(os.path.join(path, d), svntest.main.S_ALL_RX) for f in files: - os.chmod(os.path.join(path, f), 0444) + os.chmod(os.path.join(path, f), svntest.main.S_ALL_READ) state = svntest.actions.get_virginal_state(sbox.wc_dir, 1) svntest.actions.run_and_verify_status(sbox.wc_dir, state) - svntest.main.chmod_tree(sbox.wc_dir, 0666, 0022) + svntest.main.chmod_tree(sbox.wc_dir, svntest.main.S_ALL_RW, + stat.S_IWGRP | stat.S_IWOTH) state = svntest.actions.get_virginal_state(sbox.wc_dir, 1) svntest.actions.run_and_verify_status(sbox.wc_dir, state) Modified: subversion/branches/ra-git/subversion/tests/cmdline/wc_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/wc_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/wc_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/wc_tests.py Tue Oct 11 09:11:50 2016 @@ -142,7 +142,7 @@ def status_with_corrupt_wc_db(sbox): sbox.build(read_only = True) with open(sbox.ospath(".svn/wc.db"), 'wb') as fd: - fd.write('\0' * 17) + fd.write(b'\0' * 17) svntest.actions.run_and_verify_svn( None, r"[^ ]+ E155016: The working copy database at '.*' is corrupt", @@ -189,7 +189,7 @@ def status_with_missing_wc_db_and_maybe_ sbox.build(read_only = True) with open(sbox.ospath(".svn/entries"), 'ab') as fd: - fd.write('something\n') + fd.write(b'something\n') os.remove(sbox.ospath(".svn/wc.db")) svntest.actions.run_and_verify_svn( None, Propchange: subversion/branches/ra-git/subversion/tests/libsvn_client/ ------------------------------------------------------------------------------ --- svn:ignore (original) +++ svn:ignore Tue Oct 11 09:11:50 2016 @@ -1,3 +1,4 @@ .libs *-test *.lo +svn-test-work Modified: subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_diff/diff-diff3-test.c Tue Oct 11 09:11:50 2016 @@ -2407,6 +2407,8 @@ merge_with_part_already_present(apr_pool /* Merge is more "aggressive" about resolving conflicts than traditional * patch or diff3. Some people consider this behaviour to be a bug, see * http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=35014 + * + * The original behavior of this test (added in 2003) was tweaked in 2016. */ static svn_error_t * merge_adjacent_changes(apr_pool_t *pool) @@ -2428,8 +2430,13 @@ merge_adjacent_changes(apr_pool_t *pool) "zig\n" "foo\n" + "<<<<<<< adj2\n" "new_bar\n" - "new_baz\n", + "baz\n" + "=======\n" + "bar\n" + "new_baz\n" + ">>>>>>> adj3\n", NULL, svn_diff_conflict_display_modified_latest, @@ -2952,6 +2959,124 @@ two_way_issue_3362_v2(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +three_way_double_add(apr_pool_t *pool) +{ + SVN_ERR(three_way_merge("doubleadd1", "doubleadd2", "doubleadd3", + "A\n" + "B\n" + "C\n" + "J\n" + "K\n" + "L", + + "A\n" + "B\n" + "C\n" + "D\n" /* New line 1a */ + "E\n" /* New line 2a */ + "F\n" /* New line 3a*/ + "J\n" + "K\n" + "L", + + "A\n" + "B\n" + "O\n" /* Change C to O */ + "P\n" /* New line 1b */ + "Q\n" /* New line 2b */ + "R\n" /* New line 3b */ + "J\n" + "K\n" + "L", + + /* With s/C/O/ we expect something like this, + but the current (1.9/trunk) result is a + succeeded merge to a combined result. + + ### I'm guessing this result needs tweaks before it + will be a PASS. */ + "A\n" + "B\n" + "<<<<<<< doubleadd2\n" + "C\n" + "D\n" /* New line 1a */ + "E\n" /* New line 2a */ + "F\n" /* New line 3a*/ + "||||||| doubleadd1\n" + "C\n" + "=======\n" + "O\n" + "P\n" /* New line 1b */ + "Q\n" /* New line 2b */ + "R\n" /* New line 3b */ + ">>>>>>> doubleadd3\n" + "J\n" + "K\n" + "L", + NULL, + svn_diff_conflict_display_modified_original_latest, + pool)); + + SVN_ERR(three_way_merge("doubleadd4", "doubleadd5", "doubleadd6", + "A\n" + "B\n" + "C\n" + "J\n" + "K\n" + "L", + + "A\n" + "B\n" + "C\n" + "D\n" /* New line 1a */ + "E\n" /* New line 2a */ + "F\n" /* New line 3a*/ + "K\n" + "L", + + "A\n" + "B\n" + "O\n" /* Change C to O */ + "P\n" /* New line 1b */ + "Q\n" /* New line 2b */ + "R\n" /* New line 3b */ + "J\n" + "K\n" + "L", + + /* With s/C/O/ we expect something like this, + but the current (1.9/trunk) result is a + succeeded merge to a combined result. + + ### I'm guessing this result needs tweaks before it + will be a PASS. */ + "A\n" + "B\n" + "<<<<<<< doubleadd5\n" + "C\n" + "D\n" /* New line 1a */ + "E\n" /* New line 2a */ + "F\n" /* New line 3a*/ + "||||||| doubleadd4\n" + "C\n" + "J\n" + "=======\n" + "O\n" + "P\n" /* New line 1b */ + "Q\n" /* New line 2b */ + "R\n" /* New line 3b */ + "J\n" + ">>>>>>> doubleadd6\n" + "K\n" + "L", + NULL, + svn_diff_conflict_display_modified_original_latest, + pool)); + + return SVN_NO_ERROR; +} + /* ========================================================================== */ @@ -2994,6 +3119,8 @@ static struct svn_test_descriptor_t test "2-way issue #3362 test v1"), SVN_TEST_PASS2(two_way_issue_3362_v2, "2-way issue #3362 test v2"), + SVN_TEST_PASS2(three_way_double_add, + "3-way merge, double add"), SVN_TEST_NULL }; Modified: subversion/branches/ra-git/subversion/tests/libsvn_diff/parse-diff-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_diff/parse-diff-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_diff/parse-diff-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_diff/parse-diff-test.c Tue Oct 11 09:11:50 2016 @@ -471,10 +471,10 @@ test_parse_git_diff(apr_pool_t *pool) SVN_TEST_STRING_ASSERT(patch->new_filename, "A/C/gamma"); SVN_TEST_ASSERT(patch->operation == svn_diff_op_modified); SVN_TEST_ASSERT(patch->hunks->nelts == 1); - SVN_TEST_ASSERT(patch->old_executable_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->new_executable_bit = svn_tristate_true); - SVN_TEST_ASSERT(patch->old_symlink_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->new_symlink_bit = svn_tristate_false); + SVN_TEST_ASSERT(patch->old_executable_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->new_executable_bit == svn_tristate_true); + SVN_TEST_ASSERT(patch->old_symlink_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->new_symlink_bit == svn_tristate_false); hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *); @@ -510,10 +510,10 @@ test_parse_git_diff(apr_pool_t *pool) SVN_TEST_STRING_ASSERT(patch->new_filename, "new"); SVN_TEST_ASSERT(patch->operation == svn_diff_op_added); SVN_TEST_ASSERT(patch->hunks->nelts == 0); - SVN_TEST_ASSERT(patch->old_executable_bit = svn_tristate_unknown); - SVN_TEST_ASSERT(patch->new_executable_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->old_symlink_bit = svn_tristate_unknown); - SVN_TEST_ASSERT(patch->new_symlink_bit = svn_tristate_false); + SVN_TEST_ASSERT(patch->old_executable_bit == svn_tristate_unknown); + SVN_TEST_ASSERT(patch->new_executable_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->old_symlink_bit == svn_tristate_unknown); + SVN_TEST_ASSERT(patch->new_symlink_bit == svn_tristate_false); SVN_ERR(svn_diff_close_patch_file(patch_file, pool)); @@ -539,10 +539,10 @@ test_parse_git_tree_and_text_diff(apr_po SVN_TEST_ASSERT(patch); SVN_TEST_STRING_ASSERT(patch->old_filename, "iota"); SVN_TEST_STRING_ASSERT(patch->new_filename, "iota.copied"); - SVN_TEST_ASSERT(patch->old_executable_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->new_executable_bit = svn_tristate_true); - SVN_TEST_ASSERT(patch->old_symlink_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->new_symlink_bit = svn_tristate_false); + SVN_TEST_ASSERT(patch->old_executable_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->new_executable_bit == svn_tristate_true); + SVN_TEST_ASSERT(patch->old_symlink_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->new_symlink_bit == svn_tristate_false); SVN_TEST_ASSERT(patch->operation == svn_diff_op_copied); SVN_TEST_ASSERT(patch->hunks->nelts == 1); @@ -565,10 +565,10 @@ test_parse_git_tree_and_text_diff(apr_po SVN_TEST_ASSERT(patch); SVN_TEST_STRING_ASSERT(patch->old_filename, "A/mu"); SVN_TEST_STRING_ASSERT(patch->new_filename, "A/mu.moved"); - SVN_TEST_ASSERT(patch->old_executable_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->new_executable_bit = svn_tristate_true); - SVN_TEST_ASSERT(patch->old_symlink_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->new_symlink_bit = svn_tristate_false); + SVN_TEST_ASSERT(patch->old_executable_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->new_executable_bit == svn_tristate_true); + SVN_TEST_ASSERT(patch->old_symlink_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->new_symlink_bit == svn_tristate_false); SVN_TEST_ASSERT(patch->operation == svn_diff_op_moved); SVN_TEST_ASSERT(patch->hunks->nelts == 1); @@ -612,10 +612,10 @@ test_parse_git_tree_and_text_diff(apr_po SVN_TEST_STRING_ASSERT(patch->new_filename, "/dev/null"); SVN_TEST_ASSERT(patch->operation == svn_diff_op_deleted); SVN_TEST_ASSERT(patch->hunks->nelts == 1); - SVN_TEST_ASSERT(patch->old_executable_bit = svn_tristate_true); - SVN_TEST_ASSERT(patch->new_executable_bit = svn_tristate_unknown); - SVN_TEST_ASSERT(patch->old_symlink_bit = svn_tristate_false); - SVN_TEST_ASSERT(patch->new_symlink_bit = svn_tristate_unknown); + SVN_TEST_ASSERT(patch->old_executable_bit == svn_tristate_true); + SVN_TEST_ASSERT(patch->new_executable_bit == svn_tristate_unknown); + SVN_TEST_ASSERT(patch->old_symlink_bit == svn_tristate_false); + SVN_TEST_ASSERT(patch->new_symlink_bit == svn_tristate_unknown); hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *); Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_fs/fs-test.c Tue Oct 11 09:11:50 2016 @@ -43,6 +43,7 @@ #include "private/svn_fs_util.h" #include "private/svn_fs_private.h" #include "private/svn_fspath.h" +#include "private/svn_sqlite.h" #include "../svn_test_fs.h" @@ -3592,17 +3593,11 @@ get_file_checksum(svn_checksum_t **check apr_pool_t *pool) { svn_stream_t *stream; - svn_stream_t *checksum_stream; /* Get a stream for the file contents. */ SVN_ERR(svn_fs_file_contents(&stream, root, path, pool)); - - /* Get a checksummed stream for the contents. */ - checksum_stream = svn_stream_checksummed2(stream, checksum, NULL, - checksum_kind, TRUE, pool); - - /* Close the stream, forcing a complete read and copy the digest. */ - SVN_ERR(svn_stream_close(checksum_stream)); + SVN_ERR(svn_stream_contents_checksum(checksum, stream, checksum_kind, + pool, pool)); return SVN_NO_ERROR; } @@ -6701,6 +6696,9 @@ test_fsfs_config_opts(const svn_test_opt svn_fs_t *fs; const svn_fs_info_placeholder_t *fs_info; const svn_fs_fsfs_info_t *fsfs_info; + const char *dir_name = "test-repo-fsfs-config-opts"; + const char *repo_name_default = "test-repo-fsfs-config-opts/default"; + const char *repo_name_custom = "test-repo-fsfs-config-opts/custom"; /* Bail (with SKIP) on known-untestable scenarios */ if (strcmp(opts->fs_type, SVN_FS_TYPE_FSFS) != 0) @@ -6708,20 +6706,19 @@ test_fsfs_config_opts(const svn_test_opt "this will test FSFS repositories only"); /* Remove the test directory from previous runs. */ - SVN_ERR(svn_io_remove_dir2("test-repo-fsfs-config-opts", TRUE, NULL, NULL, - pool)); + SVN_ERR(svn_io_remove_dir2(dir_name, TRUE, NULL, NULL, pool)); /* Create the test directory and add it to the test cleanup list. */ - SVN_ERR(svn_io_dir_make("test-fsfs-config-opts", APR_OS_DEFAULT, pool)); - svn_test_add_dir_cleanup("test-fsfs-config-opts"); + SVN_ERR(svn_io_dir_make(dir_name, APR_OS_DEFAULT, pool)); + svn_test_add_dir_cleanup(dir_name); /* Create an FSFS filesystem with default config.*/ fs_config = apr_hash_make(pool); svn_hash_sets(fs_config, SVN_FS_CONFIG_FS_TYPE, SVN_FS_TYPE_FSFS); - SVN_ERR(svn_fs_create(&fs, "test-fsfs-config-opts/default", fs_config, pool)); + SVN_ERR(svn_fs_create(&fs, repo_name_default, fs_config, pool)); /* Re-open FS to test the data on disk. */ - SVN_ERR(svn_fs_open2(&fs, "test-fsfs-config-opts/default", NULL, pool, pool)); + SVN_ERR(svn_fs_open2(&fs, repo_name_default, NULL, pool, pool)); SVN_ERR(svn_fs_info(&fs_info, fs, pool, pool)); SVN_TEST_STRING_ASSERT(fs_info->fs_type, SVN_FS_TYPE_FSFS); @@ -6738,10 +6735,10 @@ test_fsfs_config_opts(const svn_test_opt svn_hash_sets(fs_config, SVN_FS_CONFIG_FS_TYPE, SVN_FS_TYPE_FSFS); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_LOG_ADDRESSING, "false"); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_SHARD_SIZE, "123"); - SVN_ERR(svn_fs_create(&fs, "test-fsfs-config-opts/custom", fs_config, pool)); + SVN_ERR(svn_fs_create(&fs, repo_name_custom, fs_config, pool)); /* Re-open FS to test the data on disk. */ - SVN_ERR(svn_fs_open2(&fs, "test-fsfs-config-opts/custom", NULL, pool, pool)); + SVN_ERR(svn_fs_open2(&fs, repo_name_custom, NULL, pool, pool)); SVN_ERR(svn_fs_info(&fs_info, fs, pool, pool)); SVN_TEST_STRING_ASSERT(fs_info->fs_type, SVN_FS_TYPE_FSFS); @@ -6982,13 +6979,13 @@ freeze_and_commit(const svn_test_opts_t svn_fs_root_t *txn_root; svn_revnum_t new_rev = 0; apr_pool_t *subpool = svn_pool_create(pool); + const char *repo_name = "test-repo-freeze-and-commit"; if (!strcmp(opts->fs_type, "bdb")) return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, "this will not test BDB repositories"); - SVN_ERR(svn_test__create_fs(&fs, "test-repo-freeze-and-commit", opts, - subpool)); + SVN_ERR(svn_test__create_fs(&fs, repo_name, opts, subpool)); /* This test used to FAIL with an SQLite error since svn_fs_freeze() * wouldn't unlock rep-cache.db. Therefore, part of the role of creating @@ -7020,7 +7017,7 @@ freeze_and_commit(const svn_test_opts_t SVN_ERR(test_commit_txn(&new_rev, txn, NULL, pool)); /* Re-open FS and make another commit. */ - SVN_ERR(svn_fs_open(&fs, "test-freeze-and-commit", NULL, subpool)); + SVN_ERR(svn_fs_open(&fs, repo_name, NULL, subpool)); SVN_ERR(svn_fs_begin_txn(&txn, fs, new_rev, pool)); SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); SVN_ERR(svn_fs_change_node_prop(txn_root, "/", "temperature", @@ -7031,6 +7028,165 @@ freeze_and_commit(const svn_test_opts_t return SVN_NO_ERROR; } +/* Number of changes in a revision. + * Should be > 100 to span multiple blocks. */ +#define CHANGES_COUNT 1017 + +/* Check that REVISION in FS reports the expected changes. */ +static svn_error_t * +verify_added_files_list(svn_fs_t *fs, + svn_revnum_t revision, + apr_pool_t *scratch_pool) +{ + int i; + svn_fs_root_t *root; + apr_hash_t *changed_paths; + svn_fs_path_change_iterator_t *iterator; + svn_fs_path_change3_t *change; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + + /* Collect changes and test that no path gets reported twice. */ + SVN_ERR(svn_fs_revision_root(&root, fs, revision, scratch_pool)); + SVN_ERR(svn_fs_paths_changed3(&iterator, root, scratch_pool, scratch_pool)); + + changed_paths = apr_hash_make(scratch_pool); + SVN_ERR(svn_fs_path_change_get(&change, iterator)); + while (change) + { + const char *path = apr_pstrmemdup(scratch_pool, change->path.data, + change->path.len); + SVN_TEST_ASSERT(change->change_kind == svn_fs_path_change_add); + SVN_TEST_ASSERT(!apr_hash_get(changed_paths, path, change->path.len)); + + apr_hash_set(changed_paths, path, change->path.len, path); + SVN_ERR(svn_fs_path_change_get(&change, iterator)); + } + + /* Verify that we've got exactly all paths that we added. */ + SVN_TEST_ASSERT(CHANGES_COUNT == apr_hash_count(changed_paths)); + for (i = 0; i < CHANGES_COUNT; ++i) + { + const char *file_name; + svn_pool_clear(iterpool); + + file_name = apr_psprintf(iterpool, "/file-%d", i); + SVN_TEST_ASSERT(svn_hash_gets(changed_paths, file_name)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_large_changed_paths_list(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_fs_t *fs; + svn_fs_txn_t *txn; + svn_fs_root_t *txn_root; + int i; + svn_revnum_t rev = 0; + apr_pool_t *iterpool = svn_pool_create(pool); + const char *repo_name = "test-repo-changed-paths-list"; + + SVN_ERR(svn_test__create_fs(&fs, repo_name, opts, pool)); + + /* r1: Add many empty files - just to amass a long list of changes. */ + SVN_ERR(svn_fs_begin_txn(&txn, fs, rev, pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + + for (i = 0; i < CHANGES_COUNT; ++i) + { + const char *file_name; + svn_pool_clear(iterpool); + + file_name = apr_psprintf(iterpool, "/file-%d", i); + SVN_ERR(svn_fs_make_file(txn_root, file_name, iterpool)); + } + + SVN_ERR(test_commit_txn(&rev, txn, NULL, pool)); + + /* Now, read the change list. + * Do it twice to cover cached data as well. */ + svn_pool_clear(iterpool); + SVN_ERR(verify_added_files_list(fs, rev, iterpool)); + svn_pool_clear(iterpool); + SVN_ERR(verify_added_files_list(fs, rev, iterpool)); + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + +#undef CHANGES_COUNT + +static svn_error_t * +commit_with_locked_rep_cache(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_fs_t *fs; + svn_fs_txn_t *txn; + svn_fs_root_t *txn_root; + svn_revnum_t new_rev; + svn_sqlite__db_t *sdb; + svn_error_t *err; + const char *fs_path; + const char *statements[] = { "SELECT MAX(revision) FROM rep_cache", NULL }; + + if (strcmp(opts->fs_type, SVN_FS_TYPE_BDB) == 0) + return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, + "this will not test BDB repositories"); + + if (opts->server_minor_version && (opts->server_minor_version < 6)) + return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, + "pre-1.6 SVN doesn't support FSFS rep-sharing"); + + fs_path = "test-repo-commit-with-locked-rep-cache"; + SVN_ERR(svn_test__create_fs(&fs, fs_path, opts, pool)); + + /* r1: Add a file. */ + SVN_ERR(svn_fs_begin_txn2(&txn, fs, 0, 0, pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_fs_make_file(txn_root, "/foo", pool)); + SVN_ERR(svn_test__set_file_contents(txn_root, "/foo", "a", pool)); + SVN_ERR(test_commit_txn(&new_rev, txn, NULL, pool)); + SVN_TEST_INT_ASSERT(new_rev, 1); + + /* Begin a new transaction based on r1. */ + SVN_ERR(svn_fs_begin_txn2(&txn, fs, 1, 0, pool)); + SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); + SVN_ERR(svn_test__set_file_contents(txn_root, "/foo", "b", pool)); + + /* Obtain a shared lock on the rep-cache.db by starting a new read + * transaction. */ + SVN_ERR(svn_sqlite__open(&sdb, + svn_dirent_join(fs_path, "rep-cache.db", pool), + svn_sqlite__mode_readonly, statements, 0, NULL, + 0, pool, pool)); + SVN_ERR(svn_sqlite__begin_transaction(sdb)); + SVN_ERR(svn_sqlite__exec_statements(sdb, 0)); + + /* Attempt to commit fs transaction. This should result in a commit + * post-processing error due to us still holding the shared lock on the + * rep-cache.db. */ + err = svn_fs_commit_txn(NULL, &new_rev, txn, pool); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_SQLITE_BUSY); + SVN_TEST_INT_ASSERT(new_rev, 2); + + /* Release the shared lock. */ + SVN_ERR(svn_sqlite__finish_transaction(sdb, SVN_NO_ERROR)); + SVN_ERR(svn_sqlite__close(sdb)); + + /* Try an operation that reads from rep-cache.db. + * + * XFAIL: Around r1740802, this call was producing an error due to the + * svn_fs_t keeping an unusable db connection (and associated file + * locks) within it. + */ + SVN_ERR(svn_fs_verify(fs_path, NULL, 0, SVN_INVALID_REVNUM, NULL, NULL, + NULL, NULL, pool)); + + return SVN_NO_ERROR; +} + /* ------------------------------------------------------------------------ */ /* The test table. */ @@ -7165,6 +7321,10 @@ static struct svn_test_descriptor_t test "test svn_fs_check_related for transactions"), SVN_TEST_OPTS_PASS(freeze_and_commit, "freeze and commit"), + SVN_TEST_OPTS_PASS(test_large_changed_paths_list, + "test reading a large changed paths list"), + SVN_TEST_OPTS_PASS(commit_with_locked_rep_cache, + "test commit with locked rep-cache"), SVN_TEST_NULL }; Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c Tue Oct 11 09:11:50 2016 @@ -86,6 +86,7 @@ fuzzing_1_byte_1_rev(const char *repo_na fs_config = apr_hash_make(pool); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS, "1"); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS, "1"); + svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NODEPROPS, "1"); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS, "2"); svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ, "0"); Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_fs_fs/fs-fs-pack-test.c Tue Oct 11 09:11:50 2016 @@ -29,6 +29,7 @@ #include "../../libsvn_fs_fs/fs.h" #include "../../libsvn_fs_fs/fs_fs.h" #include "../../libsvn_fs_fs/low_level.h" +#include "../../libsvn_fs_fs/pack.h" #include "../../libsvn_fs_fs/util.h" #include "svn_hash.h" @@ -101,17 +102,16 @@ pack_notify(void *baton, #define R1_LOG_MSG "Let's serf" -/* Create a packed filesystem in DIR. Set the shard size to - SHARD_SIZE and create NUM_REVS number of revisions (in addition to - r0). Use POOL for allocations. After this function successfully - completes, the filesystem's youngest revision number will be the - same as NUM_REVS. */ -static svn_error_t * -create_packed_filesystem(const char *dir, - const svn_test_opts_t *opts, - svn_revnum_t num_revs, - int shard_size, - apr_pool_t *pool) +/* Create a filesystem in DIR. Set the shard size to SHARD_SIZE and create + NUM_REVS number of revisions (in addition to r0). Use POOL for + allocations. After this function successfully completes, the filesystem's + youngest revision number will be NUM_REVS. */ +static svn_error_t * +create_non_packed_filesystem(const char *dir, + const svn_test_opts_t *opts, + svn_revnum_t num_revs, + int shard_size, + apr_pool_t *pool) { svn_fs_t *fs; svn_fs_txn_t *txn; @@ -119,7 +119,6 @@ create_packed_filesystem(const char *dir const char *conflict; svn_revnum_t after_rev; apr_pool_t *subpool = svn_pool_create(pool); - struct pack_notify_baton pnb; apr_pool_t *iterpool; apr_hash_t *fs_config; @@ -166,6 +165,28 @@ create_packed_filesystem(const char *dir svn_pool_destroy(iterpool); svn_pool_destroy(subpool); + /* Done */ + return SVN_NO_ERROR; +} + +/* Create a packed filesystem in DIR. Set the shard size to + SHARD_SIZE and create NUM_REVS number of revisions (in addition to + r0). Use POOL for allocations. After this function successfully + completes, the filesystem's youngest revision number will be the + same as NUM_REVS. */ +static svn_error_t * +create_packed_filesystem(const char *dir, + const svn_test_opts_t *opts, + svn_revnum_t num_revs, + int shard_size, + apr_pool_t *pool) +{ + struct pack_notify_baton pnb; + + /* Create the repo and fill it. */ + SVN_ERR(create_non_packed_filesystem(dir, opts, num_revs, shard_size, + pool)); + /* Now pack the FS */ pnb.expected_shard = 0; pnb.expected_action = svn_fs_pack_notify_start; @@ -669,7 +690,7 @@ recover_fully_packed(const svn_test_opts /* ------------------------------------------------------------------------ */ /* Regression test for issue #4320 (fsfs file-hinting fails when reading a rep - from the transaction that is commiting rev = SHARD_SIZE). */ + from the transaction that is committing rev = SHARD_SIZE). */ #define REPO_NAME "test-repo-file-hint-at-shard-boundary" #define SHARD_SIZE 4 #define MAX_REV (SHARD_SIZE - 1) @@ -1672,7 +1693,7 @@ compare_0_length_rep(const svn_test_opts enum { COUNT = 5 }; const char *file_names[COUNT] = { no_rep_file, - empty_delta_file, + empty_plain_file, plain_file, empty_delta_file, delta_file }; @@ -1740,6 +1761,56 @@ compare_0_length_rep(const svn_test_opts #undef REPO_NAME +/* ------------------------------------------------------------------------ */ +/* Verify that the format 7 pack logic works even if we can't fit all index + metadata into memory. */ +#define REPO_NAME "test-repo-pack-with-limited-memory" +#define SHARD_SIZE 4 +#define MAX_REV (2 * SHARD_SIZE - 1) +static svn_error_t * +pack_with_limited_memory(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + apr_size_t max_mem; + apr_pool_t *iterpool = svn_pool_create(pool); + + /* Bail (with success) on known-untestable scenarios */ + if (opts->server_minor_version && (opts->server_minor_version < 9)) + return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, + "pre-1.9 SVN doesn't support reordering packs"); + + /* Run with an increasing memory allowance such that we cover all + splitting scenarios. */ + for (max_mem = 350; max_mem < 8000; max_mem += max_mem / 2) + { + const char *dir; + svn_fs_t *fs; + + svn_pool_clear(iterpool); + + /* Create a filesystem. */ + dir = apr_psprintf(iterpool, "%s-%d", REPO_NAME, (int)max_mem); + SVN_ERR(create_non_packed_filesystem(dir, opts, MAX_REV, SHARD_SIZE, + iterpool)); + + /* Pack it with a narrow memory budget. */ + SVN_ERR(svn_fs_open2(&fs, dir, NULL, iterpool, iterpool)); + SVN_ERR(svn_fs_fs__pack(fs, max_mem, NULL, NULL, NULL, NULL, + iterpool)); + + /* To be sure: Verify that we didn't break the repo. */ + SVN_ERR(svn_fs_verify(dir, NULL, 0, MAX_REV, NULL, NULL, NULL, NULL, + iterpool)); + } + + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} +#undef REPO_NAME +#undef MAX_REV +#undef SHARD_SIZE + /* The test table. */ @@ -1790,6 +1861,8 @@ static struct svn_test_descriptor_t test "delta chains starting with PLAIN, issue #4577"), SVN_TEST_OPTS_PASS(compare_0_length_rep, "compare empty PLAIN and non-existent reps"), + SVN_TEST_OPTS_PASS(pack_with_limited_memory, + "pack with limited memory for metadata"), SVN_TEST_NULL }; Modified: subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_fs_x/fs-x-pack-test.c Tue Oct 11 09:11:50 2016 @@ -737,7 +737,7 @@ test_info(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_fs_t *fs; - const svn_fs_fsfs_info_t *fsfs_info; + const svn_fs_fsx_info_t *fsx_info; const svn_fs_info_placeholder_t *info; SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, @@ -753,9 +753,9 @@ test_info(const svn_test_opts_t *opts, if (strcmp(opts->fs_type, "fsx") != 0) return SVN_NO_ERROR; - fsfs_info = (const void *)info; - SVN_TEST_ASSERT(fsfs_info->shard_size == SHARD_SIZE); - SVN_TEST_ASSERT(fsfs_info->min_unpacked_rev + fsx_info = (const void *)info; + SVN_TEST_ASSERT(fsx_info->shard_size == SHARD_SIZE); + SVN_TEST_ASSERT(fsx_info->min_unpacked_rev == (MAX_REV + 1) / SHARD_SIZE * SHARD_SIZE); return SVN_NO_ERROR; @@ -873,7 +873,7 @@ test_batch_fsync(const svn_test_opts_t * SVN_ERR(svn_fs_x__batch_fsync_init()); /* We use and re-use the same batch object throughout this test. */ - SVN_ERR(svn_fs_x__batch_fsync_create(&batch, pool)); + SVN_ERR(svn_fs_x__batch_fsync_create(&batch, TRUE, pool)); /* The working directory is new. */ SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, abspath, pool)); Modified: subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_ra/ra-test.c Tue Oct 11 09:11:50 2016 @@ -603,6 +603,7 @@ get_dir_test(const svn_test_opts_t *opts { svn_ra_session_t *session; apr_hash_t *dirents; + svn_dirent_t *ent; SVN_ERR(make_and_open_repos(&session, "test-get-dir", opts, pool)); SVN_ERR(commit_tree(session, pool)); @@ -613,6 +614,19 @@ get_dir_test(const svn_test_opts_t *opts SVN_DIRENT_KIND, pool), SVN_ERR_FS_NOT_FOUND); + /* Test fetching SVN_DIRENT_SIZE without SVN_DIRENT_KIND. */ + SVN_ERR(svn_ra_get_dir2(session, &dirents, NULL, NULL, "", 1, + SVN_DIRENT_SIZE, pool)); + SVN_TEST_INT_ASSERT(apr_hash_count(dirents), 1); + ent = svn_hash_gets(dirents, "A"); + SVN_TEST_ASSERT(ent); + +#if 0 + /* ra_serf has returns SVN_INVALID_SIZE instead of documented zero for + * for directories. */ + SVN_TEST_INT_ASSERT(ent->size, 0); +#endif + return SVN_NO_ERROR; } @@ -1632,12 +1646,9 @@ commit_empty_last_change(const svn_test_ SVN_TEST_ASSERT(dirent != NULL); SVN_TEST_STRING_ASSERT(dirent->last_author, "jrandom"); - /* BDB only updates last_changed on the repos_root when there is an - actual change. Our other filesystems handle this differently */ - if (!opts->fs_type || !strcasecmp(opts->fs_type, "BDB")) - SVN_TEST_INT_ASSERT(dirent->created_rev, 1); - else - SVN_TEST_INT_ASSERT(dirent->created_rev, 2+i); + /* BDB used to only updates last_changed on the repos_root when there + was an actual change. Now all filesystems behave in the same way */ + SVN_TEST_INT_ASSERT(dirent->created_rev, 2+i); } svn_pool_clear(tmp_pool); Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/io-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/io-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_subr/io-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_subr/io-test.c Tue Oct 11 09:11:50 2016 @@ -674,6 +674,68 @@ test_file_readline(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_open_uniquely_named(apr_pool_t *pool) +{ + const char *tmp_dir; + apr_file_t *file; + const char *path; + svn_error_t *err; + + SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "test_open_uniquely_named", + pool)); + + /* Test #1: File 'foo.tmp' doesn't exist. */ + SVN_ERR(svn_io_open_uniquely_named(&file, &path, tmp_dir, "foo", ".tmp", + svn_io_file_del_none, pool, pool)); + SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "foo.tmp", pool)); + SVN_ERR(svn_io_file_close(file, pool)); + + /* Test #2: File 'foo.tmp' is already exist. */ + SVN_ERR(svn_io_open_uniquely_named(NULL, &path, tmp_dir, "foo", ".tmp", + svn_io_file_del_none, pool, pool)); + SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "foo.2.tmp", pool)); + + /* Test #3: Directory named 'bar.tmp' is already exist. */ + SVN_ERR(svn_io_dir_make(svn_dirent_join(tmp_dir, "bar.tmp", pool), + APR_OS_DEFAULT, pool)); + SVN_ERR(svn_io_open_uniquely_named(NULL, &path, tmp_dir, "bar", ".tmp", + svn_io_file_del_none, pool, pool)); + SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "bar.2.tmp", pool)); + + + /* Test #4: Attempt create file in non-existing directory. */ + err = svn_io_open_uniquely_named(NULL, &path, + svn_dirent_join(tmp_dir, "non-existing", pool), + NULL, NULL, svn_io_file_del_none, pool, pool); + if (err && APR_STATUS_IS_ENOENT(err->apr_err)) + { + svn_error_clear(err); + } + else if (err) + { + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "Expected error APR_STATUS_IS_ENOTDIR() but " + "got %s", + svn_error_symbolic_name(err->apr_err)); + } + else + { + SVN_TEST_ASSERT_ANY_ERROR(err); + } + + /* Test #5: File 'yota.tmp' is already exist and readonly. */ + SVN_ERR(svn_io_file_create_empty(svn_dirent_join(tmp_dir, "yota.tmp", pool), + pool)); + SVN_ERR(svn_io_set_file_read_only(svn_dirent_join(tmp_dir, "yota.tmp", pool), + FALSE, pool)); + SVN_ERR(svn_io_open_uniquely_named(NULL, &path, tmp_dir, "yota", ".tmp", + svn_io_file_del_none, pool, pool)); + SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "yota.2.tmp", pool)); + + return SVN_NO_ERROR; +} + /* Move the read pointer in FILE to absolute position OFFSET and align * the read buffer to multiples of BLOCK_SIZE. BUFFERED is set only if * FILE actually uses a read buffer. Use POOL for allocations. @@ -803,7 +865,7 @@ aligned_seek_test(apr_pool_t *pool) SVN_ERR(svn_io_file_close(f, pool)); /* now, try read data with buffering disabled. - That are a special case because APR reports a buffer size of 0. */ + That is a special case because APR reports a buffer size of 0. */ SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ, APR_OS_DEFAULT, pool)); SVN_ERR(aligned_read(f, contents, 0x1000, FALSE, pool)); SVN_ERR(aligned_read(f, contents, 0x8000, FALSE, pool)); @@ -1040,6 +1102,51 @@ test_file_rename2(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_apr_trunc_workaround(apr_pool_t *pool) +{ + const char *tmp_dir; + const char *tmp_file; + apr_file_t *f; + apr_size_t len; + apr_off_t offset; + char dummy; + + /* create a temp folder & schedule it for automatic cleanup */ + SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_apr_trunc_workaround", + pool)); + SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool)); + svn_test_add_dir_cleanup(tmp_dir); + + /* create an r/w file */ + tmp_file = svn_dirent_join(tmp_dir, "file", pool); + SVN_ERR(svn_io_file_open(&f, tmp_file, + APR_READ | APR_WRITE | APR_BUFFERED | APR_CREATE | + APR_TRUNCATE, + APR_OS_DEFAULT, pool)); + + /* write some content and put it internally into read mode */ + len = 10; + SVN_ERR(svn_io_file_write(f, "0123456789", &len, pool)); + + offset = 0; + SVN_ERR(svn_io_file_seek(f, APR_SET, &offset, pool)); + SVN_ERR(svn_io_file_getc(&dummy, f, pool)); + + /* clear the file and write some new content */ + SVN_ERR(svn_io_file_trunc(f, 0, pool)); + len = 3; + SVN_ERR(svn_io_file_write(f, "abc", &len, pool)); + + /* we should now be positioned at the end of the new content */ + offset = 0; + SVN_ERR(svn_io_file_seek(f, APR_CUR, &offset, pool)); + SVN_TEST_ASSERT(offset == (int)len); + + return SVN_NO_ERROR; +} + /* The test table. */ static int max_threads = 3; @@ -1073,6 +1180,10 @@ static struct svn_test_descriptor_t test "test svn_io_read_length_line()"), SVN_TEST_PASS2(test_file_readline, "test svn_io_file_readline()"), + SVN_TEST_PASS2(test_open_uniquely_named, + "test svn_io_open_uniquely_named()"), + SVN_TEST_PASS2(test_apr_trunc_workaround, + "test workaround for APR in svn_io_file_trunc"), SVN_TEST_NULL }; Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/packed-data-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/packed-data-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_subr/packed-data-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_subr/packed-data-test.c Tue Oct 11 09:11:50 2016 @@ -222,6 +222,7 @@ test_byte_stream(apr_pool_t *pool) /* the stream shall contain exactly the items we put into it */ SVN_TEST_ASSERT(svn_packed__byte_count(stream) == 20); + SVN_TEST_ASSERT(svn_packed__byte_block_count(stream) == COUNT); for (i = 0; i < COUNT; ++i) { svn_string_t string; Modified: subversion/branches/ra-git/subversion/tests/libsvn_subr/sqlite-test.c URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/libsvn_subr/sqlite-test.c?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/libsvn_subr/sqlite-test.c (original) +++ subversion/branches/ra-git/subversion/tests/libsvn_subr/sqlite-test.c Tue Oct 11 09:11:50 2016 @@ -26,8 +26,10 @@ static svn_error_t * open_db(svn_sqlite__db_t **sdb, + const char **db_abspath_p, const char *db_name, const char *const *statements, + apr_int32_t timeout, apr_pool_t *pool) { const char *db_dir, *db_abspath; @@ -40,8 +42,10 @@ open_db(svn_sqlite__db_t **sdb, db_abspath = svn_dirent_join(db_dir, db_name, pool); SVN_ERR(svn_sqlite__open(sdb, db_abspath, svn_sqlite__mode_rwcreate, - statements, 0, NULL, 0, pool, pool)); + statements, 0, NULL, timeout, pool, pool)); + if (db_abspath_p) + *db_abspath_p = db_abspath; return SVN_NO_ERROR; } @@ -83,7 +87,7 @@ test_sqlite_reset(apr_pool_t *pool) NULL }; - SVN_ERR(open_db(&sdb, "reset", statements, pool)); + SVN_ERR(open_db(&sdb, NULL, "reset", statements, 0, pool)); SVN_ERR(svn_sqlite__create_scalar_function(sdb, "error_second", 1, FALSE /* deterministic */, error_second, NULL)); @@ -113,6 +117,59 @@ test_sqlite_reset(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_sqlite_txn_commit_busy(apr_pool_t *pool) +{ + svn_sqlite__db_t *sdb1; + svn_sqlite__db_t *sdb2; + const char *db_abspath; + svn_error_t *err; + + static const char *const statements[] = { + "CREATE TABLE test (one TEXT NOT NULL PRIMARY KEY)", + + "INSERT INTO test(one) VALUES ('foo')", + + "SELECT one from test", + + NULL + }; + + /* Open two db connections. + + Use a small busy_timeout of 250ms, since we're about to receive an + SVN_ERR_SQLITE_BUSY error, and retrying for the default 10 seconds + would be a waste of time. */ + SVN_ERR(open_db(&sdb1, &db_abspath, "txn_commit_busy", + statements, 250, pool)); + SVN_ERR(svn_sqlite__open(&sdb2, db_abspath, svn_sqlite__mode_readwrite, + statements, 0, NULL, 250, pool, pool)); + SVN_ERR(svn_sqlite__exec_statements(sdb1, 0)); + + /* Begin two deferred transactions. */ + SVN_ERR(svn_sqlite__begin_transaction(sdb1)); + SVN_ERR(svn_sqlite__exec_statements(sdb1, 1 /* INSERT */)); + SVN_ERR(svn_sqlite__begin_transaction(sdb2)); + SVN_ERR(svn_sqlite__exec_statements(sdb2, 2 /* SELECT */)); + + /* Try to COMMIT the first write transaction; this should fail due to + the concurrent read transaction that holds a shared lock on the db. */ + err = svn_sqlite__finish_transaction(sdb1, SVN_NO_ERROR); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_SQLITE_BUSY); + + /* We failed to COMMIT the first transaction, but COMMIT-ting the + second transaction through a different db connection should succeed. + Upgrade it to a write transaction by executing the INSERT statement, + and then commit. */ + SVN_ERR(svn_sqlite__exec_statements(sdb2, 1 /* INSERT */)); + SVN_ERR(svn_sqlite__finish_transaction(sdb2, SVN_NO_ERROR)); + + SVN_ERR(svn_sqlite__close(sdb2)); + SVN_ERR(svn_sqlite__close(sdb1)); + + return SVN_NO_ERROR; +} + static int max_threads = 1; @@ -121,6 +178,8 @@ static struct svn_test_descriptor_t test SVN_TEST_NULL, SVN_TEST_PASS2(test_sqlite_reset, "sqlite reset"), + SVN_TEST_PASS2(test_sqlite_txn_commit_busy, + "sqlite busy on transaction commit"), SVN_TEST_NULL };