Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnadmin_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnadmin_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnadmin_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnadmin_tests.py Tue Oct 11 09:11:50 2016 @@ -114,8 +114,8 @@ def check_hotcopy_fsfs_fsx(src, dst): # to match. Source and target must have the same number of lines # (due to having the same format). if src_path == os.path.join(src, 'db', 'uuid'): - lines1 = open(src_path, 'rb').read().split("\n") - lines2 = open(dst_path, 'rb').read().split("\n") + lines1 = open(src_path, 'rb').read().split(b"\n") + lines2 = open(dst_path, 'rb').read().split(b"\n") if len(lines1) != len(lines2): raise svntest.Failure("%s differs in number of lines" % dst_path) @@ -153,8 +153,8 @@ def check_hotcopy_fsfs_fsx(src, dst): "revprop generation") continue - f1 = open(src_path, 'r') - f2 = open(dst_path, 'r') + f1 = open(src_path, 'rb') + f2 = open(dst_path, 'rb') while True: offset = 0 BUFSIZE = 1024 @@ -239,14 +239,14 @@ def patch_format(repo_dir, shard_size): contents = open(format_path, 'rb').read() processed_lines = [] - for line in contents.split("\n"): - if line.startswith("layout "): - processed_lines.append("layout sharded %d" % shard_size) + for line in contents.split(b"\n"): + if line.startswith(b"layout "): + processed_lines.append(("layout sharded %d" % shard_size).encode()) else: processed_lines.append(line) - new_contents = "\n".join(processed_lines) - os.chmod(format_path, 0666) + new_contents = b"\n".join(processed_lines) + os.chmod(format_path, svntest.main.S_ALL_RW) open(format_path, 'wb').write(new_contents) def is_sharded(repo_dir): @@ -255,8 +255,8 @@ def is_sharded(repo_dir): format_path = os.path.join(repo_dir, "db", "format") contents = open(format_path, 'rb').read() - for line in contents.split("\n"): - if line.startswith("layout sharded"): + for line in contents.split(b"\n"): + if line.startswith(b"layout sharded"): return True return False @@ -269,8 +269,7 @@ def load_and_verify_dumpstream(sbox, exp of each rev's items. VARARGS are optional arguments passed to the 'load' command.""" - if isinstance(dump, str): - dump = [ dump ] + dump = svntest.main.ensure_list(dump) exit_code, output, errput = svntest.main.run_command_stdin( svntest.main.svnadmin_binary, expected_stderr, 0, True, dump, @@ -334,24 +333,25 @@ class FSFS_Index: for line in output: values = line.split() if len(values) >= 4 and values[0] != 'Start': - item = long(values[4]) + item = int(values[4]) self.by_item[item] = values def _write(self): """ Rewrite indexes using svnfsfs. """ by_offset = {} - for values in self.by_item.itervalues(): - by_offset[long(values[0], 16)] = values + for key in self.by_item: + values = self.by_item[key] + by_offset[int(values[0], 16)] = values lines = [] for (offset, values) in sorted(by_offset.items()): values = by_offset[offset] line = values[0] + ' ' + values[1] + ' ' + values[2] + ' ' + \ values[3] + ' ' + values[4] + '\n'; - lines.append(line) + lines.append(line.encode()) exit_code, output, errput = svntest.main.run_command_stdin( - svntest.main.svnfsfs_binary, 0, 0, True, lines, + svntest.main.svnfsfs_binary, 0, 0, False, lines, 'load-index', self.repo_dir) svntest.verify.verify_outputs("Error while rewriting index", @@ -362,8 +362,8 @@ class FSFS_Index: """ Return offset, length and type of ITEM. """ values = self.by_item[item] - offset = long(values[0], 16) - len = long(values[1], 16) + offset = int(values[0], 16) + len = int(values[1], 16) type = values[2] return (offset, len, type) @@ -399,17 +399,20 @@ def set_changed_path_list(sbox, revision if repo_format(sbox) < 7: # replace the changed paths list - header = contents[contents.rfind('\n', length - 64, length - 1):] - body_len = long(header.split(' ')[1]) + header = contents[contents.rfind(b'\n', length - 64, length - 1):] + body_len = int(header.split(b' ')[1]) else: # read & parse revision file footer - footer_length = ord(contents[length-1]); + footer_length = contents[length-1]; + if isinstance(footer_length, str): + footer_length = ord(footer_length) + footer = contents[length - footer_length - 1:length-1] - l2p_offset = long(footer.split(' ')[0]) - l2p_checksum = footer.split(' ')[1] - p2l_offset = long(footer.split(' ')[2]) - p2l_checksum = footer.split(' ')[3] + l2p_offset = int(footer.split(b' ')[0]) + l2p_checksum = footer.split(b' ')[1] + p2l_offset = int(footer.split(b' ')[2]) + p2l_checksum = footer.split(b' ')[3] idx = FSFS_Index(sbox, revision) (offset, item_len, item_type) = idx.get_item(1) @@ -422,10 +425,10 @@ def set_changed_path_list(sbox, revision file_len = body_len + len(changes) + 1 p2l_offset += file_len - l2p_offset - header = str(file_len) + ' ' + l2p_checksum + ' ' \ - + str(p2l_offset) + ' ' + p2l_checksum - header += chr(len(header)) - header = '\n' + indexes + header + header = str(file_len).encode() + b' ' + l2p_checksum + b' ' \ + + str(p2l_offset).encode() + b' ' + p2l_checksum + header += bytes([len(header)]) + header = b'\n' + indexes + header contents = contents[:body_len] + changes + header @@ -448,25 +451,25 @@ def set_changed_path_list(sbox, revision def clean_dumpfile(): return \ - [ "SVN-fs-dump-format-version: 2\n\n", - "UUID: 668cc64a-31ed-0310-8ccb-b75d75bb44e3\n\n", - "Revision-number: 0\n", - "Prop-content-length: 56\n", - "Content-length: 56\n\n", - "K 8\nsvn:date\nV 27\n2005-01-08T21:48:13.838745Z\nPROPS-END\n\n\n", - "Revision-number: 1\n", - "Prop-content-length: 98\n", - "Content-length: 98\n\n", - "K 7\nsvn:log\nV 0\n\nK 10\nsvn:author\nV 4\nerik\n", - "K 8\nsvn:date\nV 27\n2005-01-08T21:51:16.313791Z\nPROPS-END\n\n\n", - "Node-path: A\n", - "Node-kind: file\n", - "Node-action: add\n", - "Prop-content-length: 35\n", - "Text-content-length: 5\n", - "Text-content-md5: e1cbb0c3879af8347246f12c559a86b5\n", - "Content-length: 40\n\n", - "K 12\nsvn:keywords\nV 2\nId\nPROPS-END\ntext\n\n\n"] + [ b"SVN-fs-dump-format-version: 2\n\n", + b"UUID: 668cc64a-31ed-0310-8ccb-b75d75bb44e3\n\n", + b"Revision-number: 0\n", + b"Prop-content-length: 56\n", + b"Content-length: 56\n\n", + b"K 8\nsvn:date\nV 27\n2005-01-08T21:48:13.838745Z\nPROPS-END\n\n\n", + b"Revision-number: 1\n", + b"Prop-content-length: 98\n", + b"Content-length: 98\n\n", + b"K 7\nsvn:log\nV 0\n\nK 10\nsvn:author\nV 4\nerik\n", + b"K 8\nsvn:date\nV 27\n2005-01-08T21:51:16.313791Z\nPROPS-END\n\n\n", + b"Node-path: A\n", + b"Node-kind: file\n", + b"Node-action: add\n", + b"Prop-content-length: 35\n", + b"Text-content-length: 5\n", + b"Text-content-md5: e1cbb0c3879af8347246f12c559a86b5\n", + b"Content-length: 40\n\n", + b"K 12\nsvn:keywords\nV 2\nId\nPROPS-END\ntext\n\n\n"] dumpfile_revisions = \ [ svntest.wc.State('', { 'A' : svntest.wc.StateItem(contents="text\n") }) ] @@ -480,7 +483,7 @@ def extra_headers(sbox): dumpfile = clean_dumpfile() dumpfile[3:3] = \ - [ "X-Comment-Header: Ignored header normally not in dump stream\n" ] + [ b"X-Comment-Header: Ignored header normally not in dump stream\n" ] load_and_verify_dumpstream(sbox,[],[], dumpfile_revisions, False, dumpfile, '--ignore-uuid') @@ -496,10 +499,10 @@ def extra_blockcontent(sbox): # Replace "Content-length" line with two lines dumpfile[8:9] = \ - [ "Extra-content-length: 10\n", - "Content-length: 108\n\n" ] + [ b"Extra-content-length: 10\n", + b"Content-length: 108\n\n" ] # Insert the extra content after "PROPS-END\n" - dumpfile[11] = dumpfile[11][:-2] + "extra text\n\n\n" + dumpfile[11] = dumpfile[11][:-2] + b"extra text\n\n\n" load_and_verify_dumpstream(sbox,[],[], dumpfile_revisions, False, dumpfile, '--ignore-uuid') @@ -512,7 +515,7 @@ def inconsistent_headers(sbox): dumpfile = clean_dumpfile() - dumpfile[-2] = "Content-length: 30\n\n" + dumpfile[-2] = b"Content-length: 30\n\n" load_and_verify_dumpstream(sbox, [], svntest.verify.AnyOutput, dumpfile_revisions, False, dumpfile) @@ -530,9 +533,9 @@ def empty_date(sbox): # Replace portions of the revision data to drop the svn:date revprop. dumpfile[7:11] = \ - [ "Prop-content-length: 52\n", - "Content-length: 52\n\n", - "K 7\nsvn:log\nV 0\n\nK 10\nsvn:author\nV 4\nerik\nPROPS-END\n\n\n" + [ b"Prop-content-length: 52\n", + b"Content-length: 52\n\n", + b"K 7\nsvn:log\nV 0\n\nK 10\nsvn:author\nV 4\nerik\nPROPS-END\n\n\n" ] load_and_verify_dumpstream(sbox,[],[], dumpfile_revisions, False, dumpfile, @@ -807,7 +810,7 @@ def verify_incremental_fsfs(sbox): raise svntest.Skip('Test doesn\'t handle packed revisions') fp = open(r2, 'wb') - fp.write("""id: 0-2.0.r2/0 + fp.write(b"""id: 0-2.0.r2/0 type: dir count: 0 cpath: /A/B/E/bravo @@ -1033,7 +1036,7 @@ def load_with_parent_dir(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svnadmin_tests_data', 'mergeinfo_included.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) # Create 'sample' dir in sbox.repo_url, and load the dump stream there. svntest.actions.run_and_verify_svn(['Committing transaction...\n', @@ -1125,7 +1128,7 @@ def reflect_dropped_renumbered_revs(sbox dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'with_merges.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) # Create 'toplevel' dir in sbox.repo_url svntest.actions.run_and_verify_svn(['Committing transaction...\n', @@ -1363,9 +1366,10 @@ def dont_drop_valid_mergeinfo_during_inc # Properties on 'branches/B2': # svn:mergeinfo # /trunk:9 - dumpfile_full = open(os.path.join(os.path.dirname(sys.argv[0]), - 'svnadmin_tests_data', - 'mergeinfo_included_full.dump')).read() + dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), + 'svnadmin_tests_data', + 'mergeinfo_included_full.dump') + dumpfile_full = svntest.actions.load_dumpfile(dumpfile_location) load_dumpstream(sbox, dumpfile_full, '--ignore-uuid') # Check that the mergeinfo is as expected. @@ -1408,9 +1412,12 @@ def dont_drop_valid_mergeinfo_during_inc sbox.build(empty=True) # Load the three incremental dump files in sequence. - load_dumpstream(sbox, open(dump_file_r1_10).read(), '--ignore-uuid') - load_dumpstream(sbox, open(dump_file_r11_13).read(), '--ignore-uuid') - load_dumpstream(sbox, open(dump_file_r14_15).read(), '--ignore-uuid') + load_dumpstream(sbox, svntest.actions.load_dumpfile(dump_file_r1_10), + '--ignore-uuid') + load_dumpstream(sbox, svntest.actions.load_dumpfile(dump_file_r11_13), + '--ignore-uuid') + load_dumpstream(sbox, svntest.actions.load_dumpfile(dump_file_r14_15), + '--ignore-uuid') # Check the mergeinfo, we use the same expected output as before, # as it (duh!) should be exactly the same as when we loaded the @@ -1436,9 +1443,10 @@ def dont_drop_valid_mergeinfo_during_inc # Project-Z (Added r5) # docs/ (Added r6) # README (Added r6) - dumpfile_skeleton = open(os.path.join(os.path.dirname(sys.argv[0]), - 'svnadmin_tests_data', - 'skeleton_repos.dump')).read() + dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), + 'svnadmin_tests_data', + 'skeleton_repos.dump') + dumpfile_skeleton = svntest.actions.load_dumpfile(dumpfile_location) load_dumpstream(sbox, dumpfile_skeleton, '--ignore-uuid') # Load 'svnadmin_tests_data/mergeinfo_included_full.dump' in one shot: @@ -1482,11 +1490,11 @@ def dont_drop_valid_mergeinfo_during_inc load_dumpstream(sbox, dumpfile_skeleton, '--ignore-uuid') # Load the three incremental dump files in sequence. - load_dumpstream(sbox, open(dump_file_r1_10).read(), + load_dumpstream(sbox, svntest.actions.load_dumpfile(dump_file_r1_10), '--parent-dir', 'Projects/Project-X', '--ignore-uuid') - load_dumpstream(sbox, open(dump_file_r11_13).read(), + load_dumpstream(sbox, svntest.actions.load_dumpfile(dump_file_r11_13), '--parent-dir', 'Projects/Project-X', '--ignore-uuid') - load_dumpstream(sbox, open(dump_file_r14_15).read(), + load_dumpstream(sbox, svntest.actions.load_dumpfile(dump_file_r14_15), '--parent-dir', 'Projects/Project-X', '--ignore-uuid') # Check the resulting mergeinfo. We expect the exact same results @@ -1560,7 +1568,7 @@ def hotcopy_symlink(sbox): def load_bad_props(sbox): "svnadmin load with invalid svn: props" - dump_str = """SVN-fs-dump-format-version: 2 + dump_str = b"""SVN-fs-dump-format-version: 2 UUID: dc40867b-38f6-0310-9f5f-f81aa277e06f @@ -1645,24 +1653,24 @@ def verify_non_utf8_paths(sbox): fp1 = open(path1, 'rb') fp_new = open(path_new, 'wb') for line in fp1.readlines(): - if line == "A\n": + if line == b"A\n": # replace 'A' with a latin1 character -- the new path is not valid UTF-8 - fp_new.write("\xE6\n") - elif line == "text: 1 279 32 32 d63ecce65d8c428b86f4f8b0920921fe\n": + fp_new.write(b"\xE6\n") + elif line == b"text: 1 279 32 32 d63ecce65d8c428b86f4f8b0920921fe\n": # phys, PLAIN directories: fix up the representation checksum - fp_new.write("text: 1 279 32 32 b50b1d5ed64075b5f632f3b8c30cd6b2\n") - elif line == "text: 1 292 44 32 a6be7b4cf075fd39e6a99eb69a31232b\n": + fp_new.write(b"text: 1 279 32 32 b50b1d5ed64075b5f632f3b8c30cd6b2\n") + elif line == b"text: 1 292 44 32 a6be7b4cf075fd39e6a99eb69a31232b\n": # phys, deltified directories: fix up the representation checksum - fp_new.write("text: 1 292 44 32 f2e93e73272cac0f18fccf16f224eb93\n") - elif line == "text: 1 6 31 31 90f306aa9bfd72f456072076a2bd94f7\n": + fp_new.write(b"text: 1 292 44 32 f2e93e73272cac0f18fccf16f224eb93\n") + elif line == b"text: 1 6 31 31 90f306aa9bfd72f456072076a2bd94f7\n": # log addressing: fix up the representation checksum - fp_new.write("text: 1 6 31 31 db2d4a0bad5dff0aea9a288dec02f1fb\n") - elif line == "cpath: /A\n": + fp_new.write(b"text: 1 6 31 31 db2d4a0bad5dff0aea9a288dec02f1fb\n") + elif line == b"cpath: /A\n": # also fix up the 'created path' field - fp_new.write("cpath: /\xE6\n") - elif line == "_0.0.t0-0 add-file true true /A\n": + fp_new.write(b"cpath: /\xE6\n") + elif line == b"_0.0.t0-0 add-file true true /A\n": # and another occurrance - fp_new.write("_0.0.t0-0 add-file true true /\xE6\n") + fp_new.write(b"_0.0.t0-0 add-file true true /\xE6\n") else: fp_new.write(line) fp1.close() @@ -1778,18 +1786,17 @@ def load_ranges(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svnadmin_tests_data', 'skeleton_repos.dump') - dumplines = open(dumpfile_location).readlines() - dumpdata = "".join(dumplines) + dumplines = svntest.actions.load_dumpfile(dumpfile_location) # Load our dumpfile, 2 revisions at a time, verifying that we have # the correct youngest revision after each load. - load_dumpstream(sbox, dumpdata, '-r0:2') + load_dumpstream(sbox, dumplines, '-r0:2') svntest.actions.run_and_verify_svnlook(['2\n'], None, 'youngest', sbox.repo_dir) - load_dumpstream(sbox, dumpdata, '-r3:4') + load_dumpstream(sbox, dumplines, '-r3:4') svntest.actions.run_and_verify_svnlook(['4\n'], None, 'youngest', sbox.repo_dir) - load_dumpstream(sbox, dumpdata, '-r5:6') + load_dumpstream(sbox, dumplines, '-r5:6') svntest.actions.run_and_verify_svnlook(['6\n'], None, 'youngest', sbox.repo_dir) @@ -2086,7 +2093,7 @@ def verify_keep_going(sbox): r2 = fsfs_file(sbox.repo_dir, 'revs', '2') fp = open(r2, 'r+b') - fp.write("""inserting junk to corrupt the rev""") + fp.write(b"inserting junk to corrupt the rev") fp.close() exit_code, output, errput = svntest.main.run_svnadmin("verify", "--keep-going", @@ -2190,7 +2197,7 @@ def verify_keep_going_quiet(sbox): r2 = fsfs_file(sbox.repo_dir, 'revs', '2') fp = open(r2, 'r+b') - fp.write("""inserting junk to corrupt the rev""") + fp.write(b"inserting junk to corrupt the rev") fp.close() exit_code, output, errput = svntest.main.run_svnadmin("verify", @@ -2242,79 +2249,176 @@ def verify_invalid_path_changes(sbox): # add existing node set_changed_path_list(sbox, 2, - "_0.0.t1-1 add-dir false false /A\n\n") + b"_0.0.t1-1 add-dir false false /A\n\n") # add into non-existent parent set_changed_path_list(sbox, 4, - "_0.0.t3-2 add-dir false false /C/X\n\n") + b"_0.0.t3-2 add-dir false false /C/X\n\n") # del non-existent node set_changed_path_list(sbox, 6, - "_0.0.t5-2 delete-dir false false /C\n\n") + b"_0.0.t5-2 delete-dir false false /C\n\n") # del existent node of the wrong kind # # THIS WILL NOT BE DETECTED # since dump mechanism and file don't care about the types of deleted nodes set_changed_path_list(sbox, 8, - "_0.0.t7-2 delete-file false false /B3\n\n") + b"_0.0.t7-2 delete-file false false /B3\n\n") # copy from non-existent node set_changed_path_list(sbox, 10, - "_0.0.t9-2 add-dir false false /B10\n" - "6 /B8\n") + b"_0.0.t9-2 add-dir false false /B10\n6 /B8\n") # copy from existing node of the wrong kind set_changed_path_list(sbox, 12, - "_0.0.t11-2 add-file false false /B12\n" - "9 /B8\n") + b"_0.0.t11-2 add-file false false /B12\n9 /B8\n") # modify non-existent node set_changed_path_list(sbox, 14, - "_0.0.t13-2 modify-file false false /A/D/H/foo\n\n") + b"_0.0.t13-2 modify-file false false /A/D/H/foo\n\n") # modify existent node of the wrong kind set_changed_path_list(sbox, 16, - "_0.0.t15-2 modify-file false false /B12\n\n") + b"_0.0.t15-2 modify-file false false /B12\n\n") # replace non-existent node set_changed_path_list(sbox, 18, - "_0.0.t17-2 replace-file false false /A/D/H/foo\n\n") + b"_0.0.t17-2 replace-file false false /A/D/H/foo\n\n") # find corruptions exit_code, output, errput = svntest.main.run_svnadmin("verify", "--keep-going", sbox.repo_dir) - exp_out = svntest.verify.RegexListOutput([".*Verified revision 0.", - ".*Verified revision 1.", - ".*Verified revision 3.", - ".*Verified revision 5.", - ".*Verified revision 7.", - ".*Verified revision 8.", - ".*Verified revision 9.", - ".*Verified revision 11.", - ".*Verified revision 13.", - ".*Verified revision 15.", - ".*Verified revision 17.", - ".*Verified revision 19.", - ".*", - ".*Summary.*", - ".*r2: E160020:.*", - ".*r2: E160020:.*", - ".*r4: E160013:.*", - ".*r6: E160013:.*", - ".*r6: E160013:.*", - ".*r10: E160013:.*", - ".*r10: E160013:.*", - ".*r12: E145001:.*", - ".*r12: E145001:.*", - ".*r14: E160013:.*", - ".*r14: E160013:.*", - ".*r16: E145001:.*", - ".*r16: E145001:.*", - ".*r18: E160013:.*", - ".*r18: E160013:.*"]) + # Errors generated by FSFS when CHANGED_PATHS is not forced into emulation + exp_out1 = svntest.verify.RegexListOutput([".*Verified revision 0.", + ".*Verified revision 1.", + ".*Verified revision 3.", + ".*Verified revision 5.", + ".*Verified revision 7.", + ".*Verified revision 8.", + ".*Verified revision 9.", + ".*Verified revision 11.", + ".*Verified revision 13.", + ".*Verified revision 15.", + ".*Verified revision 17.", + ".*Verified revision 19.", + ".*", + ".*Summary.*", + ".*r2: E160020:.*", + ".*r2: E160020:.*", + ".*r4: E160013:.*", + ".*r6: E160013:.*", + ".*r6: E160013:.*", + ".*r10: E160013:.*", + ".*r10: E160013:.*", + ".*r12: E145001:.*", + ".*r12: E145001:.*", + ".*r14: E160013:.*", + ".*r14: E160013:.*", + ".*r16: E145001:.*", + ".*r16: E145001:.*", + ".*r18: E160013:.*", + ".*r18: E160013:.*"]) + + exp_err1 = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160020:.*", + "svnadmin: E160020:.*", + ".*Error verifying revision 4.", + "svnadmin: E160013:.*", + ".*Error verifying revision 6.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + ".*Error verifying revision 10.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + ".*Error verifying revision 12.", + "svnadmin: E145001:.*", + "svnadmin: E145001:.*", + ".*Error verifying revision 14.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + ".*Error verifying revision 16.", + "svnadmin: E145001:.*", + "svnadmin: E145001:.*", + ".*Error verifying revision 18.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + "svnadmin: E205012:.*"], False) + + # If CHANGED_PATHS is emulated, FSFS fails earlier, generating fewer + # of the same messages per revision. + exp_out2 = svntest.verify.RegexListOutput([".*Verified revision 0.", + ".*Verified revision 1.", + ".*Verified revision 3.", + ".*Verified revision 5.", + ".*Verified revision 7.", + ".*Verified revision 8.", + ".*Verified revision 9.", + ".*Verified revision 11.", + ".*Verified revision 13.", + ".*Verified revision 15.", + ".*Verified revision 17.", + ".*Verified revision 19.", + ".*", + ".*Summary.*", + ".*r2: E160020:.*", + ".*r2: E160020:.*", + ".*r4: E160013:.*", + ".*r6: E160013:.*", + ".*r10: E160013:.*", + ".*r10: E160013:.*", + ".*r12: E145001:.*", + ".*r12: E145001:.*", + ".*r14: E160013:.*", + ".*r16: E145001:.*", + ".*r16: E145001:.*", + ".*r18: E160013:.*"]) + + exp_err2 = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160020:.*", + "svnadmin: E160020:.*", + ".*Error verifying revision 4.", + "svnadmin: E160013:.*", + ".*Error verifying revision 6.", + "svnadmin: E160013:.*", + ".*Error verifying revision 10.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + ".*Error verifying revision 12.", + "svnadmin: E145001:.*", + "svnadmin: E145001:.*", + ".*Error verifying revision 14.", + "svnadmin: E160013:.*", + ".*Error verifying revision 16.", + "svnadmin: E145001:.*", + "svnadmin: E145001:.*", + ".*Error verifying revision 18.", + "svnadmin: E160013:.*", + "svnadmin: E205012:.*"], False) + + # Determine which pattern to use. + # Note that index() will throw an exception if the string can't be found. + try: + rev6_line = errput.index('* Error verifying revision 6.\n'); + rev10_line = errput.index('* Error verifying revision 10.\n'); + + error_count = 0 + for line in errput[rev6_line+1:rev10_line]: + if "svnadmin: E" in line: + error_count = error_count + 1 + + if error_count == 1: + exp_out = exp_out2 + exp_err = exp_err2 + else: + exp_out = exp_out1 + exp_err = exp_err1 + except ValueError: + exp_out = exp_out1 + exp_err = exp_err1 + if (svntest.main.fs_has_rep_sharing()): exp_out.insert(0, ".*Verifying.*metadata.*") if svntest.main.options.fsfs_sharding is not None: @@ -2323,32 +2427,6 @@ def verify_invalid_path_changes(sbox): if svntest.main.is_fs_log_addressing(): exp_out.insert(0, ".*Verifying.*metadata.*") - exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.", - "svnadmin: E160020:.*", - "svnadmin: E160020:.*", - ".*Error verifying revision 4.", - "svnadmin: E160013:.*", - ".*Error verifying revision 6.", - "svnadmin: E160013:.*", - "svnadmin: E160013:.*", - ".*Error verifying revision 10.", - "svnadmin: E160013:.*", - "svnadmin: E160013:.*", - ".*Error verifying revision 12.", - "svnadmin: E145001:.*", - "svnadmin: E145001:.*", - ".*Error verifying revision 14.", - "svnadmin: E160013:.*", - "svnadmin: E160013:.*", - ".*Error verifying revision 16.", - "svnadmin: E145001:.*", - "svnadmin: E145001:.*", - ".*Error verifying revision 18.", - "svnadmin: E160013:.*", - "svnadmin: E160013:.*", - "svnadmin: E205012:.*"], False) - - if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin verify'.", output, errput, exp_out, exp_err): raise svntest.Failure @@ -2400,7 +2478,7 @@ def verify_denormalized_names(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svnadmin_tests_data', 'normalization_check.dump') - load_dumpstream(sbox, open(dumpfile_location).read()) + load_dumpstream(sbox, svntest.actions.load_dumpfile(dumpfile_location)) exit_code, output, errput = svntest.main.run_svnadmin( "verify", "--check-normalization", sbox.repo_dir) @@ -2478,9 +2556,10 @@ def load_ignore_dates(sbox): sbox.build(create_wc=False, empty=True) - dumpfile_skeleton = open(os.path.join(os.path.dirname(sys.argv[0]), - 'svnadmin_tests_data', - 'skeleton_repos.dump')).read() + dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), + 'svnadmin_tests_data', + 'skeleton_repos.dump') + dumpfile_skeleton = svntest.actions.load_dumpfile(dumpfile_location) load_dumpstream(sbox, dumpfile_skeleton, '--ignore-dates') svntest.actions.run_and_verify_svnlook(['6\n'], @@ -2750,7 +2829,7 @@ def verify_quickly(sbox): # set new contents rev_file.seek(8) - rev_file.write('#') + rev_file.write(b'#') rev_file.close() exit_code, output, errput = svntest.main.run_svnadmin("verify", @@ -3051,7 +3130,7 @@ def load_txdelta(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svnadmin_tests_data', 'load_txdelta.dump.gz') - dumpfile = gzip.open(dumpfile_location).read() + dumpfile = gzip.open(dumpfile_location, "rb").readlines() load_dumpstream(sbox, dumpfile) @@ -3080,12 +3159,12 @@ def load_no_svndate_r0(sbox): 'proplist', '--revprop', '-r0', sbox.repo_dir) - dump_old = ["SVN-fs-dump-format-version: 2\n", "\n", - "UUID: bf52886d-358d-4493-a414-944a6e5ad4f5\n", "\n", - "Revision-number: 0\n", - "Prop-content-length: 10\n", - "Content-length: 10\n", "\n", - "PROPS-END\n", "\n"] + dump_old = [b"SVN-fs-dump-format-version: 2\n", b"\n", + b"UUID: bf52886d-358d-4493-a414-944a6e5ad4f5\n", b"\n", + b"Revision-number: 0\n", + b"Prop-content-length: 10\n", + b"Content-length: 10\n", b"\n", + b"PROPS-END\n", b"\n"] svntest.actions.run_and_verify_load(sbox.repo_dir, dump_old) # svn:date should have been removed @@ -3099,7 +3178,7 @@ def load_no_svndate_r0(sbox): def hotcopy_read_only(sbox): "'svnadmin hotcopy' a read-only source repository" sbox.build() - svntest.main.chmod_tree(sbox.repo_dir, 0, 0222) + svntest.main.chmod_tree(sbox.repo_dir, 0, svntest.main.S_ALL_WRITE) backup_dir, backup_url = sbox.add_repo_path('backup') exit_code, output, errput = svntest.main.run_svnadmin("hotcopy", @@ -3107,7 +3186,8 @@ def hotcopy_read_only(sbox): backup_dir) # r/o repos are hard to clean up. Make it writable again. - svntest.main.chmod_tree(sbox.repo_dir, 0222, 0222) + svntest.main.chmod_tree(sbox.repo_dir, svntest.main.S_ALL_WRITE, + svntest.main.S_ALL_WRITE) if errput: logger.warn("Error: hotcopy failed") raise SVNUnexpectedStderr(errput) @@ -3175,7 +3255,7 @@ def dump_revprops(sbox): # We expect the dump to contain no path changes for line in dump_contents: - if line.find("Node-path: ") > -1: + if line.find(b"Node-path: ") > -1: logger.warn("Error: path change found in revprops-only dump.") raise svntest.Failure @@ -3250,7 +3330,8 @@ def dump_no_op_change(sbox): svntest.actions.run_and_verify_svn(expected, [], 'log', '-v', sbox2.repo_url + '/bar') -@XFail() +@XFail() # This test will XPASS on FSFS if rep-caching is disabled. +@Issue(4623) def dump_no_op_prop_change(sbox): "svnadmin dump with no-op property change" @@ -3293,6 +3374,68 @@ def dump_no_op_prop_change(sbox): svntest.actions.run_and_verify_svn(expected, [], 'log', '-v', sbox2.repo_url + '/bar') +def load_no_flush_to_disk(sbox): + "svnadmin load --no-flush-to-disk" + + sbox.build(empty=True) + + # Can't test the "not flushing to disk part", but loading the + # dump should work. + dump = clean_dumpfile() + expected = [ + svntest.wc.State('', { + 'A' : svntest.wc.StateItem(contents="text\n", + props={'svn:keywords': 'Id'}) + }) + ] + load_and_verify_dumpstream(sbox, [], [], expected, True, dump, + '--no-flush-to-disk', '--ignore-uuid') + +def dump_to_file(sbox): + "svnadmin dump --file ARG" + + sbox.build(create_wc=False, empty=False) + expected_dump = svntest.actions.run_and_verify_dump(sbox.repo_dir) + + file = sbox.get_tempname() + svntest.actions.run_and_verify_svnadmin2([], + ["* Dumped revision 0.\n", + "* Dumped revision 1.\n"], + 0, 'dump', '--file', file, + sbox.repo_dir) + actual_dump = open(file, 'rb').readlines() + svntest.verify.compare_dump_files(None, None, expected_dump, actual_dump) + + # Test that svnadmin dump --file overwrites existing files. + file = sbox.get_tempname() + svntest.main.file_write(file, '') + svntest.actions.run_and_verify_svnadmin2([], + ["* Dumped revision 0.\n", + "* Dumped revision 1.\n"], + 0, 'dump', '--file', file, + sbox.repo_dir) + actual_dump = open(file, 'rb').readlines() + svntest.verify.compare_dump_files(None, None, expected_dump, actual_dump) + +def load_from_file(sbox): + "svnadmin load --file ARG" + + sbox.build(empty=True) + + file = sbox.get_tempname() + open(file, 'wb').writelines(clean_dumpfile()) + svntest.actions.run_and_verify_svnadmin2(None, [], + 0, 'load', '--file', file, + '--ignore-uuid', sbox.repo_dir) + expected_tree = \ + svntest.wc.State('', { + 'A' : svntest.wc.StateItem(contents="text\n", + props={'svn:keywords': 'Id'}) + }) + svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], + 'update', sbox.wc_dir) + svntest.actions.verify_disk(sbox.wc_dir, expected_tree, check_props=True) + ######################################################################## # Run the tests @@ -3354,7 +3497,10 @@ test_list = [ None, load_revprops, dump_revprops, dump_no_op_change, - dump_no_op_prop_change + dump_no_op_prop_change, + load_no_flush_to_disk, + dump_to_file, + load_from_file ] if __name__ == '__main__':
Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnauthz_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnauthz_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnauthz_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnauthz_tests.py Tue Oct 11 09:11:50 2016 @@ -53,7 +53,7 @@ def output_command(fp, cmd, opt): status = process.returncode fp.write(output) fp.write(errors) - fp.write("Exit %%d\\n" %% status) + fp.write(("Exit %%d\\n" %% status).encode()) return status for (svnauthz_cmd, svnauthz_opt) in %s: Modified: subversion/branches/ra-git/subversion/tests/cmdline/svndumpfilter_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svndumpfilter_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svndumpfilter_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svndumpfilter_tests.py Tue Oct 11 09:11:50 2016 @@ -90,7 +90,7 @@ def reflect_dropped_renumbered_revs(sbox dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'with_merges.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) filtered_out, filtered_err = filter_and_return_output( dumpfile, 0, "include", @@ -140,7 +140,7 @@ def svndumpfilter_loses_mergeinfo(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'with_merges.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) filtered_out, filtered_err = filter_and_return_output(dumpfile, 0, "include", "trunk", "branch1", @@ -224,7 +224,7 @@ def dumpfilter_with_targets(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'greek_tree.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) (fd, targets_file) = tempfile.mkstemp(dir=svntest.main.temp_dir) try: @@ -247,7 +247,7 @@ def dumpfilter_with_patterns(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'greek_tree.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) _simple_dumpfilter_test(sbox, dumpfile, 'exclude', '--pattern', '/A/D/[GH]*', '/A/[B]/E*') @@ -335,7 +335,7 @@ def filter_mergeinfo_revs_outside_of_dum partial_dump = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'mergeinfo_included_partial.dump') - partial_dump_contents = open(partial_dump).read() + partial_dump_contents = svntest.actions.load_dumpfile(partial_dump) filtered_dumpfile2, filtered_out = filter_and_return_output( partial_dump_contents, 8192, # Set a sufficiently large bufsize to avoid a deadlock @@ -366,14 +366,15 @@ def filter_mergeinfo_revs_outside_of_dum # docs/ (Added r6) # README (Added r6). sbox.build(empty=True) - skeleton_dumpfile = open(os.path.join(os.path.dirname(sys.argv[0]), - 'svnadmin_tests_data', - 'skeleton_repos.dump')).read() + skeleton_location = os.path.join(os.path.dirname(sys.argv[0]), + 'svnadmin_tests_data', + 'skeleton_repos.dump') + skeleton_dumpfile = svntest.actions.load_dumpfile(skeleton_location) load_dumpstream(sbox, skeleton_dumpfile, '--ignore-uuid') partial_dump2 = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'mergeinfo_included_partial.dump') - partial_dump_contents2 = open(partial_dump2).read() + partial_dump_contents2 = svntest.actions.load_dumpfile(partial_dump2) # Now use the partial dump file we used above, but this time exclude # the B2 branch. Load the filtered dump into the /Projects/Project-X # subtree of the skeleton repos. @@ -550,7 +551,7 @@ def dropped_but_not_renumbered_empty_rev full_dump = os.path.join(os.path.dirname(sys.argv[0]), 'svnadmin_tests_data', 'mergeinfo_included_full.dump') - full_dump_contents = open(full_dump).read() + full_dump_contents = svntest.actions.load_dumpfile(full_dump) filtered_dumpfile, filtered_out = filter_and_return_output( full_dump_contents, 16384, # Set a sufficiently large bufsize to avoid a deadlock @@ -595,7 +596,7 @@ def match_empty_prefix(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'greek_tree.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) def test(sbox, dumpfile, *dumpargs): """Run svndumpfilter with DUMPFILE as the input lines, load @@ -648,7 +649,7 @@ def accepts_deltas(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'simple_v3.dump') - dump_in = open(dumpfile_location).read() + dump_in = svntest.actions.load_dumpfile(dumpfile_location) dump_out, err = filter_and_return_output(dump_in, 0, "include", "trunk", "--quiet") @@ -683,7 +684,7 @@ def dumpfilter_targets_expect_leading_sl dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'greek_tree.dump') - dumpfile = open(dumpfile_location).read() + dumpfile = svntest.actions.load_dumpfile(dumpfile_location) (fd, targets_file) = tempfile.mkstemp(dir=svntest.main.temp_dir) try: @@ -706,7 +707,7 @@ def drop_all_empty_revisions(sbox): dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]), 'svndumpfilter_tests_data', 'empty_revisions.dump') - dump_contents = open(dumpfile_location).read() + dump_contents = svntest.actions.load_dumpfile(dumpfile_location) filtered_dumpfile, filtered_err = filter_and_return_output( dump_contents, Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnfsfs_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnfsfs_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnfsfs_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnfsfs_tests.py Tue Oct 11 09:11:50 2016 @@ -86,14 +86,14 @@ def patch_format(repo_dir, shard_size): contents = open(format_path, 'rb').read() processed_lines = [] - for line in contents.split("\n"): - if line.startswith("layout "): - processed_lines.append("layout sharded %d" % shard_size) + for line in contents.split(b"\n"): + if line.startswith(b"layout "): + processed_lines.append(b"layout sharded %d" % shard_size) else: processed_lines.append(line) - new_contents = "\n".join(processed_lines) - os.chmod(format_path, 0666) + new_contents = b"\n".join(processed_lines) + os.chmod(format_path, svntest.main.S_ALL_RW) open(format_path, 'wb').write(new_contents) ###################################################################### @@ -202,7 +202,7 @@ def test_stats(sbox): # check that the output contains all sections for section_name in sections_to_find: - if not sections.has_key(section_name): + if not section_name in sections.keys(): logger.warn("Error: section '" + section_name + "' not found") raise svntest.Failure @@ -294,6 +294,9 @@ def load_index_sharded(sbox): assert(items[1].split()[3] == "1") + # The STDIN data must be binary. + items = svntest.main.ensure_list(map(str.encode, items)) + # Reload the index exit_code, output, errput = svntest.main.run_command_stdin( svntest.main.svnfsfs_binary, [], 0, False, items, Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnlook_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnlook_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnlook_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnlook_tests.py Tue Oct 11 09:11:50 2016 @@ -98,17 +98,17 @@ def test_misc(sbox): expected_status) # give the repo a new UUID - uuid = "01234567-89ab-cdef-89ab-cdef01234567" + uuid = b"01234567-89ab-cdef-89ab-cdef01234567" svntest.main.run_command_stdin(svntest.main.svnadmin_binary, None, 0, True, - ["SVN-fs-dump-format-version: 2\n", - "\n", - "UUID: ", uuid, "\n", + [b"SVN-fs-dump-format-version: 2\n", + b"\n", + b"UUID: ", uuid, b"\n", ], 'load', '--force-uuid', repo_dir) expect('youngest', [ '2\n' ], run_svnlook('youngest', repo_dir)) - expect('uuid', [ uuid + '\n' ], run_svnlook('uuid', repo_dir)) + expect('uuid', [ uuid.decode() + '\n' ], run_svnlook('uuid', repo_dir)) # it would be nice to test the author too, but the current test framework # does not pull a username when testing over ra_neon or ra_svn, @@ -301,7 +301,7 @@ def test_print_property_diffs(sbox): def info_bad_newlines(sbox): "svnlook info must allow inconsistent newlines" - dump_str = """SVN-fs-dump-format-version: 2 + dump_str = b"""SVN-fs-dump-format-version: 2 UUID: dc40867b-38f6-0310-9f5f-f81aa277e06e Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnmover_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnmover_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnmover_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnmover_tests.py Tue Oct 11 09:11:50 2016 @@ -456,7 +456,7 @@ rm A/B/C/Y """.split())) # ### TODO: need a smarter run_and_verify_log() that verifies copyfrom - expected_output = svntest.verify.UnorderedRegexListOutput(map(re.escape, [ + escaped = svntest.main.ensure_list(map(re.escape, [ ' R /top0/A (from /top0/X/Y/Z:1)', ' A /top0/A/B (from /top0/A/B:1)', ' R /top0/A/B/C (from /top0/X:1)', @@ -467,9 +467,9 @@ rm A/B/C/Y ' A /top0/X/Y (from /top0/X/Y:1)', ' R /top0/X/Y/Z (from /top0/M:1)', ' D /top0/A/B/C/Y', - ]) + [ - '^-', '^r2', '^-', '^Changed paths:', - ]) + ])) + expected_output = svntest.verify.UnorderedRegexListOutput(escaped + + ['^-', '^r2', '^-', '^Changed paths:',]) svntest.actions.run_and_verify_svn(expected_output, [], 'log', '-qvr2', repo_url) Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnmucc_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnmucc_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnmucc_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnmucc_tests.py Tue Oct 11 09:11:50 2016 @@ -48,7 +48,7 @@ def reject_bogus_mergeinfo(sbox): '-m', 'log msg', sbox.repo_url + '/A') -_svnmucc_re = re.compile('^(r[0-9]+) committed by jrandom at (.*)$') +_svnmucc_re = re.compile(b'^(r[0-9]+) committed by jrandom at (.*)$') _log_re = re.compile('^ ([ADRM] /[^\(]+($| \(from .*:[0-9]+\)$))') _err_re = re.compile('^svnmucc: (.*)$') @@ -445,7 +445,7 @@ rm A/B/C/Y """.split())) # ### TODO: need a smarter run_and_verify_log() that verifies copyfrom - expected_output = svntest.verify.UnorderedRegexListOutput(map(re.escape, [ + excaped = svntest.main.ensure_list(map(re.escape, [ ' R /A (from /X/Y/Z:2)', ' A /A/B (from /A/B:2)', ' R /A/B/C (from /X:2)', @@ -456,9 +456,9 @@ rm A/B/C/Y ' A /X/Y (from /X/Y:2)', ' R /X/Y/Z (from /M:2)', ' D /A/B/C/Y', - ]) + [ - '^-', '^r3', '^-', '^Changed paths:', - ]) + ])) + expected_output = svntest.verify.UnorderedRegexListOutput(excaped + + ['^-', '^r3', '^-', '^Changed paths:',]) svntest.actions.run_and_verify_svn(expected_output, [], 'log', '-qvr3', repo_url) Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnrdump_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnrdump_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnrdump_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnrdump_tests.py Tue Oct 11 09:11:50 2016 @@ -53,8 +53,8 @@ Item = svntest.wc.StateItem # the logic for differentiating between these two cases. mismatched_headers_re = re.compile( - "Prop-delta: .*|Text-content-sha1: .*|Text-copy-source-md5: .*|" - "Text-copy-source-sha1: .*|Text-delta-base-sha1: .*" + b"Prop-delta: .*|Text-content-sha1: .*|Text-copy-source-md5: .*|" + + b"Text-copy-source-sha1: .*|Text-delta-base-sha1: .*" ) ###################################################################### @@ -124,9 +124,9 @@ def run_dump_test(sbox, dumpfile_name, e # Compare the output from stdout if ignore_base_checksums: expected_dumpfile = [l for l in expected_dumpfile - if not l.startswith('Text-delta-base-md5')] + if not l.startswith(b'Text-delta-base-md5')] svnrdump_dumpfile = [l for l in svnrdump_dumpfile - if not l.startswith('Text-delta-base-md5')] + if not l.startswith(b'Text-delta-base-md5')] expected_dumpfile = [l for l in expected_dumpfile if not mismatched_headers_re.match(l)] svnrdump_dumpfile = [l for l in svnrdump_dumpfile @@ -165,7 +165,7 @@ def run_load_test(sbox, dumpfile_name, e # Set the UUID of the sbox repository to the UUID specified in the # dumpfile ### RA layer doesn't have a set_uuid functionality - uuid = original_dumpfile[2].split(' ')[1][:-1] + uuid = original_dumpfile[2].split(b' ')[1][:-1].decode() svntest.actions.run_and_verify_svnadmin2(None, None, 0, 'setuuid', sbox.repo_dir, uuid) @@ -203,7 +203,7 @@ def basic_dump(sbox): [], 0, '-q', 'dump', sbox.repo_url) - if not out[0].startswith('SVN-fs-dump-format-version:'): + if not out[0].startswith(b'SVN-fs-dump-format-version:'): raise svntest.Failure('No valid output') def revision_0_dump(sbox): Modified: subversion/branches/ra-git/subversion/tests/cmdline/svnsync_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svnsync_tests.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svnsync_tests.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svnsync_tests.py Tue Oct 11 09:11:50 2016 @@ -527,7 +527,7 @@ PROPS-END """ content = content_tmpl % (len(mi), mi) headers = headers_tmpl % (node_name, len(content), len(content)) - record = headers + '\n' + content + '\n\n' + record = (headers + '\n' + content + '\n\n').encode() return record.splitlines(True) # The test case mergeinfo (before, after) syncing, separated here with @@ -572,6 +572,21 @@ PROPS-END # Compare the dump produced by the mirror repository with expected verify_mirror(dest_sbox, dump_out) +def up_to_date_sync(sbox): + """sync that does nothing""" + + # An up-to-date mirror. + sbox.build(create_wc=False) + dest_sbox = sbox.clone_dependent() + dest_sbox.build(create_wc=False, empty=True) + svntest.actions.enable_revprop_changes(dest_sbox.repo_dir) + run_init(dest_sbox.repo_url, sbox.repo_url) + run_sync(dest_sbox.repo_url) + + # Another sync should be a no-op + svntest.actions.run_and_verify_svnsync([], [], + "synchronize", dest_sbox.repo_url) + ######################################################################## # Run the tests @@ -609,6 +624,7 @@ test_list = [ None, delete_revprops, fd_leak_sync_from_serf_to_local, # calls setrlimit mergeinfo_contains_r0, + up_to_date_sync, ] if __name__ == '__main__': Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/__init__.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/__init__.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/__init__.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/__init__.py Tue Oct 11 09:11:50 2016 @@ -53,11 +53,11 @@ class Skip(Exception): pass # import in a specific order: things with the fewest circular imports first. -import testcase -import wc -import verify -import tree -import sandbox -import main -import actions -import factory +from . import testcase +from . import wc +from . import verify +from . import tree +from . import sandbox +from . import main +from . import actions +from . import factory Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/actions.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/actions.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/actions.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/actions.py Tue Oct 11 09:11:50 2016 @@ -166,7 +166,7 @@ def guarantee_greek_repository(path, min sys.exit(1) # make the repos world-writeable, for mod_dav_svn's sake. - main.chmod_tree(path, 0666, 0666) + main.chmod_tree(path, main.S_ALL_RW, main.S_ALL_RW) # give the repository a unique UUID run_and_verify_svnadmin([], [], 'setuuid', path) @@ -563,10 +563,22 @@ def run_and_verify_checkout(URL, wc_dir_ def run_and_verify_export(URL, export_dir_name, output_tree, disk_tree, *args): + """Same as run_and_verify_export2 but with KEEP_EOL_STYLE set to False.""" + + run_and_verify_export2(URL, export_dir_name, output_tree, disk_tree, + False, *args) + +def run_and_verify_export2(URL, export_dir_name, output_tree, disk_tree, + keep_eol_style=False, *args): """Export the URL into a new directory WC_DIR_NAME. The subcommand output will be verified against OUTPUT_TREE, and the exported copy itself will be verified against DISK_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 if successful, raise on failure. """ assert isinstance(output_tree, wc.State) @@ -592,7 +604,8 @@ def run_and_verify_export(URL, export_di # Create a tree by scanning the working copy. Don't ignore # the .svn directories so that we generate an error if they # happen to show up. - actual = tree.build_tree_from_wc(export_dir_name, ignore_svn=False) + actual = tree.build_tree_from_wc(export_dir_name, ignore_svn=False, + keep_eol_style=keep_eol_style) # Verify expected disk against actual disk. try: @@ -659,7 +672,7 @@ class LogParser: for i in data: self.parser.Parse(i) self.parser.Parse('', True) - except xml.parsers.expat.ExpatError, e: + except xml.parsers.expat.ExpatError as e: raise verify.SVNUnexpectedStdout('%s\n%s\n' % (e, ''.join(data),)) return self.entries @@ -791,6 +804,7 @@ def verify_update(actual_output, disk_tree, status_tree, check_props=False, + keep_eol_style=False, extra_files=None): """Verify update of WC_DIR_NAME. @@ -803,6 +817,10 @@ def verify_update(actual_output, against STATUS_TREE (if provided). (This is a good way to check that revision numbers were bumped.) + 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 if successful, raise on failure. For the comparison with DISK_TREE, pass SINGLETON_HANDLER_A and @@ -854,7 +872,7 @@ def verify_update(actual_output, # Create a tree by scanning the working copy, and verify it if disk_tree: verify_disk(wc_dir_name, disk_tree, check_props, - extra_files=extra_files) + extra_files, keep_eol_style) # Verify via 'status' command too, if possible. if status_tree: @@ -862,10 +880,15 @@ def verify_update(actual_output, def verify_disk(wc_dir_name, disk_tree, check_props=False, - extra_files=None): + extra_files=None, keep_eol_style=False): """Verify WC_DIR_NAME against DISK_TREE. If CHECK_PROPS is set, - the comparison will examin props. Returns if successful, raises on - failure.""" + the comparison will examin props. + + 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. + + Returns if successful, raises on failure.""" singleton_handler_a = None a_baton = None, @@ -881,7 +904,8 @@ def verify_disk(wc_dir_name, disk_tree, if isinstance(disk_tree, wc.State): disk_tree = disk_tree.old_tree() - actual_disk = tree.build_tree_from_wc(wc_dir_name, check_props) + actual_disk = tree.build_tree_from_wc(wc_dir_name, check_props, + keep_eol_style=keep_eol_style) try: tree.compare_trees("disk", actual_disk, disk_tree, singleton_handler_a, a_baton, @@ -900,6 +924,21 @@ def run_and_verify_update(wc_dir_name, expected_stderr=[], check_props = False, *args, **kw): + """Same as run_and_verify_update2 but with keep_eol_style set to False.""" + run_and_verify_update2(wc_dir_name, + output_tree, disk_tree, status_tree, + expected_stderr, + check_props, + False, + *args, **kw) + + +def run_and_verify_update2(wc_dir_name, + output_tree, disk_tree, status_tree, + expected_stderr=[], + check_props = False, + keep_eol_style = False, + *args, **kw): """Update WC_DIR_NAME. *ARGS are any extra optional args to the update subcommand. NOTE: If *ARGS is specified at all, explicit @@ -919,6 +958,10 @@ def run_and_verify_update(wc_dir_name, If CHECK_PROPS is set, then disk comparison will examine props. + 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 if successful, raise on failure.""" # Update and make a tree of the output. @@ -930,7 +973,7 @@ def run_and_verify_update(wc_dir_name, actual = wc.State.from_checkout(output) verify_update(actual, None, None, wc_dir_name, output_tree, None, None, disk_tree, status_tree, - check_props, **kw) + check_props, keep_eol_style=keep_eol_style, **kw) def run_and_parse_info(*args): @@ -1045,6 +1088,29 @@ def run_and_verify_merge(dir, rev1, rev2 check_props = False, dry_run = True, *args, **kw): + """Same as run_and_verify_merge2 but with keep_eol_style set to False. """ + + run_and_verify_merge2(dir, rev1, rev2, url1, url2, + output_tree, + mergeinfo_output_tree, + elision_output_tree, + disk_tree, status_tree, skip_tree, + expected_stderr, + check_props, + dry_run, + False, + *args, **kw) + +def run_and_verify_merge2(dir, rev1, rev2, url1, url2, + output_tree, + mergeinfo_output_tree, + elision_output_tree, + disk_tree, status_tree, skip_tree, + expected_stderr = [], + check_props = False, + dry_run = True, + keep_eol_style = False, + *args, **kw): """Run 'svn merge URL1@REV1 URL2@REV2 DIR' if URL2 is not None (for a three-way merge between URLs and WC). @@ -1068,6 +1134,10 @@ def run_and_verify_merge(dir, rev1, rev2 If DRY_RUN is set then a --dry-run merge will be carried out first and the output compared with that of the full merge. + 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 if successful, raise on failure. *ARGS are any extra optional args to the merge subcommand. @@ -1087,12 +1157,12 @@ def run_and_verify_merge(dir, rev1, rev2 merge_command = tuple(merge_command) if dry_run: - pre_disk = tree.build_tree_from_wc(dir) + pre_disk = tree.build_tree_from_wc(dir, keep_eol_style=keep_eol_style) dry_run_command = merge_command + ('--dry-run',) dry_run_command = dry_run_command + args exit_code, out_dry, err_dry = run_and_verify_svn(None, expected_stderr, *dry_run_command) - post_disk = tree.build_tree_from_wc(dir) + post_disk = tree.build_tree_from_wc(dir, keep_eol_style=keep_eol_style) try: tree.compare_trees("disk", post_disk, pre_disk) except tree.SVNTreeError: @@ -1193,7 +1263,7 @@ def run_and_verify_merge(dir, rev1, rev2 verify_update(actual_diff, actual_mergeinfo, actual_elision, dir, output_tree, mergeinfo_output_tree, elision_output_tree, disk_tree, status_tree, - check_props, **kw) + check_props, keep_eol_style=keep_eol_style, **kw) def run_and_verify_patch(dir, patch_path, @@ -1202,6 +1272,23 @@ def run_and_verify_patch(dir, patch_path check_props=False, dry_run=True, *args, **kw): + """Same as run_and_verify_patch2 but with KEEP_EOL_STYLE set to False.""" + + run_and_verify_patch2(dir, patch_path, + output_tree, disk_tree, status_tree, skip_tree, + error_re_string, + check_props, + dry_run, + False, + *args, **kw) + +def run_and_verify_patch2(dir, patch_path, + output_tree, disk_tree, status_tree, skip_tree, + error_re_string=None, + check_props=False, + dry_run=True, + keep_eol_style=False, + *args, **kw): """Run 'svn patch patch_path DIR'. If ERROR_RE_STRING, 'svn patch' must exit with error, and the error @@ -1217,20 +1304,23 @@ def run_and_verify_patch(dir, patch_path If DRY_RUN is set then a --dry-run patch will be carried out first and the output compared with that of the full patch application. - Returns if successful, raises on failure.""" + 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. + Returns if successful, raises on failure.""" patch_command = [ "patch" ] patch_command.append(patch_path) patch_command.append(dir) patch_command = tuple(patch_command) if dry_run: - pre_disk = tree.build_tree_from_wc(dir) + pre_disk = tree.build_tree_from_wc(dir, keep_eol_style=keep_eol_style) dry_run_command = patch_command + ('--dry-run',) dry_run_command = dry_run_command + args exit_code, out_dry, err_dry = main.run_svn(error_re_string, *dry_run_command) - post_disk = tree.build_tree_from_wc(dir) + post_disk = tree.build_tree_from_wc(dir, keep_eol_style=keep_eol_style) try: tree.compare_trees("disk", post_disk, pre_disk) except tree.SVNTreeError: @@ -1293,7 +1383,8 @@ def run_and_verify_patch(dir, patch_path verify_update(mytree, None, None, dir, output_tree, None, None, disk_tree, status_tree, - check_props=check_props, **kw) + check_props=check_props, keep_eol_style=keep_eol_style, + **kw) def run_and_verify_mergeinfo(error_re_string = None, @@ -1797,6 +1888,15 @@ def _run_and_verify_resolve(cmd, expecte expected_paths] + [ "Resolved conflicted state of '" + path + "'\n" for path in expected_paths]), + verify.UnorderedOutput([ + "Merge conflicts in '" + path + "' marked as resolved.\n" for path in + expected_paths]), + verify.UnorderedRegexListOutput([ + "Conflict in property.*at '" + path + "' marked as resolved.\n" \ + for path in expected_paths]), + verify.UnorderedOutput([ + "Tree conflict at '" + path + "' marked as resolved.\n" for path in + expected_paths]), ], match_all=False) run_and_verify_svn(expected_output, [], @@ -1880,7 +1980,7 @@ def make_repo_and_wc(sbox, create_wc=Tru # just make sure the parent folder of our working copy is created try: os.mkdir(main.general_wc_dir) - except OSError, err: + except OSError as err: if err.errno != errno.EEXIST: raise @@ -1928,6 +2028,10 @@ def get_wc_base_rev(wc_dir): "Return the BASE revision of the working copy at WC_DIR." return run_and_parse_info(wc_dir)[0]['Revision'] +def load_dumpfile(filename): + "Return the contents of the FILENAME assuming that it is a dump file" + return open(filename, "rb").readlines() + def hook_failure_message(hook_name): """Return the error message that the client prints for failure of the specified hook HOOK_NAME. The wording changed with Subversion 1.5.""" @@ -1999,6 +2103,18 @@ def create_failing_post_commit_hook(repo '@echo Post-commit hook failed 1>&2\n' '@exit 1\n') +def _make_temp_file(contents): + """ Create a unique temporary file with the specified CONTENTS + and return its path. """ + from tempfile import mkstemp + (fd, path) = mkstemp() + os.close(fd) + file = open(path, 'wb') + file.write(contents) + file.flush() + file.close() + return path + # set_prop can be used for properties with NULL characters which are not # handled correctly when passed to subprocess.Popen() and values like "*" # which are not handled correctly on Windows. @@ -2008,20 +2124,29 @@ def set_prop(name, value, path, expected propset = ('propset',) else: propset = ('propset', '--force') - if value and (value[0] == '-' or '\x00' in value or sys.platform == 'win32'): - from tempfile import mkstemp - (fd, value_file_path) = mkstemp() - os.close(fd) - value_file = open(value_file_path, 'wb') - value_file.write(value) - value_file.flush() - value_file.close() - propset += ('-F', value_file_path, name, path) - exit_code, out, err = main.run_svn(expected_re_string, *propset) - os.remove(value_file_path) + + if isinstance(value, bytes): + file = _make_temp_file(value) + elif isinstance(value, str): + if value and (value[0] == '-' or '\x00' in value or + sys.platform == 'win32'): + file = _make_temp_file(value.encode()) + else: + file = None else: + raise TypeError(value) + + if file is None: propset += (name, value, path) + else: + propset += ('-F', file, name, path) + + try: exit_code, out, err = main.run_svn(expected_re_string, *propset) + finally: + if file is not None: + os.remove(file) + if expected_re_string: if not expected_re_string.startswith(".*"): expected_re_string = ".*(" + expected_re_string + ")" Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/deeptrees.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/deeptrees.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/deeptrees.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/deeptrees.py Tue Oct 11 09:11:50 2016 @@ -37,7 +37,7 @@ else: import svntest from svntest import main, verify, tree, wc, sandbox from svntest import Failure -from actions import * +from svntest.actions import * logger = logging.getLogger() Modified: subversion/branches/ra-git/subversion/tests/cmdline/svntest/main.py URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/tests/cmdline/svntest/main.py?rev=1764214&r1=1764213&r2=1764214&view=diff ============================================================================== --- subversion/branches/ra-git/subversion/tests/cmdline/svntest/main.py (original) +++ subversion/branches/ra-git/subversion/tests/cmdline/svntest/main.py Tue Oct 11 09:11:50 2016 @@ -37,18 +37,20 @@ import urllib import logging import hashlib import zipfile -from urlparse import urlparse +import codecs try: # Python >=3.0 import queue from urllib.parse import quote as urllib_parse_quote from urllib.parse import unquote as urllib_parse_unquote + from urllib.parse import urlparse except ImportError: # Python <3.0 import Queue as queue from urllib import quote as urllib_parse_quote from urllib import unquote as urllib_parse_unquote + from urlparse import urlparse import svntest from svntest import Failure @@ -146,6 +148,19 @@ stack_trace_regexp = r'(?:.*subversion[\ os.environ['LC_ALL'] = 'C' ###################################################################### +# Permission constants used with e.g. chmod() and open(). +# Define them here at a central location, so people aren't tempted to +# use octal literals which are not portable between Python 2 and 3. + +S_ALL_READ = stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH +S_ALL_WRITE = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH +S_ALL_EXEC = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH + +S_ALL_RW = S_ALL_READ | S_ALL_WRITE +S_ALL_RX = S_ALL_READ | S_ALL_EXEC +S_ALL_RWX = S_ALL_READ | S_ALL_WRITE | S_ALL_EXEC + +###################################################################### # The locations of the svn binaries. # Use --bin to override these defaults. def P(relpath, @@ -258,7 +273,7 @@ def wrap_ex(func, output): def w(*args, **kwds): try: return func(*args, **kwds) - except Failure, ex: + except Failure as ex: if ex.__class__ != Failure or ex.args: ex_args = str(ex) if ex_args: @@ -360,11 +375,26 @@ def get_fsfs_format_file_path(repo_dir): return os.path.join(repo_dir, "db", "format") -def filter_dbg(lines): - excluded = filter(lambda line: line.startswith('DBG:'), lines) - included = filter(lambda line: not line.startswith('DBG:'), lines) +def ensure_list(item): + "If ITEM is not already a list, convert it to a list." + if isinstance(item, list): + return item + elif isinstance(item, bytes) or isinstance(item, str): + return [ item ] + else: + return list(item) + +def filter_dbg(lines, binary = False): + if binary: + excluded = filter(lambda line: line.startswith(b'DBG:'), lines) + excluded = map(bytes.decode, excluded) + included = filter(lambda line: not line.startswith(b'DBG:'), lines) + else: + excluded = filter(lambda line: line.startswith('DBG:'), lines) + included = filter(lambda line: not line.startswith('DBG:'), lines) + sys.stdout.write(''.join(excluded)) - return included + return ensure_list(included) # Run any binary, logging the command line and return code def run_command(command, error_expected, binary_mode=False, *varargs): @@ -377,6 +407,17 @@ def run_command(command, error_expected, return run_command_stdin(command, error_expected, 0, binary_mode, None, *varargs) +# Frequently used constants: +# If any of these relative path strings show up in a server response, +# then we can assume that the on-disk repository path was leaked to the +# client. Having these here as constants means we don't need to construct +# them over and over again. +_repos_diskpath1 = os.path.join('cmdline', 'svn-test-work', 'repositories') +_repos_diskpath2 = os.path.join('cmdline', 'svn-test-work', 'local_tmp', + 'repos') +_repos_diskpath1_bytes = _repos_diskpath1.encode() +_repos_diskpath2_bytes = _repos_diskpath2.encode() + # A regular expression that matches arguments that are trivially safe # to pass on a command line without quoting on any supported operating # system: @@ -447,10 +488,17 @@ def wait_on_pipe(waiter, binary_mode, st stdout, stderr = kid.communicate(stdin) exit_code = kid.returncode - # Normalize Windows line endings if in text mode. - if windows and not binary_mode: - stdout = stdout.replace('\r\n', '\n') - stderr = stderr.replace('\r\n', '\n') + # We always expect STDERR to be strings, not byte-arrays. + if not isinstance(stderr, str): + stderr = stderr.decode("utf-8") + if not binary_mode: + if not isinstance(stdout, str): + stdout = stdout.decode("utf-8") + + # Normalize Windows line endings if in text mode. + if windows: + stdout = stdout.replace('\r\n', '\n') + stderr = stderr.replace('\r\n', '\n') # Convert output strings to lists. stdout_lines = stdout.splitlines(True) @@ -539,9 +587,10 @@ def run_command_stdin(command, error_exp # ### or the diskpath isn't realpath()'d somewhere on the way from # ### the server's configuration and the client's stderr. We could # ### check for both the symlinked path and the realpath. - return \ - os.path.join('cmdline', 'svn-test-work', 'repositories') in line \ - or os.path.join('cmdline', 'svn-test-work', 'local_tmp', 'repos') in line + if isinstance(line, str): + return _repos_diskpath1 in line or _repos_diskpath2 in line + else: + return _repos_diskpath1_bytes in line or _repos_diskpath2_bytes in line for lines, name in [[stdout_lines, "stdout"], [stderr_lines, "stderr"]]: if is_ra_type_file() or 'svnadmin' in command or 'svnlook' in command: @@ -580,7 +629,7 @@ def run_command_stdin(command, error_exp '"; exit code ' + str(exit_code)) return exit_code, \ - filter_dbg(stdout_lines), \ + filter_dbg(stdout_lines, binary_mode), \ stderr_lines def create_config_dir(cfgdir, config_contents=None, server_contents=None, @@ -736,7 +785,7 @@ def run_svnadmin(*varargs): """Run svnadmin with VARARGS, returns exit code as int; stdout, stderr as list of lines (including line terminators).""" - use_binary = ('dump' in varargs) + use_binary = ('dump' in varargs) or ('dump-revprops' in varargs) exit_code, stdout_lines, stderr_lines = \ run_command(svnadmin_binary, 1, use_binary, *varargs) @@ -901,7 +950,7 @@ def safe_rmtree(dirname, retry=0): """Remove the tree at DIRNAME, making it writable first. If DIRNAME is a symlink, only remove the symlink, not its target.""" def rmtree(dirname): - chmod_tree(dirname, 0666, 0666) + chmod_tree(dirname, S_ALL_RW, S_ALL_RW) shutil.rmtree(dirname) if os.path.islink(dirname): @@ -923,21 +972,37 @@ def safe_rmtree(dirname, retry=0): else: rmtree(dirname) +# For creating new files, and making local mods to existing files. +def file_write(path, contents, mode='w'): + """Write the CONTENTS to the file at PATH, opening file using MODE, + which is (w)rite by default.""" + + if sys.version_info < (3, 0): + open(path, mode).write(contents) + else: + # Python 3: Write data in the format required by MODE, i.e. byte arrays + # to 'b' files, utf-8 otherwise.""" + if 'b' in mode: + if isinstance(contents, str): + contents = contents.encode() + else: + if not isinstance(contents, str): + contents = contents.decode("utf-8") + + if isinstance(contents, str): + codecs.open(path, mode, "utf-8").write(contents) + else: + open(path, mode).write(contents) + # For making local mods to files def file_append(path, new_text): "Append NEW_TEXT to file at PATH" - open(path, 'a').write(new_text) + file_write(path, new_text, 'a') # Append in binary mode def file_append_binary(path, new_text): "Append NEW_TEXT to file at PATH in binary mode" - open(path, 'ab').write(new_text) - -# For creating new files, and making local mods to existing files. -def file_write(path, contents, mode='w'): - """Write the CONTENTS to the file at PATH, opening file using MODE, - which is (w)rite by default.""" - open(path, mode).write(contents) + file_write(path, new_text, 'ab') # For replacing parts of contents in an existing file, with new content. def file_substitute(path, contents, new_contents): @@ -1004,7 +1069,7 @@ def _post_create_repos(path, minor_versi new_contents = new_contents[:-1] # replace it - os.chmod(format_file_path, 0666) + os.chmod(format_file_path, S_ALL_RW) file_write(format_file_path, new_contents, 'wb') # post-commit @@ -1021,7 +1086,7 @@ def _post_create_repos(path, minor_versi % repr([svnadmin_binary, 'pack', abs_path])) # make the repos world-writeable, for mod_dav_svn's sake. - chmod_tree(path, 0666, 0666) + chmod_tree(path, S_ALL_RW, S_ALL_RW) def _unpack_precooked_repos(path, template): testdir = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) @@ -1153,12 +1218,12 @@ def copy_repos(src_path, dst_path, head_ logger.warn('ERROR: dump failed; did not see revision %s', head_revision) raise SVNRepositoryCopyFailure - load_re = re.compile(r'^------- Committed revision (\d+) >>>\r?$') + load_re = re.compile(b'^------- Committed revision (\\d+) >>>\\r?$') expect_revision = 1 - for load_line in filter_dbg(load_stdout): + for load_line in filter_dbg(load_stdout, True): match = load_re.match(load_line) if match: - if match.group(1) != str(expect_revision): + if match.group(1).decode() != str(expect_revision): logger.warn('ERROR: load failed: %s', load_line.strip()) raise SVNRepositoryCopyFailure expect_revision += 1 @@ -1198,7 +1263,7 @@ def create_python_hook_script(hook_path, else: # For all other platforms file_write(hook_path, "#!%s\n%s" % (sys.executable, hook_script_code)) - os.chmod(hook_path, 0755) + os.chmod(hook_path, S_ALL_RW | stat.S_IXUSR) def create_http_connection(url, debuglevel=9): """Create an http(s) connection to the host specified by URL. @@ -1206,8 +1271,12 @@ def create_http_connection(url, debuglev working with this connection) to DEBUGLEVEL. By default, all debugging output is printed. """ - import httplib - from urlparse import urlparse + if sys.version_info < (3, 0): + # Python <3.0 + import httplib + else: + # Python >=3.0 + import http.client as httplib loc = urlparse(url) if loc.scheme == 'http': @@ -1571,7 +1640,7 @@ __mod_dav_url_quoting_broken_versions = '2.4.5', ]) def is_mod_dav_url_quoting_broken(): - if is_ra_type_dav(): + if is_ra_type_dav() and options.httpd_version != options.httpd_whitelist: return (options.httpd_version in __mod_dav_url_quoting_broken_versions) return None @@ -1643,6 +1712,8 @@ class TestSpawningThread(threading.Threa args.append('--http-proxy-password=' + options.http_proxy_password) if options.httpd_version: args.append('--httpd-version=' + options.httpd_version) + if options.httpd_whitelist: + args.append('--httpd-whitelist=' + options.httpd_whitelist) if options.exclusive_wc_locks: args.append('--exclusive-wc-locks') if options.memcached_server: @@ -1784,9 +1855,9 @@ class TestRunner: print('Test driver returned a status code.') sys.exit(255) result = svntest.testcase.RESULT_OK - except Skip, ex: + except Skip as ex: result = svntest.testcase.RESULT_SKIP - except Failure, ex: + except Failure as ex: result = svntest.testcase.RESULT_FAIL msg = '' # We captured Failure and its subclasses. We don't want to print @@ -1804,7 +1875,7 @@ class TestRunner: except KeyboardInterrupt: logger.error('Interrupted') sys.exit(0) - except SystemExit, ex: + except SystemExit as ex: logger.error('EXCEPTION: SystemExit(%d), skipping cleanup' % ex.code) self._print_name(ex.code and 'FAIL: ' or 'PASS: ') raise @@ -2059,6 +2130,8 @@ def _create_parser(usage=None): help='Password for the HTTP Proxy.') parser.add_option('--httpd-version', action='store', help='Assume HTTPD is this version.') + parser.add_option('--httpd-whitelist', action='store', + help='httpd whitelist version.') parser.add_option('--tools-bin', action='store', dest='tools_bin', help='Use the svn tools installed in this path') parser.add_option('--exclusive-wc-locks', action='store_true', @@ -2174,8 +2247,8 @@ def get_issue_details(issue_numbers): # Parse the xml for ISSUE_NO from the issue tracker into a Document. issue_xml_f = urllib.urlopen(xml_url) except: - print "WARNING: Unable to contact issue tracker; " \ - "milestones defaulting to 'unknown'." + print("WARNING: Unable to contact issue tracker; " \ + "milestones defaulting to 'unknown'.") return issue_dict try: @@ -2194,7 +2267,7 @@ def get_issue_details(issue_numbers): assignment = assignment_element[0].childNodes[0].nodeValue issue_dict[issue_id] = [milestone, assignment] except: - print "ERROR: Unable to parse target milestones from issue tracker" + print("ERROR: Unable to parse target milestones from issue tracker") raise return issue_dict @@ -2361,7 +2434,7 @@ def execute_tests(test_list, serial_only or options.mode_filter.upper() == test_mode \ or (options.mode_filter.upper() == 'PASS' and test_mode == ''): if not printed_header: - print header + print(header) printed_header = True TestRunner(test_list[testnum], testnum).list(milestones_dict) # We are simply listing the tests so always exit with success.