diff options
Diffstat (limited to 'subversion/tests/cmdline/merge_tree_conflict_tests.py')
-rwxr-xr-x | subversion/tests/cmdline/merge_tree_conflict_tests.py | 538 |
1 files changed, 330 insertions, 208 deletions
diff --git a/subversion/tests/cmdline/merge_tree_conflict_tests.py b/subversion/tests/cmdline/merge_tree_conflict_tests.py index 42dbb35..15287d3 100755 --- a/subversion/tests/cmdline/merge_tree_conflict_tests.py +++ b/subversion/tests/cmdline/merge_tree_conflict_tests.py @@ -30,7 +30,7 @@ import time # Our testing module import svntest -from svntest import main, wc, verify, actions +from svntest import main, wc, verify, actions, deeptrees # (abbreviation) Item = wc.StateItem @@ -46,6 +46,7 @@ from svntest.main import server_has_mergeinfo from merge_tests import set_up_branch from merge_tests import svn_copy from merge_tests import svn_merge +from merge_tests import expected_merge_output #---------------------------------------------------------------------- @SkipUnless(server_has_mergeinfo) @@ -624,7 +625,6 @@ def mergeinfo_recording_in_skipped_merge(sbox): 'B' : Item(), 'B/lambda' : Item(contents="This is the file 'lambda'.\n"), 'B/F' : Item(), - 'B/E' : Item(), 'D/gamma' : Item("This is the file 'gamma'.\n"), 'D/G' : Item(), 'D/G/pi' : Item("This is the file 'pi'.\n"), @@ -635,9 +635,6 @@ def mergeinfo_recording_in_skipped_merge(sbox): 'D/H/omega': Item("This is the file 'omega'.\n"), 'D/H/psi' : Item("This is the file 'psi'.\n"), }) - if svntest.main.wc_is_singledb(sbox.wc_dir): - # Delete removes directories in single-db - expected_disk.remove('B/E') expected_skip = wc.State(A_COPY_path, {}) svntest.actions.run_and_verify_merge(A_COPY_path, None, None, A_url, None, @@ -680,25 +677,16 @@ def del_differing_file(sbox): 'newprop', 'v', target+"/pi") dir_D = os.path.join('A','D') - dir_G2 = os.path.join(dir_D, 'G2') tau = os.path.join(dir_D,'G2','tau') pi = os.path.join(dir_D, 'G2', 'pi') # Should complain and "skip" it. svn_merge(s_rev_tau, source, target, [ - "--- Merging r2 into '%s':\n" % dir_G2, - " C %s\n" % tau, - "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G2), - " U %s\n" % (dir_G2), - "Summary of conflicts:\n", - " Tree conflicts: 1\n"]) + " C %s\n" % tau, # merge + ], tree_conflicts=1) svn_merge(s_rev_pi, source, target, [ - "--- Merging r3 into '%s':\n" % dir_G2, - " C %s\n" % pi, - "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G2), - " G %s\n" % (dir_G2), - "Summary of conflicts:\n", - " Tree conflicts: 1\n"]) + " C %s\n" % pi, # merge + ], tree_conflicts=1) # Copy a file, modify it, commit, and merge a deletion to it. @@ -710,26 +698,17 @@ def del_differing_file(sbox): sbox.simple_commit(target) - dir_G3 = os.path.join(dir_D, 'G3') tau = os.path.join(dir_D,'G3','tau') pi = os.path.join(dir_D, 'G3', 'pi') # Should complain and "skip" it. svn_merge(s_rev_tau, source, target, [ - "--- Merging r2 into '%s':\n" % dir_G3, " C %s\n" % tau, - "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G3), - " U %s\n" % (dir_G3), - "Summary of conflicts:\n", - " Tree conflicts: 1\n"]) + ], tree_conflicts=1) svn_merge(s_rev_pi, source, target, [ - "--- Merging r3 into '%s':\n" % dir_G3, " C %s\n" % pi, - "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G3), - " G %s\n" % (dir_G3), - "Summary of conflicts:\n", - " Tree conflicts: 1\n"]) + ], tree_conflicts=1) os.chdir(saved_cwd) @@ -786,7 +765,7 @@ def tree_conflicts_and_obstructions(sbox): 'beta' : Item(status=' ', wc_rev=3), }) expected_skip = wc.State(branch_path, { - 'alpha-moved' : Item(), + 'alpha-moved' : Item(verb='Skipped'), }) svntest.actions.run_and_verify_merge(branch_path, @@ -810,21 +789,21 @@ def tree_conflicts_and_obstructions(sbox): # parent directory. # convenience definitions -leaf_edit = svntest.actions.deep_trees_leaf_edit -tree_del = svntest.actions.deep_trees_tree_del -leaf_del = svntest.actions.deep_trees_leaf_del +leaf_edit = svntest.deeptrees.deep_trees_leaf_edit +tree_del = svntest.deeptrees.deep_trees_tree_del +leaf_del = svntest.deeptrees.deep_trees_leaf_del -disk_after_leaf_edit = svntest.actions.deep_trees_after_leaf_edit -disk_after_leaf_del = svntest.actions.deep_trees_after_leaf_del -disk_after_tree_del = svntest.actions.deep_trees_after_tree_del -disk_after_leaf_del_no_ci = svntest.actions.deep_trees_after_leaf_del_no_ci -disk_after_tree_del_no_ci = svntest.actions.deep_trees_after_tree_del_no_ci +disk_after_leaf_edit = svntest.deeptrees.deep_trees_after_leaf_edit +disk_after_leaf_del = svntest.deeptrees.deep_trees_after_leaf_del +disk_after_tree_del = svntest.deeptrees.deep_trees_after_tree_del +disk_after_leaf_del_no_ci = svntest.deeptrees.deep_trees_after_leaf_del_no_ci +disk_after_tree_del_no_ci = svntest.deeptrees.deep_trees_after_tree_del_no_ci -deep_trees_conflict_output = svntest.actions.deep_trees_conflict_output +deep_trees_conflict_output = svntest.deeptrees.deep_trees_conflict_output j = os.path.join -DeepTreesTestCase = svntest.actions.DeepTreesTestCase +DeepTreesTestCase = svntest.deeptrees.DeepTreesTestCase alpha_beta_gamma = svntest.wc.State('', { 'F/alpha' : Item(), @@ -861,7 +840,7 @@ def tree_conflicts_on_merge_local_ci_4_1(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase("local_tree_del_incoming_leaf_edit", tree_del, leaf_edit, @@ -899,7 +878,7 @@ def tree_conflicts_on_merge_local_ci_4_2(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase("local_tree_del_incoming_leaf_del", tree_del, leaf_del, @@ -909,7 +888,6 @@ def tree_conflicts_on_merge_local_ci_4_2(sbox): expected_skip) ], True) #---------------------------------------------------------------------- -@XFail() @Issue(2282) def tree_conflicts_on_merge_local_ci_5_1(sbox): "tree conflicts 5.1: leaf edit, tree del" @@ -927,23 +905,23 @@ def tree_conflicts_on_merge_local_ci_5_1(sbox): '' : Item(status=' M', wc_rev='3'), 'D' : Item(status=' ', wc_rev='3'), 'D/D1' : Item(status=' ', treeconflict='C', wc_rev='4'), - 'D/D1/delta' : Item(status='D ', wc_rev='4'), + 'D/D1/delta' : Item(status=' ', wc_rev='4'), 'DD' : Item(status=' ', wc_rev='3'), - 'DD/D1' : Item(status=' ', treeconflict='C', wc_rev='4'), - 'DD/D1/D2' : Item(status='D ', wc_rev='3'), - 'DD/D1/D2/epsilon' : Item(status='D ', wc_rev='4'), + 'DD/D1' : Item(status=' ', treeconflict='C', wc_rev='3'), + 'DD/D1/D2' : Item(status=' ', wc_rev='4'), + 'DD/D1/D2/epsilon' : Item(status=' ', wc_rev='4'), 'DDD' : Item(status=' ', wc_rev='3'), - 'DDD/D1' : Item(status=' ', treeconflict='C', wc_rev='4'), - 'DDD/D1/D2' : Item(status='D ', wc_rev='3'), - 'DDD/D1/D2/D3' : Item(status='D ', wc_rev='3'), - 'DDD/D1/D2/D3/zeta' : Item(status='D ', wc_rev='4'), + 'DDD/D1' : Item(status=' ', treeconflict='C', wc_rev='3'), + 'DDD/D1/D2' : Item(status=' ', wc_rev='3'), + 'DDD/D1/D2/D3' : Item(status=' ', wc_rev='4'), + 'DDD/D1/D2/D3/zeta' : Item(status=' ', wc_rev='4'), 'DDF' : Item(status=' ', wc_rev='3'), - 'DDF/D1' : Item(status=' ', treeconflict='C', wc_rev='4'), - 'DDF/D1/D2' : Item(status='D ', wc_rev='3'), - 'DDF/D1/D2/gamma' : Item(status='D ', wc_rev='4'), + 'DDF/D1' : Item(status=' ', treeconflict='C', wc_rev='3'), + 'DDF/D1/D2' : Item(status=' ', wc_rev='3'), + 'DDF/D1/D2/gamma' : Item(status=' ', wc_rev='4'), 'DF' : Item(status=' ', wc_rev='3'), - 'DF/D1' : Item(status=' ', treeconflict='C', wc_rev='4'), - 'DF/D1/beta' : Item(status='D ', wc_rev='4'), + 'DF/D1' : Item(status=' ', treeconflict='C', wc_rev='3'), + 'DF/D1/beta' : Item(status=' ', wc_rev='4'), 'F' : Item(status=' ', wc_rev='3'), 'F/alpha' : Item(status=' ', treeconflict='C', wc_rev='4'), @@ -952,7 +930,7 @@ def tree_conflicts_on_merge_local_ci_5_1(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase("local_leaf_edit_incoming_tree_del", leaf_edit, tree_del, @@ -962,7 +940,6 @@ def tree_conflicts_on_merge_local_ci_5_1(sbox): expected_skip) ], True) #---------------------------------------------------------------------- -@XFail() @Issue(2282) def tree_conflicts_on_merge_local_ci_5_2(sbox): "tree conflicts 5.2: leaf del, tree del" @@ -978,15 +955,15 @@ def tree_conflicts_on_merge_local_ci_5_2(sbox): 'D' : Item(status=' ', wc_rev='3'), 'F' : Item(status=' ', wc_rev='3'), 'DD' : Item(status=' ', wc_rev='3'), - 'DD/D1' : Item(status='! ', treeconflict='C'), + 'DD/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), 'DF' : Item(status=' ', wc_rev='3'), - 'DF/D1' : Item(status='! ', treeconflict='C'), + 'DF/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), 'DDD' : Item(status=' ', wc_rev='3'), - 'DDD/D1' : Item(status='! ', treeconflict='C'), - 'DDD/D1/D2' : Item(status='D ', wc_rev='3'), + 'DDD/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), + 'DDD/D1/D2' : Item(status=' ', wc_rev='3'), 'DDF' : Item(status=' ', wc_rev='3'), - 'DDF/D1' : Item(status='! ', treeconflict='C'), - 'DDF/D1/D2' : Item(status='D ', wc_rev='3'), + 'DDF/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), + 'DDF/D1/D2' : Item(status=' ', wc_rev='3'), 'D/D1' : Item(status='! ', treeconflict='C'), 'F/alpha' : Item(status='! ', treeconflict='C'), }) @@ -994,7 +971,7 @@ def tree_conflicts_on_merge_local_ci_5_2(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase("local_leaf_del_incoming_tree_del", leaf_del, tree_del, @@ -1033,7 +1010,7 @@ def tree_conflicts_on_merge_local_ci_6(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase("local_tree_del_incoming_tree_del", tree_del, tree_del, @@ -1080,7 +1057,7 @@ def tree_conflicts_on_merge_no_local_ci_4_1(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase( "local_tree_del_incoming_leaf_edit", tree_del, @@ -1128,7 +1105,7 @@ def tree_conflicts_on_merge_no_local_ci_4_2(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase( "local_tree_del_incoming_leaf_del", tree_del, @@ -1179,7 +1156,7 @@ def tree_conflicts_on_merge_no_local_ci_5_1(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase( "local_leaf_edit_incoming_tree_del", leaf_edit, @@ -1191,7 +1168,6 @@ def tree_conflicts_on_merge_no_local_ci_5_1(sbox): ) ], False) #---------------------------------------------------------------------- -@XFail() @Issue(2282) def tree_conflicts_on_merge_no_local_ci_5_2(sbox): "tree conflicts 5.2: leaf del (no ci), tree del" @@ -1209,25 +1185,25 @@ def tree_conflicts_on_merge_no_local_ci_5_2(sbox): 'F' : Item(status=' ', wc_rev='3'), 'F/alpha' : Item(status='D ', wc_rev='3', treeconflict='C'), 'DD' : Item(status=' ', wc_rev='3'), - 'DD/D1' : Item(status='D ', wc_rev='3', treeconflict='C'), + 'DD/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), 'DD/D1/D2' : Item(status='D ', wc_rev='3'), 'DF' : Item(status=' ', wc_rev='3'), - 'DF/D1' : Item(status='D ', wc_rev='3', treeconflict='C'), + 'DF/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), 'DF/D1/beta' : Item(status='D ', wc_rev='3'), 'DDD' : Item(status=' ', wc_rev='3'), - 'DDD/D1' : Item(status='D ', wc_rev='3', treeconflict='C'), - 'DDD/D1/D2' : Item(status='D ', wc_rev='3'), + 'DDD/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), + 'DDD/D1/D2' : Item(status=' ', wc_rev='3'), 'DDD/D1/D2/D3' : Item(status='D ', wc_rev='3'), 'DDF' : Item(status=' ', wc_rev='3'), - 'DDF/D1' : Item(status='D ', wc_rev='3', treeconflict='C'), - 'DDF/D1/D2' : Item(status='D ', wc_rev='3'), + 'DDF/D1' : Item(status=' ', wc_rev='3', treeconflict='C'), + 'DDF/D1/D2' : Item(status=' ', wc_rev='3'), 'DDF/D1/D2/gamma' : Item(status='D ', wc_rev='3'), }) expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase( "local_leaf_del_incoming_tree_del", leaf_del, @@ -1276,7 +1252,7 @@ def tree_conflicts_on_merge_no_local_ci_6(sbox): expected_skip = svntest.wc.State('', { }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase( "local_tree_del_incoming_tree_del", tree_del, @@ -1305,6 +1281,14 @@ def tree_conflicts_merge_edit_onto_missing(sbox): sbox.build() expected_output = wc.State('', { + # Below the skips + 'DD/D1/D2' : Item(status=' ', treeconflict='U'), + 'DD/D1/D2/epsilon' : Item(status=' ', treeconflict='A'), + 'DDD/D1/D2/D3' : Item(status=' ', treeconflict='U'), + 'DDD/D1/D2/D3/zeta' : Item(status=' ', treeconflict='A'), + 'DDF/D1/D2/gamma' : Item(status=' ', treeconflict='U'), + 'D/D1/delta' : Item(status=' ', treeconflict='A'), + 'DF/D1/beta' : Item(status=' ', treeconflict='U'), }) expected_disk = disk_after_tree_del @@ -1316,52 +1300,40 @@ def tree_conflicts_merge_edit_onto_missing(sbox): 'F' : Item(status=' ', wc_rev=3), 'F/alpha' : Item(status='! ', wc_rev=3), 'D' : Item(status=' ', wc_rev=3), - 'D/D1' : Item(status='! ', wc_rev='?'), + 'D/D1' : Item(status='! ', wc_rev='3', entry_rev='?'), 'DF' : Item(status=' ', wc_rev=3), - 'DF/D1' : Item(status='! ', wc_rev='?'), - 'DF/D1/beta' : Item(status=' '), + 'DF/D1' : Item(status='! ', wc_rev=3, entry_rev='?'), + 'DF/D1/beta' : Item(status='! ', wc_rev=3), 'DD' : Item(status=' ', wc_rev=3), - 'DD/D1' : Item(status='! ', wc_rev='?'), - 'DD/D1/D2' : Item(status=' '), + 'DD/D1' : Item(status='! ', wc_rev=3, entry_rev='?'), + 'DD/D1/D2' : Item(status='! ', wc_rev=3), 'DDF' : Item(status=' ', wc_rev=3), - 'DDF/D1' : Item(status='! ', wc_rev='?'), - 'DDF/D1/D2' : Item(status=' '), - 'DDF/D1/D2/gamma' : Item(status=' '), + 'DDF/D1' : Item(status='! ', wc_rev=3, entry_rev='?'), + 'DDF/D1/D2' : Item(status='! ', wc_rev=3), + 'DDF/D1/D2/gamma' : Item(status='! ', wc_rev=3), 'DDD' : Item(status=' ', wc_rev=3), - 'DDD/D1' : Item(status='! ', wc_rev='?'), - 'DDD/D1/D2' : Item(status=' '), - 'DDD/D1/D2/D3' : Item(status=' '), - }) - - if svntest.main.wc_is_singledb(sbox.wc_dir): - expected_status.tweak('D/D1', wc_rev=3, entry_rev='?') - expected_status.tweak('DF/D1', wc_rev=3, entry_rev='?') - expected_status.tweak('DF/D1/beta', wc_rev=3, status='! ') - expected_status.tweak('DD/D1', wc_rev=3, entry_rev='?') - expected_status.tweak('DD/D1/D2', wc_rev=3, status='! ') - expected_status.tweak('DDF/D1', wc_rev=3, entry_rev='?') - expected_status.tweak('DDF/D1/D2', wc_rev=3, status='! ') - expected_status.tweak('DDF/D1/D2/gamma', wc_rev=3, status='! ') - expected_status.tweak('DDD/D1', wc_rev=3, entry_rev='?') - expected_status.tweak('DDD/D1/D2', wc_rev=3, status='! ') - expected_status.tweak('DDD/D1/D2/D3', wc_rev=3, status='! ') - - expected_skip = svntest.wc.State('', { - 'F/alpha' : Item(), - # BH: After fixing several issues in the obstruction handling - # I get the following Skip notifications. Please review! - 'D/D1' : Item(), - 'DD/D1' : Item(), - 'DF/D1' : Item(), - 'DDD/D1' : Item(), - 'DDF/D1' : Item(), + 'DDD/D1' : Item(status='! ', wc_rev=3, entry_rev='?'), + 'DDD/D1/D2' : Item(status='! ', wc_rev=3), + 'DDD/D1/D2/D3' : Item(status='! ', wc_rev=3), }) + expected_skip = svntest.wc.State('', { + 'F/alpha' : Item(verb='Skipped missing target'), + # Obstruction handling improvements in 1.7 and 1.8 added + 'DDD/D1' : Item(verb='Skipped missing target'), + 'DF/D1' : Item(verb='Skipped missing target'), + 'DDF/D1' : Item(verb='Skipped missing target'), + 'D/D1' : Item(verb='Skipped missing target'), + 'DD/D1' : Item(verb='Skipped missing target'), + 'F/alpha' : Item(verb='Skipped missing target'), + }) - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + # Currently this test fails because some parts of the merge + # start succeeding. + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase( "local_tree_missing_incoming_leaf_edit", - svntest.actions.deep_trees_rmtree, + svntest.deeptrees.deep_trees_rmtree, leaf_edit, expected_output, expected_disk, @@ -1387,6 +1359,11 @@ def tree_conflicts_merge_del_onto_missing(sbox): sbox.build() expected_output = wc.State('', { + # Below the skips + 'DF/D1/beta' : Item(status=' ', treeconflict='D'), + 'DDD/D1/D2/D3' : Item(status=' ', treeconflict='D'), + 'DD/D1/D2' : Item(status=' ', treeconflict='D'), + 'DDF/D1/D2/gamma' : Item(status=' ', treeconflict='D'), }) expected_disk = disk_after_tree_del @@ -1398,52 +1375,37 @@ def tree_conflicts_merge_del_onto_missing(sbox): 'F' : Item(status=' ', wc_rev=3), 'F/alpha' : Item(status='! ', wc_rev=3), 'D' : Item(status=' ', wc_rev=3), - 'D/D1' : Item(status='! ', wc_rev='?'), + 'D/D1' : Item(status='! ', wc_rev=3), 'DF' : Item(status=' ', wc_rev=3), - 'DF/D1' : Item(status='! ', wc_rev='?'), - 'DF/D1/beta' : Item(status=' '), + 'DF/D1' : Item(status='! ', wc_rev=3), + 'DF/D1/beta' : Item(status='! ', wc_rev=3), 'DD' : Item(status=' ', wc_rev=3), - 'DD/D1' : Item(status='! ', wc_rev='?'), - 'DD/D1/D2' : Item(status=' '), + 'DD/D1' : Item(status='! ', wc_rev=3), + 'DD/D1/D2' : Item(status='! ', wc_rev=3), 'DDF' : Item(status=' ', wc_rev=3), - 'DDF/D1' : Item(status='! ', wc_rev='?'), - 'DDF/D1/D2' : Item(status=' '), - 'DDF/D1/D2/gamma' : Item(status=' '), + 'DDF/D1' : Item(status='! ', wc_rev=3), + 'DDF/D1/D2' : Item(status='! ', wc_rev=3), + 'DDF/D1/D2/gamma' : Item(status='! ', wc_rev=3), 'DDD' : Item(status=' ', wc_rev=3), - 'DDD/D1' : Item(status='! ', wc_rev='?'), - 'DDD/D1/D2' : Item(status=' '), - 'DDD/D1/D2/D3' : Item(status=' '), - }) - - if svntest.main.wc_is_singledb(sbox.wc_dir): - expected_status.tweak('D/D1', wc_rev=3) - expected_status.tweak('DF/D1', wc_rev=3) - expected_status.tweak('DF/D1/beta', wc_rev=3, status='! ') - expected_status.tweak('DD/D1', wc_rev=3) - expected_status.tweak('DD/D1/D2', wc_rev=3, status='! ') - expected_status.tweak('DDF/D1', wc_rev=3) - expected_status.tweak('DDF/D1/D2', wc_rev=3, status='! ') - expected_status.tweak('DDF/D1/D2/gamma', wc_rev=3, status='! ') - expected_status.tweak('DDD/D1', wc_rev=3) - expected_status.tweak('DDD/D1/D2', wc_rev=3, status='! ') - expected_status.tweak('DDD/D1/D2/D3', wc_rev=3, status='! ') + 'DDD/D1' : Item(status='! ', wc_rev=3), + 'DDD/D1/D2' : Item(status='! ', wc_rev=3), + 'DDD/D1/D2/D3' : Item(status='! ', wc_rev=3), + }) expected_skip = svntest.wc.State('', { - 'F/alpha' : Item(), - 'D/D1' : Item(), - # BH: After fixing several issues in the obstruction handling - # I get the following Skip notifications. Please review! - 'D/D1' : Item(), - 'DD/D1' : Item(), - 'DF/D1' : Item(), - 'DDD/D1' : Item(), - 'DDF/D1' : Item(), - }) - - svntest.actions.deep_trees_run_tests_scheme_for_merge(sbox, + 'F/alpha' : Item(verb='Skipped missing target'), + 'D/D1' : Item(verb='Skipped missing target'), + # Obstruction handling improvements in 1.7 and 1.8 added + 'DDD/D1' : Item(verb='Skipped missing target'), + 'DD/D1' : Item(verb='Skipped missing target'), + 'DDF/D1' : Item(verb='Skipped missing target'), + 'DF/D1' : Item(verb='Skipped missing target'), + }) + + svntest.deeptrees.deep_trees_run_tests_scheme_for_merge(sbox, [ DeepTreesTestCase( "local_tree_missing_incoming_leaf_del", - svntest.actions.deep_trees_rmtree, + svntest.deeptrees.deep_trees_rmtree, leaf_del, expected_output, expected_disk, @@ -1688,7 +1650,6 @@ def merge_replace_setup(sbox): #---------------------------------------------------------------------- # ra_serf causes duplicate notifications with this test: -@XFail(svntest.main.is_ra_type_dav_serf) @Issue(3802) def merge_replace_causes_tree_conflict(sbox): "replace vs. edit tree-conflicts" @@ -1738,18 +1699,15 @@ def merge_replace_causes_tree_conflict(sbox): 'propname', 'propval', A_D_H) # svn merge $URL/A $URL/branch A - expected_stdout = verify.UnorderedOutput([ - "--- Merging differences between repository URLs into '" + A + "':\n", + expected_stdout = expected_merge_output(None, [ + # merge ' C ' + A_B_E + '\n', ' C ' + A_mu + '\n', ' C ' + A_D_G_pi + '\n', ' C ' + A_D_H + '\n', - "--- Recording mergeinfo for merge between repository URLs into '" \ - + A + "':\n", + # mergeinfo ' U ' + A + '\n', - 'Summary of conflicts:\n', - ' Tree conflicts: 4\n', - ]) + ], target=A, two_url=True, tree_conflicts=4) actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge', url_A, url_branch, A) @@ -1758,13 +1716,11 @@ def merge_replace_causes_tree_conflict(sbox): expected_status.tweak('A', status=' M') expected_status.tweak('A/D/G/pi', 'A/mu', status='M ', treeconflict='C') expected_status.tweak('A/D/H', status=' M', treeconflict='C') - ### A/B/E gets both a property and tree conflict flagged. Is this OK? - expected_status.tweak('A/B/E', status=' C', treeconflict='C') + expected_status.tweak('A/B/E', status=' M', treeconflict='C') actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- -@XFail() @Issue(3806) def merge_replace_causes_tree_conflict2(sbox): "replace vs. delete tree-conflicts" @@ -1825,19 +1781,19 @@ def merge_replace_causes_tree_conflict2(sbox): 'A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', status='D ') + # H is now a file. This hides the status of the descendants. + expected_status.remove('A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega') + # Merge them one by one to see all the errors. ### A file-with-file replacement onto a deleted file. # svn merge $URL/A/mu $URL/branch/mu A/mu - expected_stdout = verify.UnorderedOutput([ - "--- Merging differences between repository URLs into '" + A + "':\n", - ' C ' + A_mu + '\n', - "--- Recording mergeinfo for merge between repository URLs into '" + - A + "':\n", - " U " + A + "\n", - 'Summary of conflicts:\n', - ' Tree conflicts: 1\n', - ]) + expected_stdout = expected_merge_output(None, [ + ' C ' + A_mu + '\n', # merge + 'A ' + A_mu + '\n', # merge + " U " + A + "\n", # mergeinfo + " U " + A_mu + "\n", # mergeinfo -> 'RM' status + ], target=A, two_url=True, tree_conflicts=1) actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge', url_A, url_branch, A, '--depth=files') @@ -1848,20 +1804,16 @@ def merge_replace_causes_tree_conflict2(sbox): # # D C merge_tree_conflict_tests-23\A\mu # > local delete, incoming replace upon merge - expected_status.tweak('A/mu', status='R ', wc_rev='-', copied='+', + expected_status.tweak('A/mu', status='RM', wc_rev='-', copied='+', treeconflict='C') ### A dir-with-dir replacement onto a deleted directory. # svn merge $URL/A/B $URL/branch/B A/B - expected_stdout = verify.UnorderedOutput([ - "--- Merging differences between repository URLs into '" + A_B + "':\n", - ' C ' + A_B_E + '\n', - "--- Recording mergeinfo for merge between repository URLs into '" + - A_B + "':\n", - " U " + A_B + "\n", - 'Summary of conflicts:\n', - ' Tree conflicts: 1\n', - ]) + expected_stdout = expected_merge_output(None, [ + ' C ' + A_B_E + '\n', # merge + 'A ' + A_B_E + '\n', # merge + " U " + A_B + "\n", # mergeinfo + ], target=A_B, two_url=True, tree_conflicts=1) actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge', url_A_B, url_branch_B, A_B) @@ -1877,16 +1829,11 @@ def merge_replace_causes_tree_conflict2(sbox): ### A dir-with-file replacement onto a deleted directory. # svn merge --depth=immediates $URL/A/D $URL/branch/D A/D - expected_stdout = verify.UnorderedOutput([ - "--- Merging differences between repository URLs into '" + A_D + "':\n", - ' C ' + A_D_H + '\n', - "--- Recording mergeinfo for merge between repository URLs into '" + - A_D + "':\n", - " U " + A_D + "\n", - " U " + A_D_G + "\n", - 'Summary of conflicts:\n', - ' Tree conflicts: 1\n', - ]) + expected_stdout = expected_merge_output(None, [ + ' C ' + A_D_H + '\n', # merge + 'A ' + A_D_H + '\n', # merge + " U " + A_D + "\n", # mergeinfo + ], target=A_D, two_url=True, tree_conflicts=1) actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge', '--depth=immediates', url_A_D, url_branch_D, A_D) @@ -1902,20 +1849,11 @@ def merge_replace_causes_tree_conflict2(sbox): ### A file-with-dir replacement onto a deleted file. # svn merge $URL/A/D/G $URL/branch/D/G A/D/G - expected_stdout = verify.UnorderedOutput([ - "--- Merging differences between repository URLs into '" + A_D_G + - "':\n", - ' C ' + A_D_G_pi + '\n', - "--- Recording mergeinfo for merge between repository URLs into '" + - A_D_G + "':\n", - "--- Eliding mergeinfo from '" + A_D_G_pi + "':\n", - " U " + A_D_G_pi + "\n", - "--- Eliding mergeinfo from '" + A_D_G_pi + "':\n", - " U " + A_D_G_pi + "\n", - " G " + A_D_G + "\n", - 'Summary of conflicts:\n', - ' Tree conflicts: 1\n', - ]) + expected_stdout = expected_merge_output(None, [ + ' C ' + A_D_G_pi + '\n', # merge + 'A ' + A_D_G_pi + '\n', # merge + " U " + A_D_G + "\n", # mergeinfo + ], target=A_D_G, two_url=True, tree_conflicts=1) actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge', url_A_D_G, url_branch_D_G, A_D_G) @@ -1934,12 +1872,194 @@ def merge_replace_causes_tree_conflict2(sbox): # Check the tree conflict types: expected_stdout = '(R.*)|(Summary of conflicts.*)|( Tree conflicts.*)' \ - '|(.*local delete, incoming replace upon merge.*)' + '|(.*local delete, incoming replace upon merge.*)' \ + '|( \>.*)' tree_conflicted_path = [A_B_E, A_mu, A_D_G_pi, A_D_H] for path in tree_conflicted_path: actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'st', '--depth=empty', path) +#---------------------------------------------------------------------- +# Test for issue #4011 'merge of replacement on local delete fails' +@SkipUnless(server_has_mergeinfo) +@Issue(4011) +def merge_replace_on_del_fails(sbox): + "merge replace on local delete fails" + + sbox.build() + wc_dir = sbox.wc_dir + + C_path = os.path.join(wc_dir, 'A', 'C') + branch_path = os.path.join(wc_dir, 'branch') + C_branch_path = os.path.join(wc_dir, 'branch', 'C') + + # r2 - Copy ^/A to ^/branch + svntest.actions.run_and_verify_svn(None, None, [], 'copy', + sbox.repo_url + '/A', + sbox.repo_url + '/branch', + '-m', 'Create a branch') + + # r3 - Replace A/C + svntest.actions.run_and_verify_svn(None, None, [], 'del', C_path) + svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', C_path) + svntest.actions.run_and_verify_svn(None, None, [], 'ci', + '-m', 'Replace A/C', wc_dir) + + # r4 - Delete branch/C + svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) + svntest.actions.run_and_verify_svn(None, None, [], 'del', C_branch_path) + svntest.actions.run_and_verify_svn(None, None, [], 'ci', + '-m', 'Delete branch/C', wc_dir) + + # Sync merge ^/A to branch + svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) + expected_stdout = expected_merge_output([[2,4]], [ + ' C ' + C_branch_path + '\n', # merge + ' U ' + branch_path + '\n', # mergeinfo + ], target=branch_path, tree_conflicts=1) + # This currently fails with: + # + # >svn merge ^/A branch + # ..\..\..\subversion\svn\util.c:913: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:11349: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:11303: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:11303: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:11273: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:9287: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:8870: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:5349: (apr_err=155010) + # ..\..\..\subversion\libsvn_repos\reporter.c:1430: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\ra.c:247: (apr_err=155010) + # ..\..\..\subversion\libsvn_repos\reporter.c:1269: (apr_err=155010) + # ..\..\..\subversion\libsvn_repos\reporter.c:1205: (apr_err=155010) + # ..\..\..\subversion\libsvn_repos\reporter.c:920: (apr_err=155010) + # ..\..\..\subversion\libsvn_delta\cancel.c:120: (apr_err=155010) + # ..\..\..\subversion\libsvn_delta\cancel.c:120: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\repos_diff.c:710: (apr_err=155010) + # ..\..\..\subversion\libsvn_client\merge.c:2234: (apr_err=155010) + # ..\..\..\subversion\libsvn_wc\adm_ops.c:1069: (apr_err=155010) + # ..\..\..\subversion\libsvn_wc\adm_ops.c:956: (apr_err=155010) + # ..\..\..\subversion\libsvn_wc\update_editor.c:5036: (apr_err=155010) + # ..\..\..\subversion\libsvn_wc\wc_db.c:6985: (apr_err=155010) + # ..\..\..\subversion\libsvn_wc\wc_db.c:6929: (apr_err=155010) + # ..\..\..\subversion\libsvn_wc\wc_db.c:6920: (apr_err=155010) + # svn: E155010: The node 'C:\SVN\src-trunk\Debug\subversion\tests\ + # cmdline\svn-test-work\working_copies\merge_tree_conflict_tests-24\ + # branch\C' was not found. + actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'merge', + sbox.repo_url + '/A', branch_path) + +def merge_obstruction_recording(sbox): + "merge obstruction recording" + + sbox.build() + wc_dir = sbox.wc_dir + + sbox.simple_rm('iota', 'A') + sbox.simple_mkdir('trunk') + sbox.simple_mkdir('branches') + sbox.simple_commit() #r2 + + svntest.actions.run_and_verify_svn(None, None, [], + 'copy', sbox.repo_url + '/trunk', + sbox.repo_url + '/branches/branch', + '-mCopy') # r3 + + sbox.simple_mkdir('trunk/dir') + sbox.simple_add_text('The file on trunk\n', 'trunk/dir/file.txt') + sbox.simple_commit() #r4 + + sbox.simple_update() + + sbox.simple_mkdir('branches/branch/dir') + sbox.simple_add_text('The file on branch\n', 'branches/branch/dir/file.txt') + sbox.simple_commit() #r5 + + sbox.simple_update() + + svntest.actions.run_and_verify_svn(None, None, [], + 'switch', '^/branches/branch', wc_dir, + '--ignore-ancestry') + + expected_output = wc.State(wc_dir, { + 'dir' : Item(status=' ', treeconflict='C'), + 'dir/file.txt' : Item(status=' ', treeconflict='A'), + }) + expected_mergeinfo_output = wc.State(wc_dir, { + '' : Item(status=' U'), + 'dir' : Item(status=' U'), # Because dir already exists + }) + expected_elision_output = wc.State(wc_dir, { + }) + expected_disk = wc.State('', { + 'dir/file.txt' : Item(contents="The file on branch\n"), + 'dir' : Item(props={'svn:mergeinfo':''}), + '.' : Item(props={'svn:mergeinfo':'/trunk:3-5'}), + }) + expected_status = wc.State(wc_dir, { + '' : Item(status=' M', wc_rev='5'), + 'dir' : Item(status=' M', treeconflict='C', wc_rev='5'), + 'dir/file.txt' : Item(status=' ', wc_rev='5'), + }) + expected_skip = wc.State('', { + }) + svntest.actions.run_and_verify_merge(wc_dir, '2', '5', sbox.repo_url + '/trunk', + None, + expected_output, + expected_mergeinfo_output, + expected_elision_output, + expected_disk, + expected_status, + expected_skip, + check_props=True) + expected_info = [ + { + "Path" : re.escape(sbox.ospath('dir')), + "Tree conflict": re.escape( + 'local dir obstruction, incoming dir add upon merge' + + ' Source left: (dir) ^/trunk/dir@2' + # Should be '(none)' + ' Source right: (dir) ^/trunk/dir@5') + }, + ] + + svntest.actions.run_and_verify_info(expected_info, sbox.ospath('dir')) + + # How should the user handle this conflict? + # ### Would be nice if we could just accept mine (leave as is, fix mergeinfo) + # ### or accept theirs (delete what is here and insert copy + svntest.actions.run_and_verify_svn(None, None, [], + 'resolve', '--accept=working', + sbox.ospath('dir')) + + # Redo the skipped merge as record only merge + expected_output = [ + '--- Recording mergeinfo for merge of r5 into \'%s\':\n' % \ + sbox.ospath('dir'), + ' G %s\n' % sbox.ospath('dir'), + ] + # ### Why are r1-r3 not recorded? + # ### Guess: Because dir's history only exists since r4. + svntest.actions.run_and_verify_svn(None, expected_output, [], + 'merge', '--record-only', + sbox.repo_url + '/trunk/dir', + sbox.ospath('dir'), + '-c', '2-5') + + expected_disk = wc.State('', { + 'dir' : Item(props={'svn:mergeinfo':'/trunk/dir:5'}), + 'dir/file.txt' : Item(contents="The file on branch\n"), + '.' : Item(props={'svn:mergeinfo':'/trunk:3-5'}), + }) + svntest.actions.verify_disk(wc_dir, expected_disk, check_props=True) + + # Because r2-r4 are not recorded, the mergeinfo is not elided :( + + # Even something like a two url merge wouldn't work, because dir + # didn't exist below trunk in r2 either. + + # A resolver action could be smarter though... + + ######################################################################## # Run the tests @@ -1969,6 +2089,8 @@ test_list = [ None, tree_conflicts_merge_del_onto_missing, merge_replace_causes_tree_conflict, merge_replace_causes_tree_conflict2, + merge_replace_on_del_fails, + merge_obstruction_recording, ] if __name__ == '__main__': |