You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by as...@apache.org on 2012/11/24 21:29:48 UTC
svn commit: r1413258 [28/33] - in /subversion/branches/compressed-pristines:
./ build/ build/ac-macros/ build/generator/ build/generator/templates/
contrib/client-side/emacs/ contrib/server-side/fsfsfixer/ notes/
notes/directory-index/ subversion/ subv...
Added: subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py?rev=1413258&view=auto
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py (added)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py Sat Nov 24 20:29:11 2012
@@ -0,0 +1,1022 @@
+#!/usr/bin/env python
+#
+# merge_automatic_tests.py: testing "automatic merge" scenarios
+#
+# Subversion is a tool for revision control.
+# See http://subversion.apache.org for more information.
+#
+# ====================================================================
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+######################################################################
+
+# General modules
+import shutil, sys, re, os
+import time
+
+# Our testing module
+import svntest
+from svntest import main, wc, verify, actions
+
+# (abbreviation)
+Item = wc.StateItem
+Skip = svntest.testcase.Skip_deco
+SkipUnless = svntest.testcase.SkipUnless_deco
+XFail = svntest.testcase.XFail_deco
+Issues = svntest.testcase.Issues_deco
+Issue = svntest.testcase.Issue_deco
+Wimp = svntest.testcase.Wimp_deco
+
+from svntest.main import SVN_PROP_MERGEINFO
+from svntest.main import server_has_mergeinfo
+from merge_tests import local_path
+from merge_tests import expected_merge_output
+from merge_tests import svn_merge
+from merge_tests import set_up_branch
+
+#----------------------------------------------------------------------
+
+# Merging scenarios to test
+#
+# Merge once
+#
+# A (--?---
+# ( \
+# B (--?--x
+#
+# Merge twice in same direction
+#
+# A (--o-----?---
+# ( \ \
+# B (--o--x--?--x
+#
+# Merge to and fro
+#
+# A (--o-----?--x
+# ( \ /
+# B (--o--x--?---
+#
+# A (--o-----o-----?--x
+# ( \ \ /
+# B (--o--x--o--x--?---
+#
+# A (--o-----o--x--?--x
+# ( \ / /
+# B (--o--x--o-----?---
+#
+# A (--o-----o--x--?---
+# ( \ / \
+# B (--o--x--o-----?--x
+#
+# Merge with cherry-picks
+#
+# Cherry1, fwd
+# A (--o-----o-[o]----o---
+# ( \ \ \
+# B (--o--x--?-----c-----x
+#
+# Cherry2, fwd
+# A (--o-----?-----c--o---
+# ( \ / \
+# B (--o--x--o-[o]-------x
+#
+# Cherry3, fwd
+# A (--o-----?-------c--o----
+# ( \_____ / \
+# ( \ / \
+# B (--o--o-[o]-x-/---------x
+# \__/
+#
+# Cherry1, back
+# A (--o-----o-[o]-------x
+# ( \ \ /
+# B (--o--x--?-----c--o---
+#
+# Cherry2, back
+# A (--o-----?-----c-----x
+# ( \ / /
+# B (--o--x--o-[o]----o---
+#
+# Cherry3, back
+# A (--o-----?-------c------x
+# ( \_____ / /
+# ( \ / /
+# B (--o--o-[o]-x-/-----o----
+# \__/
+#
+# Criss-cross merge
+#
+# A (--o--?--x--?----
+# ( \ / \
+# ( X \
+# ( / \ \
+# B (--o--?--x--?---x
+#
+# Subtree mergeinfo
+#
+# subtree to, fro
+# A (--o-o-o-o---------x
+# ( \ \ /
+# ( \ \ /
+# B ( o--o------s--
+#
+# merge to, reverse cherry subtree to, merge to
+# A (--o-o-o-o------------------
+# ( \ \ \ \
+# ( \ \ \ \
+# B ( o--o------x-------rcs----x
+#
+# Sparse WC
+#
+# ...
+#
+# Mixed-rev WC
+#
+# ...
+#
+#
+# Key to diagrams:
+#
+# o - an original change
+# ? - an original change or no-op (test both)
+# x - a branch root merge
+# c - a cherry-pick merge
+# [o] - source range of a cherry-pick merge
+# s - a subtree merge
+# r - reverse merge
+
+
+########################################################################
+
+def assert_equal(a, b):
+ """Assert that two generic Python objects are equal. If not, raise an
+ exception giving their values. Rationale: During debugging, it's
+ easier to see what's wrong if we see the values rather than just
+ an indication that the assertion failed."""
+ if a != b:
+ raise Exception("assert_equal failed: a = (%s), b = (%s)" % (a, b))
+
+def logical_changes_in_branch(sbox, branch):
+ """Return the set of logical changes that are actually in branch BRANCH
+ (at its current working version), by examining the state of the
+ branch files and directories rather than its mergeinfo.
+
+ Each logical change is described by its branch and revision number
+ as a string such as 'A1'."""
+ changes = set()
+ for propname in sbox.simple_proplist(branch + '/D').keys():
+ if propname.startswith('prop-'):
+ changes.add(propname[5:])
+ return changes
+
+def get_mergeinfo_change(sbox, target):
+ """Return a list of revision numbers representing the mergeinfo change
+ on TARGET (working version against base). Non-recursive."""
+ exit, out, err = actions.run_and_verify_svn(None, None, [],
+ 'diff', '--depth=empty',
+ sbox.ospath(target))
+ merged_revs = []
+ for line in out:
+ match = re.match(r' Merged /(\w+):r(.*)', line)
+ if match:
+ for r_range in match.group(2).split(','):
+ if '-' in r_range:
+ r_start, r_end = r_range.split('-')
+ else:
+ r_start = r_end = r_range
+ merged_revs += range(int(r_start), int(r_end) + 1)
+ return merged_revs
+
+def get_3ways_from_output(output):
+ """Scan the list of lines OUTPUT for indications of 3-way merges.
+ Return a list of (base, source-right) tuples."""
+ ### Problem: test suite strips debugging output within run_and_verify_...()
+ ### so we don't see it here. And relying on debug output is a temporary
+ ### measure only. Better to access svn_client_find_automatic_merge()
+ ### directly, via bindings?
+
+ merges = []
+ for line in output:
+ print "## " + line,
+ # Extract "A1" from a line like "DBG: merge.c:11336: base svn://.../A@1"
+ match = re.search(r'merge\.c:.* base .* /(\w+)@([0-9-]+)', line)
+ if match:
+ base = match.group(1) + match.group(2)
+ match = re.search(r'merge\.c:.* right.* /(\w+)@([0-9-]+)', line)
+ if match:
+ right = match.group(1) + match.group(2)
+ assert base is not None
+ merges.append((base, right))
+ base = None
+ return merges
+
+def make_branches(sbox):
+ """Make branches A and B."""
+ sbox.build()
+ sbox.simple_copy('A', 'B')
+ sbox.simple_commit()
+ os.chdir(sbox.wc_dir)
+ sbox.wc_dir = ''
+
+def modify_branch(sbox, branch, number, conflicting=False):
+ """Commit a modification to branch BRANCH. The actual modification depends
+ on NUMBER. If CONFLICTING=True, the change will be of a kind that
+ conflicts with any other change that has CONFLICTING=True. We don't
+ modify (properties on) the branch root node itself, to make it easier
+ for the tests to distinguish mergeinfo changes from these mods."""
+ uniq = branch + str(number) # something like 'A1' or 'B2'
+ if conflicting:
+ sbox.simple_propset('conflict', uniq, branch + '/C')
+ else:
+ # Make some changes. We add a property, which we will read later in
+ # logical_changes_in_branch() to check that the correct logical
+ # changes were merged. We add a file, so that we will notice if
+ # Subversion tries to merge this same logical change into a branch
+ # that already has it (it will raise a tree conflict).
+ sbox.simple_propset('prop-' + uniq, uniq, branch + '/D')
+ sbox.simple_copy(branch + '/mu', branch + '/mu-' + uniq)
+ sbox.simple_commit()
+
+def expected_automatic_merge_output(target, expect_3ways):
+ """Calculate the expected output."""
+
+ # (This is rather specific to the current implementation.)
+
+ # Match a notification for each rev-range.
+ if expect_3ways:
+ rev_ranges = []
+ for base, right in expect_3ways:
+ if base[0] == right[0]:
+ base_rev = int(base[1:])
+ right_rev = int(right[1:])
+ rev_ranges += [(base_rev + 1, right_rev)];
+ else:
+ rev_ranges = None
+
+ # Match any content modifications; but not of the root of the branch
+ # because we don't intentionally modify the branch root node in most
+ # tests and we don't want to accidentally overlook a mergeinfo change.
+ lines = ["(A |D |[UG] | [UG]|[UG][UG]) " + target + os.path.sep + ".*\n"]
+
+ # Match mergeinfo changes. (### Subtrees are not yet supported here.)
+ lines += [" [UG] " + target + "\n"]
+
+ # At the moment, the automatic merge code sometimes says 'Merging
+ # differences between repository URLs' and sometimes 'Merging r3 through
+ # r5', but it's not trivial to predict which, so expect either form.
+ lines += ["--- Merging .* into '%s':\n" % (target,),
+ "--- Recording mergeinfo for merge .* into '%s':\n" % (target,)]
+
+ return expected_merge_output(rev_ranges, lines, target=target)
+
+def automatic_merge(sbox, source, target, args=[],
+ expect_changes=None, expect_mi=None, expect_3ways=None):
+ """Do a complete, automatic merge from path SOURCE to path TARGET, and
+ commit. Verify the output and that there is no error.
+ ### TODO: Verify the changes made.
+
+ ARGS are additional arguments passed to svn merge."""
+
+ source = local_path(source)
+ target = local_path(target)
+
+ # First, update the WC target because mixed-rev is not fully supported.
+ sbox.simple_update(target)
+
+ before_changes = logical_changes_in_branch(sbox, target)
+
+ exp_out = expected_automatic_merge_output(target, expect_3ways)
+ exit, out, err = svntest.actions.run_and_verify_svn(None, exp_out, [],
+ 'merge',
+ '^/' + source, target,
+ *args)
+
+ if expect_changes is not None:
+ after_changes = logical_changes_in_branch(sbox, target)
+ merged_changes = after_changes - before_changes
+ assert_equal(merged_changes, set(expect_changes))
+ reversed_changes = before_changes - after_changes
+ assert_equal(reversed_changes, set())
+
+ if expect_mi is not None:
+ actual_mi_change = get_mergeinfo_change(sbox, target)
+ assert_equal(actual_mi_change, expect_mi)
+
+ if expect_3ways is not None:
+ ### actual_3ways = get_3ways_from_output(out)
+ ### assert_equal(actual_3ways, expect_3ways)
+ pass
+
+ sbox.simple_commit()
+
+def three_way_merge(base_node, source_right_node):
+ return (base_node, source_right_node)
+
+def three_way_merge_no_op(base_node, source_right_node):
+ return (base_node, source_right_node)
+
+def cherry_pick(sbox, rev, source, target):
+ """Cherry-pick merge revision REV from branch SOURCE to branch TARGET
+ (both WC-relative paths), and commit."""
+ sbox.simple_update(target)
+ svn_merge(rev, source, target)
+ sbox.simple_commit()
+
+no_op_commit__n = 0
+def no_op_commit(sbox):
+ """Commit a new revision that does not affect the branches under test."""
+
+ global no_op_commit__n
+ sbox.simple_propset('foo', str(no_op_commit__n), 'iota')
+ no_op_commit__n += 1
+ sbox.simple_commit('iota')
+
+
+#----------------------------------------------------------------------
+
+def init_mod_merge_mod(sbox, mod_6, mod_7):
+ """Modify both branches, merge A -> B, optionally modify again.
+ MOD_6 is True to modify A in r6, MOD_7 is True to modify B in r7,
+ otherwise make no-op commits for r6 and/or r7."""
+
+ # A (--o------?-
+ # ( \
+ # B (---o--x---?
+ # 2 34 5 67
+
+ make_branches(sbox)
+ modify_branch(sbox, 'A', 3)
+ modify_branch(sbox, 'B', 4)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A3'],
+ expect_mi=[2, 3, 4],
+ expect_3ways=[three_way_merge('A1', 'A4')])
+
+ if mod_6:
+ modify_branch(sbox, 'A', 6)
+ else:
+ no_op_commit(sbox) # r6
+
+ if mod_7:
+ modify_branch(sbox, 'B', 7)
+ else:
+ no_op_commit(sbox) # r7
+
+########################################################################
+
+# Merge once
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_1(sbox):
+ """merge_once_1"""
+
+ # A (------
+ # ( \
+ # B (-----x
+ # 2 34 5
+
+ make_branches(sbox)
+ no_op_commit(sbox) # r3
+ no_op_commit(sbox) # r4
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=[],
+ expect_mi=[2, 3, 4],
+ expect_3ways=[three_way_merge_no_op('A1', 'A4')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_2(sbox):
+ """merge_once_2"""
+
+ # A (-o----
+ # ( \
+ # B (-----x
+ # 2 34 5
+
+ make_branches(sbox)
+ modify_branch(sbox, 'A', 3)
+ no_op_commit(sbox) # r4
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A3'],
+ expect_mi=[2, 3, 4],
+ expect_3ways=[three_way_merge('A1', 'A4')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_3(sbox):
+ """merge_once_3"""
+
+ # A (------
+ # ( \
+ # B (--o--x
+ # 2 34 5
+
+ make_branches(sbox)
+ no_op_commit(sbox) # r3
+ modify_branch(sbox, 'B', 4)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=[],
+ expect_mi=[2, 3, 4],
+ expect_3ways=[three_way_merge_no_op('A1', 'A4')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_4(sbox):
+ """merge_once_4"""
+
+ # A (-o----
+ # ( \
+ # B (--o--x
+ # 2 34 5
+
+ make_branches(sbox)
+ modify_branch(sbox, 'A', 3)
+ modify_branch(sbox, 'B', 4)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A3'],
+ expect_mi=[2, 3, 4],
+ expect_3ways=[three_way_merge('A1', 'A4')])
+
+#----------------------------------------------------------------------
+
+# Merge twice in same direction
+
+@SkipUnless(server_has_mergeinfo)
+def merge_twice_same_direction_1(sbox):
+ """merge_twice_same_direction_1"""
+
+ # A (--o-----------
+ # ( \ \
+ # B (---o--x------x
+ # 2 34 5 67 8
+
+ init_mod_merge_mod(sbox, mod_6=False, mod_7=False)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=[],
+ expect_mi=[5, 6, 7],
+ expect_3ways=[three_way_merge_no_op('A4', 'A7')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_twice_same_direction_2(sbox):
+ """merge_twice_same_direction_2"""
+
+ # A (--o------o----
+ # ( \ \
+ # B (---o--x---o--x
+ # 2 34 5 67 8
+
+ init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A6'],
+ expect_mi=[5, 6, 7],
+ expect_3ways=[three_way_merge('A4', 'A7')])
+
+#----------------------------------------------------------------------
+
+# Merge to and fro
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_1_1(sbox):
+ """merge_to_and_fro_1_1"""
+
+ # A (--o----------x
+ # ( \ /
+ # B (---o--x-------
+ # 2 34 5 67 8
+
+ init_mod_merge_mod(sbox, mod_6=False, mod_7=False)
+
+ automatic_merge(sbox, 'B', 'A',
+ expect_changes=['B4'],
+ expect_mi=[2, 3, 4, 5, 6, 7],
+ expect_3ways=[three_way_merge('A4', 'B7')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_1_2(sbox):
+ """merge_to_and_fro_1_2"""
+
+ # A (--o------o---x
+ # ( \ /
+ # B (---o--x---o---
+ # 2 34 5 67 8
+
+ init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+ automatic_merge(sbox, 'B', 'A',
+ expect_changes=['B4', 'B7'],
+ expect_mi=[2, 3, 4, 5, 6, 7],
+ expect_3ways=[three_way_merge('A4', 'B7')])
+
+def init_merge_to_and_fro_2(sbox, mod_9, mod_10):
+ """Set up branches A and B for the merge_to_and_fro_2 scenarios.
+ MOD_9 is True to modify A in r9, MOD_10 is True to modify B in r10,
+ otherwise make no-op commits for r9 and/or r10."""
+
+ # A (--o------o------?-
+ # ( \ \
+ # B (---o--x---o--x---?
+ # 2 34 5 67 8--90
+
+ init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A6'],
+ expect_mi=[5, 6, 7],
+ expect_3ways=[three_way_merge('A4', 'A7')])
+
+ if mod_9:
+ modify_branch(sbox, 'A', 9)
+ else:
+ no_op_commit(sbox) # r9
+
+ if mod_10:
+ modify_branch(sbox, 'B', 10)
+ else:
+ no_op_commit(sbox) # r10
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_2_1(sbox):
+ """merge_to_and_fro_2_1"""
+
+ # A (--o------o----------x
+ # ( \ \ /
+ # B (---o--x---o--x-------
+ # 2 34 5 67 8 90 1
+
+ init_merge_to_and_fro_2(sbox, mod_9=False, mod_10=False)
+
+ automatic_merge(sbox, 'B', 'A',
+ expect_changes=['B4', 'B7'],
+ expect_mi=[2, 3, 4, 5, 6, 7, 8, 9, 10],
+ expect_3ways=[three_way_merge('A7', 'B10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_2_2(sbox):
+ """merge_to_and_fro_2_2"""
+
+ # A (--o------o------o---x
+ # ( \ \ /
+ # B (---o--x---o--x---o---
+ # 2 34 5 67 8 90 1
+
+ init_merge_to_and_fro_2(sbox, mod_9=True, mod_10=True)
+
+ automatic_merge(sbox, 'B', 'A',
+ expect_changes=['B4', 'B7', 'B10'],
+ expect_mi=[2, 3, 4, 5, 6, 7, 8, 9, 10],
+ expect_3ways=[three_way_merge('A7', 'B10')])
+
+def init_merge_to_and_fro_3(sbox, mod_9, mod_10):
+ """Set up branches A and B for the merge_to_and_fro_3/4 scenarios.
+ MOD_9 is True to modify A in r9, MOD_10 is True to modify B in r10,
+ otherwise make no-op commits for r9 and/or r10."""
+
+ # A (--o------o---x--?-
+ # ( \ /
+ # B (---o--x---o------?
+ # 2 34 5 67 8 90
+
+ init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+ automatic_merge(sbox, 'B', 'A',
+ expect_changes=['B4', 'B7'],
+ expect_mi=[2, 3, 4, 5, 6, 7],
+ expect_3ways=[three_way_merge('A4', 'B7')])
+
+ if mod_9:
+ modify_branch(sbox, 'A', 9)
+ else:
+ no_op_commit(sbox) # r9
+
+ if mod_10:
+ modify_branch(sbox, 'B', 10)
+ else:
+ no_op_commit(sbox) # r10
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_3_1(sbox):
+ """merge_to_and_fro_3_1"""
+
+ # A (--o------o---x------x
+ # ( \ / /
+ # B (---o--x---o----------
+ # 2 34 5 67 8 90 1
+
+ init_merge_to_and_fro_3(sbox, mod_9=False, mod_10=False)
+
+ automatic_merge(sbox, 'B', 'A',
+ expect_changes=[],
+ expect_mi=[8, 9, 10],
+ expect_3ways=[three_way_merge_no_op('B7', 'B10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_3_2(sbox):
+ """merge_to_and_fro_3_2"""
+
+ # A (--o------o---x--o---x
+ # ( \ / /
+ # B (---o--x---o------o---
+ # 2 34 5 67 8 90 1
+
+ init_merge_to_and_fro_3(sbox, mod_9=True, mod_10=True)
+
+ automatic_merge(sbox, 'B', 'A',
+ expect_changes=['B10'],
+ expect_mi=[8, 9, 10],
+ expect_3ways=[three_way_merge('B7', 'B10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_4_1(sbox):
+ """merge_to_and_fro_4_1"""
+
+ # A (--o------o---x-------
+ # ( \ / \
+ # B (---o--x---o---------x
+ # 2 34 5 67 8 90 1
+
+ init_merge_to_and_fro_3(sbox, mod_9=False, mod_10=False)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A6'],
+ expect_mi=[5, 6, 7, 8, 9, 10],
+ expect_3ways=[three_way_merge_no_op('B7', 'A10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_4_2(sbox):
+ """merge_to_and_fro_4_2"""
+
+ # A (--o------o---x--o----
+ # ( \ / \
+ # B (---o--x---o------o--x
+ # 2 34 5 67 8 90 1
+
+ init_merge_to_and_fro_3(sbox, mod_9=True, mod_10=True)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A6', 'A9'],
+ expect_mi=[5, 6, 7, 8, 9, 10],
+ expect_3ways=[three_way_merge('B7', 'A10')])
+
+#----------------------------------------------------------------------
+
+# Cherry-pick scenarios
+
+@SkipUnless(server_has_mergeinfo)
+def cherry1_fwd(sbox):
+ """cherry1_fwd"""
+
+ # A (--o------o--[o]----o---
+ # ( \ \ \
+ # B (---o--x---------c-----x
+ # 2 34 5 67 8 9 0 1
+
+ init_mod_merge_mod(sbox, mod_6=True, mod_7=False)
+ modify_branch(sbox, 'A', 8)
+ cherry_pick(sbox, 8, 'A', 'B')
+ modify_branch(sbox, 'A', 10)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A6', 'A10'], # and NOT A8
+ expect_mi=[5, 6, 7, 9, 10],
+ expect_3ways=[three_way_merge('A4', 'A7'),
+ three_way_merge('A8', 'A10')])
+
+@SkipUnless(server_has_mergeinfo)
+@XFail()
+def cherry2_fwd(sbox):
+ """cherry2_fwd"""
+
+ # A (--o-------------c--o---
+ # ( \ / \
+ # B (---o--x---o-[o]-------x
+ # 2 34 5 67 8 9 0 1
+
+ init_mod_merge_mod(sbox, mod_6=False, mod_7=True)
+ modify_branch(sbox, 'B', 8)
+ cherry_pick(sbox, 8, 'B', 'A')
+ modify_branch(sbox, 'A', 10)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A10'], # and NOT A9
+ expect_mi=[5, 6, 7, 8, 9, 10],
+ expect_3ways=[three_way_merge('A9', 'A10')])
+
+@SkipUnless(server_has_mergeinfo)
+@XFail()
+def cherry3_fwd(sbox):
+ """cherry3_fwd"""
+
+ # A (--o--------------c--o----
+ # ( \ / \
+ # ( \ / \
+ # B (---o--o-[o]-x-/---------x
+ # \__/
+ # 2 34 5 6 7 8 9 0
+
+ make_branches(sbox)
+ modify_branch(sbox, 'A', 3)
+ modify_branch(sbox, 'B', 4)
+ modify_branch(sbox, 'B', 5)
+ modify_branch(sbox, 'B', 6)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A3'],
+ expect_mi=[2, 3, 4, 5, 6],
+ expect_3ways=[three_way_merge('A1', 'A6')])
+
+ cherry_pick(sbox, 6, 'B', 'A')
+ modify_branch(sbox, 'A', 9)
+
+ automatic_merge(sbox, 'A', 'B',
+ expect_changes=['A9'], # and NOT A8
+ expect_mi=[7, 8, 9],
+ expect_3ways=[three_way_merge('A8', 'A9')])
+
+#----------------------------------------------------------------------
+# Automatic merges ignore subtree mergeinfo during reintegrate.
+@SkipUnless(server_has_mergeinfo)
+@XFail()
+def subtree_to_and_fro(sbox):
+ "reintegrate considers source subtree mergeinfo"
+
+# A (--o-o-o-o---------x
+# ( \ \ /
+# ( \ \ /
+# B ( o--o------s--
+
+ # Some paths we'll care about.
+ A_COPY_gamma_path = sbox.ospath('A_COPY/D/gamma')
+ psi_path = sbox.ospath('A/D/H/psi')
+ A_COPY_D_path = sbox.ospath('A_COPY/D')
+ A_path = sbox.ospath('A')
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then
+ # make a few edits under A in r3-6:
+ wc_disk, wc_status = set_up_branch(sbox)
+
+ # r7 - Edit a file on the branch.
+ svntest.main.file_write(A_COPY_gamma_path, "Branch edit to 'gamma'.\n")
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir,
+ '-m', 'Edit a file on our branch')
+
+ # r8 - Do a subtree sync merge from ^/A/D to A_COPY/D.
+ # Note that among other things this changes A_COPY/D/H/psi.
+ svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+ svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+ sbox.repo_url + '/A/D', A_COPY_D_path)
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir,
+ '-m', 'Automatic subtree merge')
+
+ # r9 - Make an edit to A/D/H/psi.
+ svntest.main.file_write(psi_path, "Trunk Edit to 'psi'.\n")
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir,
+ '-m', 'Edit a file on our trunk')
+
+ # Now reintegrate ^/A_COPY back to A. To the automatic merge code the
+ # subtree merge to A_COPY/D just looks like any other branch edit, it is
+ # not considered a merge. So the changes which exist on A/D and were
+ # merged to A_COPY/D, are merged *back* to A, resulting in a conflict:
+ #
+ # C:\SVN\src-trunk\Debug\subversion\tests\cmdline\svn-test-work\
+ # working_copies\merge_automatic_tests-18>svn merge ^^/A_COPY A
+ # DBG: merge.c:11461: base on source: file:///C:/SVN/src-trunk/Debug/
+ # subversion/tests/cmdline/svn-test-work/repositories/
+ # merge_automatic_tests-18/A@1
+ # DBG: merge.c:11462: base on target: file:///C:/SVN/src-trunk/Debug/
+ # subversion/tests/cmdline/svn-test-work/repositories/
+ # merge_automatic_tests-18/A@1
+ # DBG: merge.c:11567: yca file:///C:/SVN/src-trunk/Debug/subversion/
+ # tests/cmdline/svn-test-work/repositories/merge_automatic_tests-18/A@1
+ # DBG: merge.c:11568: base file:///C:/SVN/src-trunk/Debug/subversion/
+ # tests/cmdline/svn-test-work/repositories/merge_automatic_tests-18/A@1
+ # DBG: merge.c:11571: right file:///C:/SVN/src-trunk/Debug/subversion/
+ # tests/cmdline/svn-test-work/repositories/merge_automatic_tests-18/
+ # A_COPY@8
+ # Conflict discovered in file 'A\D\H\psi'.
+ # Select: (p) postpone, (df) diff-full, (e) edit,
+ # (mc) mine-conflict, (tc) theirs-conflict,
+ # (s) show all options: p
+ # --- Merging r2 through r9 into 'A':
+ # C A\D\H\psi
+ # U A\D\gamma
+ # --- Recording mergeinfo for merge of r2 through r9 into 'A':
+ # U A
+ # Summary of conflicts:
+ # Text conflicts: 1
+ svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+ exit_code, out, err = svntest.actions.run_and_verify_svn(
+ None, [], svntest.verify.AnyOutput,
+ 'merge', sbox.repo_url + '/A_COPY', A_path)
+
+ # The 'old' merge produced a warning that reintegrate could not be used.
+ # Not claiming this is perfect, but it's better(?) than a conflict:
+ svntest.verify.verify_outputs("Automatic Reintegrate failed, but not "
+ "in the way expected",
+ err, None,
+ "(svn: E195016: Reintegrate can only be used if "
+ "revisions 2 through 9 were previously "
+ "merged from .*/A to the reintegrate source, "
+ "but this is not the case:\n)"
+ "|( A_COPY\n)"
+ "|( Missing ranges: /A:5\n)"
+ "|(\n)"
+ "|(.*apr_err.*)", # In case of debug build
+ None,
+ True) # Match *all* lines of stdout
+
+#----------------------------------------------------------------------
+# Automatic merges ignore subtree mergeinfo gaps older than the last rev
+# synced to the target root.
+@SkipUnless(server_has_mergeinfo)
+def merge_to_reverse_cherry_subtree_to_merge_to(sbox):
+ "sync merge considers target subtree mergeinfo"
+
+ # A (--o-o-o-o------------------
+ # ( \ \ \ \
+ # ( \ \ \ \
+ # B ( o--o------x-------rc-----x
+
+ # Some paths we'll care about.
+ A_COPY_path = sbox.ospath('A_COPY')
+ A_COPY_B_path = sbox.ospath('A_COPY/B')
+ A_COPY_beta_path = sbox.ospath('A_COPY/B/E/beta')
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then
+ # make a few edits under A in r3-6:
+ wc_disk, wc_status = set_up_branch(sbox)
+
+ # Sync merge ^/A to A_COPY, then reverse merge r5 from ^/A/B to A_COPY/B.
+ # This results in mergeinfo on the target which makes it appear that the
+ # branch is synced up to r6, but the subtree mergeinfo on A_COPY/B reveals
+ # that r5 has not been merged to that subtree:
+ #
+ # Properties on 'A_COPY':
+ # svn:mergeinfo
+ # /A:2-6
+ # Properties on 'A_COPY\B':
+ # svn:mergeinfo
+ # /A/B:2-4,6
+ svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+ svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+ sbox.repo_url + '/A', A_COPY_path)
+ svntest.actions.run_and_verify_svn(None, None, [], 'merge', '-c-5',
+ sbox.repo_url + '/A/B',
+ A_COPY_B_path)
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m',
+ 'sync merge and reverse subtree merge')
+
+ # Try an automatic sync merge from ^/A to A_COPY. Revision 5 should be
+ # merged to A_COPY/B as its subtree mergeinfo reveals that rev is missing,
+ # like so:
+ #
+ # >svn merge ^/A A_COPY
+ # --- Merging r5 into 'A_COPY\B':
+ # U A_COPY\B\E\beta
+ # --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY':
+ # U A_COPY
+ # --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY\B':
+ # U A_COPY\B
+ # --- Eliding mergeinfo from 'A_COPY\B':
+ # U A_COPY\B
+ #
+ # But the merge ignores the subtree mergeinfo and considers
+ # only the mergeinfo on the target itself (and thus is a no-op but for
+ # the mergeinfo change on the root of the merge target):
+ #
+ # >svn merge ^/A A_COPY
+ # --- Recording mergeinfo for merge of r7 into 'A_COPY':
+ # U A_COPY
+ #
+ # >svn diff
+ # Index: A_COPY
+ # ===================================================================
+ # --- A_COPY (revision 7)
+ # +++ A_COPY (working copy)
+ #
+ # Property changes on: A_COPY
+ # ___________________________________________________________________
+ # Modified: svn:mergeinfo
+ # Merged /A:r7
+ svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+ expected_output = wc.State(A_COPY_path, {
+ 'B/E/beta' : Item(status='U '),
+ })
+ expected_mergeinfo_output = wc.State(A_COPY_path, {
+ '' : Item(status=' U'),
+ 'B' : Item(status=' U'),
+ })
+ expected_elision_output = wc.State(A_COPY_path, {
+ 'B' : Item(status=' U'),
+ })
+ expected_status = wc.State(A_COPY_path, {
+ '' : Item(status=' M'),
+ 'B' : Item(status=' M'),
+ 'mu' : Item(status=' '),
+ 'B/E' : Item(status=' '),
+ 'B/E/alpha' : Item(status=' '),
+ 'B/E/beta' : Item(status='M '),
+ 'B/lambda' : Item(status=' '),
+ 'B/F' : Item(status=' '),
+ 'C' : Item(status=' '),
+ 'D' : Item(status=' '),
+ 'D/G' : Item(status=' '),
+ 'D/G/pi' : Item(status=' '),
+ 'D/G/rho' : Item(status=' '),
+ 'D/G/tau' : Item(status=' '),
+ 'D/gamma' : Item(status=' '),
+ 'D/H' : Item(status=' '),
+ 'D/H/chi' : Item(status=' '),
+ 'D/H/psi' : Item(status=' '),
+ 'D/H/omega' : Item(status=' '),
+ })
+ expected_status.tweak(wc_rev='7')
+ expected_disk = wc.State('', {
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A:2-7'}),
+ 'B' : Item(),
+ 'mu' : Item("This is the file 'mu'.\n"),
+ 'B/E' : Item(),
+ 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
+ 'B/E/beta' : Item("New content"),
+ 'B/lambda' : Item("This is the file 'lambda'.\n"),
+ 'B/F' : Item(),
+ 'C' : Item(),
+ 'D' : Item(),
+ 'D/G' : Item(),
+ 'D/G/pi' : Item("This is the file 'pi'.\n"),
+ 'D/G/rho' : Item("New content"),
+ 'D/G/tau' : Item("This is the file 'tau'.\n"),
+ 'D/gamma' : Item("This is the file 'gamma'.\n"),
+ 'D/H' : Item(),
+ 'D/H/chi' : Item("This is the file 'chi'.\n"),
+ 'D/H/psi' : Item("New content"),
+ 'D/H/omega' : Item("New content"),
+ })
+ expected_skip = wc.State(A_COPY_path, { })
+ svntest.actions.run_and_verify_merge(A_COPY_path, None, None,
+ sbox.repo_url + '/A', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None,
+ None, 1, 0, A_COPY_path)
+
+########################################################################
+# Run the tests
+
+
+# list all tests here, starting with None:
+test_list = [ None,
+ merge_once_1,
+ merge_once_2,
+ merge_once_3,
+ merge_once_4,
+ merge_twice_same_direction_1,
+ merge_twice_same_direction_2,
+ merge_to_and_fro_1_1,
+ merge_to_and_fro_1_2,
+ merge_to_and_fro_2_1,
+ merge_to_and_fro_2_2,
+ merge_to_and_fro_3_1,
+ merge_to_and_fro_3_2,
+ merge_to_and_fro_4_1,
+ merge_to_and_fro_4_2,
+ cherry1_fwd,
+ cherry2_fwd,
+ cherry3_fwd,
+ subtree_to_and_fro,
+ merge_to_reverse_cherry_subtree_to_merge_to,
+ ]
+
+if __name__ == '__main__':
+ svntest.main.run_tests(test_list)
+ # NOTREACHED
+
+
+### End of file.
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py Sat Nov 24 20:29:11 2012
@@ -5799,14 +5799,14 @@ def merge_to_path_with_switched_children
expected_mergeinfo_output = wc.State(A_COPY_D_path, {
'' : Item(status=' G'),
'H' : Item(status=' G'),
- 'H/psi' : Item(status=' G')
+ 'H/psi' : Item(status=' U')
})
expected_elision_output = wc.State(A_COPY_D_path, {
})
expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
expected_disk_D.tweak('H/psi', contents="New content",
- props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5,8'})
+ props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5'})
expected_status_D.tweak('H/psi', status='MM')
svntest.actions.run_and_verify_merge(A_COPY_D_path, '4', '5',
sbox.repo_url + '/A/D', None,
@@ -5869,7 +5869,7 @@ def merge_to_path_with_switched_children
'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'}),
'D/H/chi' : Item("This is the file 'chi'.\n"),
'D/H/psi' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5,8'}),
+ props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5'}),
'D/H/omega' : Item("New content"),
})
expected_skip = wc.State(A_COPY_path, { })
@@ -17826,6 +17826,60 @@ def merge_with_added_subtrees_with_merge
None, None, None, None,
None, 1, 0)
+#----------------------------------------------------------------------
+@SkipUnless(server_has_mergeinfo)
+def merge_with_externals_with_mergeinfo(sbox):
+ "merge with externals with mergeinfo"
+
+ # Some paths we'll care about.
+ A_path = sbox.ospath('A')
+ A_COPY_path = sbox.ospath('A_COPY')
+ file_external_path = sbox.ospath('A/file-external')
+ mu_COPY_path = sbox.ospath('A_COPY/mu')
+ mu_path = sbox.ospath('A/mu')
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Make a branch of ^/A and then make a few edits under A in r3-6:
+ wc_disk, wc_status = set_up_branch(sbox)
+
+ svntest.main.file_write(mu_COPY_path, "branch edit")
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+ 'file edit on the branch', wc_dir)
+ svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+
+ # Create a file external under 'A' and set some bogus mergeinfo
+ # on it (the fact that this mergeinfo is bogus has no bearing on
+ # this test).
+ svntest.actions.run_and_verify_svn(None, None, [], 'propset',
+ 'svn:externals',
+ '^/iota file-external', A_path)
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+ 'set file external', wc_dir)
+ svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+ svntest.actions.run_and_verify_svn(None, None, [], 'ps', SVN_PROP_MERGEINFO,
+ "/bogus-mergeinfo:5", file_external_path)
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+ 'set mergeinfo on file external',
+ file_external_path)
+
+ # Sync merge ^/A to A_COPY and then reintegrate A_COPY back to A.
+ svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+ sbox.repo_url + '/A', A_COPY_path)
+ svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+ 'sync merge', wc_dir)
+ # This was segfaulting, see
+ # http://svn.haxx.se/dev/archive-2012-10/0364.shtml
+ svntest.actions.run_and_verify_svn(
+ None,
+ expected_merge_output(None,
+ ['U ' + mu_path + '\n',
+ ' U ' + A_path + '\n'],
+ two_url=True),
+ [], 'merge', '--reintegrate', sbox.repo_url + '/A_COPY',
+ A_path)
+
########################################################################
# Run the tests
@@ -17961,6 +18015,7 @@ test_list = [ None,
reverse_merge_with_rename,
merge_adds_then_deletes_subtree,
merge_with_added_subtrees_with_mergeinfo,
+ merge_with_externals_with_mergeinfo,
]
if __name__ == '__main__':
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py Sat Nov 24 20:29:11 2012
@@ -1671,7 +1671,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"
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py Sat Nov 24 20:29:11 2012
@@ -72,7 +72,8 @@ def no_mergeinfo(sbox):
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
[],
sbox.repo_url + '/A',
- sbox.repo_url + '/A2')
+ sbox.repo_url + '/A2',
+ "--show-revs=merged")
def mergeinfo(sbox):
"'mergeinfo' on a path with mergeinfo"
@@ -94,7 +95,8 @@ def mergeinfo(sbox):
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
['3'],
sbox.repo_url + '/A',
- sbox.ospath('A2'))
+ sbox.ospath('A2'),
+ "--show-revs=merged")
@SkipUnless(server_has_mergeinfo)
def explicit_mergeinfo_source(sbox):
@@ -132,13 +134,17 @@ def explicit_mergeinfo_source(sbox):
# Check using each of our recorded merge sources (as paths and URLs).
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
- ['2', '4'], url(B2), path(B))
+ ['2', '4'], url(B2), path(B),
+ "--show-revs=merged")
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
- ['2', '4'], path(B2), path(B))
+ ['2', '4'], path(B2), path(B),
+ "--show-revs=merged")
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
- ['3', '5'], url(B3), path(B))
+ ['3', '5'], url(B3), path(B),
+ "--show-revs=merged")
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
- ['3', '5'], path(B3), path(B))
+ ['3', '5'], path(B3), path(B),
+ "--show-revs=merged")
@SkipUnless(server_has_mergeinfo)
def mergeinfo_non_source(sbox):
@@ -162,7 +168,8 @@ def mergeinfo_non_source(sbox):
# Check on a source we haven't "merged" from.
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
- [], H2_url, H_path)
+ [], H2_url, H_path,
+ "--show-revs=merged")
#----------------------------------------------------------------------
# Issue #3138
@@ -238,7 +245,8 @@ def non_inheritable_mergeinfo(sbox):
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
['4','6*'],
sbox.repo_url + '/A',
- A_COPY_path)
+ A_COPY_path,
+ '--show-revs', 'merged')
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
['3','5','6*'],
sbox.repo_url + '/A',
@@ -249,7 +257,8 @@ def non_inheritable_mergeinfo(sbox):
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
['4'],
sbox.repo_url + '/A/D',
- D_COPY_path)
+ D_COPY_path,
+ '--show-revs', 'merged')
svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
['3','6'],
sbox.repo_url + '/A/D',
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py Sat Nov 24 20:29:11 2012
@@ -3997,24 +3997,57 @@ def patch_target_no_eol_at_eof(sbox):
patch_file_path = make_patch_path(sbox)
iota_path = sbox.ospath('iota')
+ mu_path = sbox.ospath('A/mu')
iota_contents = [
"This is the file iota."
]
+ mu_contents = [
+ "context\n",
+ "context\n",
+ "context\n",
+ "context\n",
+ "This is the file mu.\n",
+ "context\n",
+ "context\n",
+ "context\n",
+ "context", # no newline at end of file
+ ]
+
svntest.main.file_write(iota_path, ''.join(iota_contents))
+ svntest.main.file_write(mu_path, ''.join(mu_contents))
expected_output = svntest.wc.State(wc_dir, {
'iota' : Item(verb='Sending'),
+ 'A/mu' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('iota', wc_rev=2)
+ expected_status.tweak('A/mu', wc_rev=2)
svntest.actions.run_and_verify_commit(wc_dir, expected_output,
expected_status, None, wc_dir)
unidiff_patch = [
- "--- iota\t(revision 1)\n",
+ "Index: A/mu\n",
+ "===================================================================\n",
+ "--- A/mu\t(revision 2)\n",
+ "+++ A/mu\t(working copy)\n",
+ "@@ -2,8 +2,8 @@ context\n",
+ " context\n",
+ " context\n",
+ " context\n",
+ "-This is the file mu.\n",
+ "+It is really the file mu.\n",
+ " context\n",
+ " context\n",
+ " context\n",
+ " context\n",
+ "\\ No newline at end of file\n",
+ "Index: iota\n",
+ "===================================================================\n",
+ "--- iota\t(revision 2)\n",
"+++ iota\t(working copy)\n",
- "@@ -1,7 +1,7 @@\n",
- "-This is the file iota.\n"
+ "@@ -1 +1 @@\n",
+ "-This is the file iota.\n",
"\\ No newline at end of file\n",
"+It is really the file 'iota'.\n",
"\\ No newline at end of file\n",
@@ -4025,15 +4058,29 @@ def patch_target_no_eol_at_eof(sbox):
iota_contents = [
"It is really the file 'iota'."
]
+ mu_contents = [
+ "context\n",
+ "context\n",
+ "context\n",
+ "context\n",
+ "It is really the file mu.\n",
+ "context\n",
+ "context\n",
+ "context\n",
+ "context", # no newline at end of file
+ ]
expected_output = [
+ 'U %s\n' % sbox.ospath('A/mu'),
'U %s\n' % sbox.ospath('iota'),
]
expected_disk = svntest.main.greek_state.copy()
expected_disk.tweak('iota', contents=''.join(iota_contents))
+ expected_disk.tweak('A/mu', contents=''.join(mu_contents))
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('iota', status='M ', wc_rev=2)
+ expected_status.tweak('A/mu', status='M ', wc_rev=2)
expected_skip = wc.State('', { })
@@ -4099,6 +4146,61 @@ def patch_add_and_delete(sbox):
1, # check-props
1) # dry-run
+
+def patch_git_with_index_line(sbox):
+ "apply git patch with 'index' line"
+
+ sbox.build(read_only = True)
+ wc_dir = sbox.wc_dir
+ patch_file_path = make_patch_path(sbox)
+
+ unidiff_patch = [
+ "diff --git a/src/tools/ConsoleRunner/hi.txt b/src/tools/ConsoleRunner/hi.txt\n",
+ "new file mode 100644\n",
+ "index 0000000..c82a38f\n",
+ "--- /dev/null\n",
+ "+++ b/src/tools/ConsoleRunner/hi.txt\n",
+ "@@ -0,0 +1 @@\n",
+ "+hihihihihihi\n",
+ "\ No newline at end of file\n",
+ ]
+
+ svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+ expected_output = [
+ 'A %s\n' % sbox.ospath('src'),
+ 'A %s\n' % sbox.ospath('src/tools'),
+ 'A %s\n' % sbox.ospath('src/tools/ConsoleRunner'),
+ 'A %s\n' % sbox.ospath('src/tools/ConsoleRunner/hi.txt'),
+ ]
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({
+ 'src/' : Item(status='A ', wc_rev=0),
+ 'src/tools' : Item(status='A ', wc_rev=0),
+ 'src/tools/ConsoleRunner/' : Item(status='A ', wc_rev=0),
+ 'src/tools/ConsoleRunner/hi.txt' : Item(status='A ', wc_rev=0),
+ })
+
+ expected_disk = svntest.main.greek_state.copy()
+ expected_disk.add({'src' : Item(),
+ 'src/tools' : Item(),
+ 'src/tools/ConsoleRunner' : Item(),
+ 'src/tools/ConsoleRunner/hi.txt' :
+ Item(contents="hihihihihihi")
+ })
+
+ expected_skip = wc.State('', { })
+
+ svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+ expected_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, # expected err
+ 1, # check-props
+ 1) # dry-run
+
########################################################################
#Run the tests
@@ -4143,6 +4245,7 @@ test_list = [ None,
patch_delete_and_skip,
patch_target_no_eol_at_eof,
patch_add_and_delete,
+ patch_git_with_index_line,
]
if __name__ == '__main__':
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py Sat Nov 24 20:29:11 2012
@@ -33,6 +33,8 @@ logger = logging.getLogger()
import svntest
from svntest.main import SVN_PROP_MERGEINFO
+from svntest.main import SVN_PROP_INHERITABLE_IGNORES
+from svntest import wc
# (abbreviation)
Skip = svntest.testcase.Skip_deco
@@ -2047,7 +2049,7 @@ def atomic_over_ra(sbox):
sbox.build(create_wc=False)
repo_url = sbox.repo_url
- # From this point on, similar to ../libsvn_fs-fs-test.c:revision_props().
+ # From this point on, similar to ../libsvn_fs/fs-test.c:revision_props().
s1 = "violet"
s2 = "wrong value"
@@ -2507,6 +2509,167 @@ def pristine_props_listed(sbox):
svntest.actions.run_and_verify_svn(None, expected_output, [],
'proplist', '-R', wc_dir, '-r', 'BASE')
+def create_inherited_ignores_config(config_dir):
+ "create config stuffs for inherited ignores tests"
+
+ # contents of the file 'config'
+ config_contents = '''\
+[miscellany]
+global-ignores = *.boo *.goo
+'''
+
+ svntest.main.create_config_dir(config_dir, config_contents)
+
+def inheritable_ignores(sbox):
+ "inheritable ignores with svn:ignores and config"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ tmp_dir = os.path.abspath(svntest.main.temp_dir)
+ config_dir = os.path.join(tmp_dir, 'autoprops_config_' + sbox.name)
+ create_inherited_ignores_config(config_dir)
+
+ sbox.simple_propset(SVN_PROP_INHERITABLE_IGNORES, '*.doo', 'A/B')
+ sbox.simple_propset(SVN_PROP_INHERITABLE_IGNORES, '*.moo', 'A/D')
+ sbox.simple_propset('svn:ignore', '*.foo', 'A/B/E')
+ sbox.simple_commit()
+
+ # Some directories and files that should be added because they don't
+ # match any applicable ignores.
+ X_dir_path = os.path.join(wc_dir, 'ADD-ME-DIR-X')
+ Y_dir_path = os.path.join(wc_dir, 'A', 'ADD-ME-DIR-Y.doo')
+ Z_dir_path = os.path.join(wc_dir, 'A', 'D', 'G', 'ADD-ME-DIR-Z.doo')
+ os.mkdir(X_dir_path)
+ os.mkdir(Y_dir_path)
+ os.mkdir(Z_dir_path)
+
+ # Some directories and files that should be ignored when adding
+ # because they match an ignore pattern (unless of course they are
+ # the direct target of an add, which we always add).
+ boo_dir_path = os.path.join(wc_dir, 'IGNORE-ME-DIR.boo')
+ goo_dir_path = os.path.join(wc_dir, 'IGNORE-ME-DIR.boo', 'IGNORE-ME-DIR.goo')
+ doo_dir_path = os.path.join(wc_dir, 'A', 'B', 'IGNORE-ME-DIR.doo')
+ moo_dir_path = os.path.join(wc_dir, 'A', 'D', 'IGNORE-ME-DIR.moo')
+ foo_dir_path = os.path.join(wc_dir, 'A', 'B', 'E', 'IGNORE-ME-DIR.foo')
+ os.mkdir(boo_dir_path)
+ os.mkdir(goo_dir_path)
+ os.mkdir(doo_dir_path)
+ os.mkdir(moo_dir_path)
+ os.mkdir(foo_dir_path)
+ boo_file_path = sbox.ospath('ADD-ME-DIR-X/ignore-me-file.boo')
+ goo_file_path = sbox.ospath('A/D/G/ignore-me-file.goo')
+ doo_file_path = sbox.ospath('A/B/IGNORE-ME-DIR.doo/ignore-me-file.doo')
+ doo_file2_path = sbox.ospath('A/B/E/ignore-me-file.doo')
+ moo_file_path = sbox.ospath('A/D/ignore-me-file.moo')
+ foo_file_path = sbox.ospath('A/B/E/ignore-me-file.foo')
+ svntest.main.file_write(boo_file_path, 'I should not be versioned!\n')
+ svntest.main.file_write(goo_file_path, 'I should not be versioned!\n')
+ svntest.main.file_write(doo_file_path, 'I should not be versioned!\n')
+ svntest.main.file_write(doo_file2_path, 'I should not be versioned!\n')
+ svntest.main.file_write(moo_file_path, 'I should not be versioned!\n')
+ svntest.main.file_write(foo_file_path, 'I should not be versioned!\n')
+
+ # Some directories and files that don't match any ignore pattern
+ # but are located within a subtree that does match and so shouldn't
+ # be added.
+ roo_file_path = sbox.ospath('A/B/IGNORE-ME-DIR.doo/ignore-me-file.roo')
+ svntest.main.file_write(roo_file_path, 'I should not be versioned!\n')
+
+ # Check (non-verbose) status with the custom config. We should only see
+ # the three unversioned directories which don't match any of the ignore
+ # patterns and aren't proper subtrees of an unversioned or ignored
+ # subtree.
+ expected_output = svntest.verify.UnorderedOutput(
+ ['? ' + X_dir_path + '\n',
+ '? ' + Y_dir_path + '\n',
+ '? ' + Z_dir_path + '\n',])
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'st',
+ '--config-dir', config_dir, wc_dir)
+
+ # Check status without the custom config.
+ # Should be the same as above except the *.boo and *.goo paths
+ # now show up as unversioned '?'.
+ expected_output = svntest.verify.UnorderedOutput(
+ ['? ' + X_dir_path + '\n',
+ '? ' + Y_dir_path + '\n',
+ '? ' + Z_dir_path + '\n',
+ '? ' + boo_dir_path + '\n',
+ '? ' + goo_file_path + '\n',])
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'st', wc_dir)
+
+ # Check status with the custom config and --no-ignore.
+ expected_output = svntest.verify.UnorderedOutput(
+ ['? ' + X_dir_path + '\n',
+ '? ' + Y_dir_path + '\n',
+ '? ' + Z_dir_path + '\n',
+ 'I ' + boo_dir_path + '\n',
+ 'I ' + doo_dir_path + '\n',
+ 'I ' + doo_file2_path + '\n',
+ 'I ' + moo_dir_path + '\n',
+ 'I ' + foo_dir_path + '\n',
+ 'I ' + goo_file_path + '\n',
+ 'I ' + moo_file_path + '\n',
+ 'I ' + foo_file_path + '\n',])
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'st',
+ '--config-dir', config_dir,
+ '--no-ignore', wc_dir)
+
+ # Check status without the custom config and --no-ignore.
+ # Should be the same as above except the *.boo and *.goo paths
+ # are reported as unversioned '?' rather than ignored 'I'.
+ expected_output = svntest.verify.UnorderedOutput(
+ ['? ' + X_dir_path + '\n',
+ '? ' + Y_dir_path + '\n',
+ '? ' + Z_dir_path + '\n',
+ '? ' + boo_dir_path + '\n',
+ 'I ' + doo_dir_path + '\n',
+ 'I ' + doo_file2_path + '\n',
+ 'I ' + moo_dir_path + '\n',
+ 'I ' + foo_dir_path + '\n',
+ '? ' + goo_file_path + '\n',
+ 'I ' + moo_file_path + '\n',
+ 'I ' + foo_file_path + '\n',])
+ svntest.actions.run_and_verify_svn(None, expected_output, [], 'st',
+ '--no-ignore', wc_dir)
+
+ # Perform the add with the --force flag, targeting the root of the WC.
+ ### Note: You have to be inside the working copy or else Subversion
+ ### will think you're trying to add the working copy to its parent
+ ### directory, and will (possibly, if the parent directory isn't
+ ### versioned) fail -- see also schedule_tests.py 11 "'svn add'
+ ### should traverse already-versioned dirs"
+ saved_wd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ expected = svntest.verify.UnorderedOutput(
+ ['A ' + 'ADD-ME-DIR-X\n',
+ 'A ' + os.path.join('A', 'ADD-ME-DIR-Y.doo') + '\n',
+ 'A ' + os.path.join('A', 'D', 'G', 'ADD-ME-DIR-Z.doo') + '\n'])
+ svntest.actions.run_and_verify_svn("Adds in spite of ignores", expected,
+ [], 'add', '.', '--force',
+ '--config-dir', config_dir)
+ os.chdir(saved_wd)
+
+ # Now revert and try the add with the --no-ignore flag, only the
+ # svn:inheritable-ignores should be enforced.
+ svntest.actions.run_and_verify_svn(None, None, [], 'revert', wc_dir, '-R')
+ saved_wd = os.getcwd()
+ os.chdir(sbox.wc_dir)
+ expected = svntest.verify.UnorderedOutput(
+ ['A ' + 'ADD-ME-DIR-X\n',
+ 'A ' + os.path.join('A', 'ADD-ME-DIR-Y.doo') + '\n',
+ 'A ' + os.path.join('A', 'D', 'G', 'ADD-ME-DIR-Z.doo') + '\n',
+ 'A ' + os.path.join('ADD-ME-DIR-X', 'ignore-me-file.boo') + '\n',
+ 'A ' + 'IGNORE-ME-DIR.boo' + '\n',
+ 'A ' + os.path.join('IGNORE-ME-DIR.boo',
+ 'IGNORE-ME-DIR.goo') + '\n',
+ 'A ' + os.path.join('A', 'B', 'E', 'IGNORE-ME-DIR.foo') + '\n',
+ 'A ' + os.path.join('A', 'B', 'E', 'ignore-me-file.foo') + '\n',
+ 'A ' + os.path.join('A', 'D', 'G', 'ignore-me-file.goo') + '\n'])
+ svntest.actions.run_and_verify_svn("Adds in spite of ignores", expected,
+ [], 'add', '.', '--force','--no-ignore',
+ '--config-dir', config_dir)
+
########################################################################
# Run the tests
@@ -2549,6 +2712,7 @@ test_list = [ None,
propget_redirection,
file_matching_dir_prop_reject,
pristine_props_listed,
+ inheritable_ignores,
]
if __name__ == '__main__':
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py Sat Nov 24 20:29:11 2012
@@ -25,7 +25,7 @@
######################################################################
# General modules
-import shutil, sys, re, os
+import shutil, sys, re, os, stat
import time
# Our testing module
@@ -106,7 +106,6 @@ def automatic_conflict_resolution(sbox):
# Test for issue #3707 'property conflicts not handled correctly by
# svn resolve'.
@Issue(3707)
-@XFail()
def prop_conflict_resolution(sbox):
"resolving prop conflicts"
@@ -225,8 +224,8 @@ def prop_conflict_resolution(sbox):
# 2) 'A/mu' - An incoming prop edit on a local prop modification.
# 3) 'A/D/gamma' - An local, non-conflicted prop edit
#
- # This currently fails because svn resolve --accept=[theirs-conflict |
- # theirs-full] removes the conflicts, but doesn't install 'their' version
+ # Previously this failed because svn resolve --accept=[theirs-conflict |
+ # theirs-full] removed the conflicts, but didn't install 'their' version
# of the conflicted properties.
do_prop_conflicting_up_and_resolve('mine-full',
['local_edit\n'],
@@ -244,6 +243,35 @@ def prop_conflict_resolution(sbox):
[], # Prop deleted
['incoming-conflict\n'])
+@SkipUnless(svntest.main.is_posix_os)
+def auto_resolve_executable_file(sbox):
+ "resolve file with executable bit set"
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Mark iota as executable
+ sbox.simple_propset("svn:executable", '*', 'iota')
+ sbox.simple_commit() # r2
+
+ # Make a change to iota in r3
+ svntest.main.file_write(sbox.ospath('iota'), "boo\n")
+ sbox.simple_commit() # r3
+
+ # Update back to r2, and tweak iota to provoke a text conflict
+ sbox.simple_update(revision=2)
+ svntest.main.file_write(sbox.ospath('iota'), "bzzt\n")
+
+ # Get permission bits of iota
+ mode = os.stat(sbox.ospath('iota'))[stat.ST_MODE]
+
+ # Update back to r3, and auto-resolve the text conflict.
+ svntest.main.run_svn(False, 'update', wc_dir, '--accept', 'theirs-full')
+
+ # permission bits of iota should be unaffected
+ if mode != os.stat(sbox.ospath('iota'))[stat.ST_MODE]:
+ raise svntest.Failure
+
+
########################################################################
# Run the tests
@@ -251,6 +279,7 @@ def prop_conflict_resolution(sbox):
test_list = [ None,
automatic_conflict_resolution,
prop_conflict_resolution,
+ auto_resolve_executable_file,
]
if __name__ == '__main__':
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py Sat Nov 24 20:29:11 2012
@@ -563,6 +563,7 @@ def status_add_deleted_directory(sbox):
# Regression test for issue #939:
# Recursive 'svn add' should still traverse already-versioned dirs.
@Issue(939)
+@Issue(4241)
def add_recursive_already_versioned(sbox):
"'svn add' should traverse already-versioned dirs"
@@ -592,8 +593,8 @@ def add_recursive_already_versioned(sbox
### or else Subversion will think you're trying to add the working copy
### to its parent directory, and will (possibly, if the parent directory
### isn't versioned) fail.
- #svntest.main.run_svn(None, 'add', '--force', wc_dir)
- #svntest.actions.run_and_verify_status(wc_dir, expected_status)
+ svntest.main.run_svn(None, 'add', '--force', wc_dir)
+ svntest.actions.run_and_verify_status(wc_dir, expected_status)
# Now revert, and do the adds again from inside the working copy.
svntest.main.run_svn(None, 'revert', '--recursive', wc_dir)
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py Sat Nov 24 20:29:11 2012
@@ -759,7 +759,6 @@ def symlink_destination_change(sbox):
# (disk and metadata).
@Issue(3884)
@SkipUnless(svntest.main.is_posix_os)
-@XFail()
def merge_foreign_symlink(sbox):
"merge symlink-add from foreign repos"
@@ -790,7 +789,7 @@ def merge_foreign_symlink(sbox):
# Verify special status.
expected_disk = svntest.main.greek_state.copy()
expected_disk.add({
- 'A/zeta': Item(props={ 'svn:special': '*' })
+ 'A/zeta': Item(contents="link target", props={ 'svn:special': '*' })
})
svntest.actions.verify_disk(sbox.ospath(''), expected_disk, True)
@@ -820,7 +819,7 @@ def symlink_to_wc_basic(sbox):
wc_uuid = svntest.actions.get_wc_uuid(wc_dir)
expected_info = [{
'Path' : re.escape(os.path.join(symlink_path)),
- 'Working Copy Root Path' : re.escape(os.path.abspath(symlink_path)),
+ 'Working Copy Root Path' : re.escape(os.path.abspath(wc_dir)),
'Repository Root' : sbox.repo_url,
'Repository UUID' : wc_uuid,
'Revision' : '1',
@@ -829,7 +828,7 @@ def symlink_to_wc_basic(sbox):
}, {
'Name' : 'iota',
'Path' : re.escape(os.path.join(symlink_path, 'iota')),
- 'Working Copy Root Path' : re.escape(os.path.abspath(symlink_path)),
+ 'Working Copy Root Path' : re.escape(os.path.abspath(wc_dir)),
'Repository Root' : sbox.repo_url,
'Repository UUID' : wc_uuid,
'Revision' : '1',
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py Sat Nov 24 20:29:11 2012
@@ -986,25 +986,19 @@ def status_ignored_dir(sbox):
#----------------------------------------------------------------------
-@Issue(2030)
-def status_unversioned_dir(sbox):
- "status on unversioned dir"
- sbox.build(read_only = True, create_wc = False)
- dir = sbox.wc_dir
- svntest.main.safe_rmtree(sbox.wc_dir)
- os.mkdir(dir)
-
- # Depending on whether you run the tests below a working copy
- # or not, the error message might either be something like
- # svn: warning: W155007: '...copies/stat_tests-19' is not a working copy
- # or
- # svn: warning: W155010: The node '...copies/stat_tests-19' was not found.
+def status_unversioned_dir_in_wc(sbox):
+ "status on unversioned dir in working copy"
+ sbox.build(read_only = True)
- expected_err = "svn: warning: W1550(07|10): .*'.*(/|\\\\)" + \
- os.path.basename(dir) + \
- "' (is not a working copy|was not found)"
+ # Create two unversioned directories within the test working copy
+ path = sbox.ospath('1/2')
+ os.makedirs(path)
+
+ expected_err = "svn: warning: (W155007|W155010): .*'.*(/|\\\\)" + \
+ os.path.basename(path) + \
+ "' was not found"
svntest.actions.run_and_verify_svn2(None, [], expected_err, 0,
- "status", dir, dir)
+ "status", path)
#----------------------------------------------------------------------
@@ -1883,14 +1877,6 @@ def status_nested_wc_old_format(sbox):
os.chdir(wc_dir)
svntest.actions.run_and_verify_svn(None, [ "? subdir\n" ], [], 'st')
-########################################################################
-# Run the tests
-
-
-def simple_lock(sbox, relpath):
- path = os.path.join(sbox.wc_dir, relpath)
- svntest.actions.run_and_verify_svn(None, None, [], 'lock', path)
-
#----------------------------------------------------------------------
# Regression test for issue #3855 "status doesn't show 'K' on a locked
# deleted node".
@@ -1902,7 +1888,8 @@ def status_locked_deleted(sbox):
iota_path = sbox.ospath('iota')
sbox.simple_rm('iota')
- simple_lock(sbox, 'iota')
+ svntest.actions.run_and_verify_svn(None, None, [], 'lock',
+ os.path.join(sbox.wc_dir, 'iota'))
svntest.actions.run_and_verify_svn(None, ['D K %s\n' % iota_path], [],
'status', iota_path)
@@ -2036,6 +2023,19 @@ def status_not_present(sbox):
sbox.ospath('A/mu'),
sbox.ospath('no-file'))
+# Skip this test is a .svn dir exists in the root directory
+@Skip(lambda: os.path.exists("/%s" % svntest.main.get_admin_name()))
+def status_unversioned_dir(sbox):
+ "status on unversioned dir"
+ sbox.build(read_only = True, create_wc = False)
+
+ # Run svn status on "/", which we assume exists and isn't a WC.
+ # This should work on UNIX-like systems and Windows systems
+ expected_err = "svn: warning: W1550(07|10): .*'.*(/|\\\\)" + \
+ "' is not a working copy"
+ svntest.actions.run_and_verify_svn2(None, [], expected_err, 0,
+ "status", "/")
+
########################################################################
# Run the tests
@@ -2060,7 +2060,7 @@ test_list = [ None,
missing_dir_in_anchor,
status_in_xml,
status_ignored_dir,
- status_unversioned_dir,
+ status_unversioned_dir_in_wc,
status_missing_dir,
status_nonrecursive_update_different_cwd,
status_add_plus_conflict,
@@ -2080,6 +2080,7 @@ test_list = [ None,
wclock_status,
modified_modulo_translation,
status_not_present,
+ status_unversioned_dir,
]
if __name__ == '__main__':
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py Sat Nov 24 20:29:11 2012
@@ -78,6 +78,12 @@ def check_hotcopy_fsfs(src, dst):
"source" % src_dirent)
# Compare all files in this directory
for src_file in src_files:
+ # Exclude temporary files
+ if src_file == 'rev-prop-atomicsShm':
+ continue
+ if src_file == 'rev-prop-atomicsMutex':
+ continue
+
src_path = os.path.join(src_dirpath, src_file)
dst_path = os.path.join(dst_dirpath, src_file)
if not os.path.isfile(dst_path):
@@ -1824,7 +1830,8 @@ def mergeinfo_race(sbox):
@Issue(4213)
def recover_old(sbox):
"recover --pre-1.4-compatible"
- sbox.build(create_wc=False)
+ svntest.main.safe_rmtree(sbox.repo_dir, 1)
+ svntest.main.create_repos(sbox.repo_dir, minor_version=0)
svntest.main.run_svnadmin("recover", sbox.repo_dir)
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py Sat Nov 24 20:29:11 2012
@@ -679,6 +679,33 @@ def accepts_deltas(sbox):
+@Issue(4234)
+def dumpfilter_targets_expect_leading_slash_prefixes(sbox):
+ "dumpfilter targets expect leading '/' in prefixes"
+ ## See http://subversion.tigris.org/issues/show_bug.cgi?id=4234. ##
+
+ test_create(sbox)
+
+ dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
+ 'svndumpfilter_tests_data',
+ 'greek_tree.dump')
+ dumpfile = open(dumpfile_location).read()
+
+ (fd, targets_file) = tempfile.mkstemp(dir=svntest.main.temp_dir)
+ try:
+ targets = open(targets_file, 'w')
+
+ # Removing the leading slash in path prefixes should work.
+ targets.write('A/D/H\n')
+ targets.write('A/D/G\n')
+ targets.close()
+ _simple_dumpfilter_test(sbox, dumpfile,
+ 'exclude', '/A/B/E', '--targets', targets_file)
+ finally:
+ os.close(fd)
+ os.remove(targets_file)
+
+
########################################################################
# Run the tests
@@ -693,6 +720,7 @@ test_list = [ None,
dropped_but_not_renumbered_empty_revs,
match_empty_prefix,
accepts_deltas,
+ dumpfilter_targets_expect_leading_slash_prefixes,
]
if __name__ == '__main__':
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py Sat Nov 24 20:29:11 2012
@@ -698,9 +698,14 @@ fp.close()"""
'bogus_rev_val\n',
' bogus_prop\n',
' svn:log\n', ' svn:author\n',
- # internal property, not really expected
- ' svn:check-locks\n',
- ' bogus_rev_prop\n', ' svn:date\n']
+ ' svn:check-locks\n', # internal prop, not really expected
+ ' bogus_rev_prop\n',
+ ' svn:date\n',
+ ' svn:txn-client-compat-version\n',
+ ]
+ # ra_dav and ra_svn add the user-agent ephemeral property
+ if svntest.main.is_ra_type_dav() or svntest.main.is_ra_type_svn():
+ expected_data.append(' svn:txn-user-agent\n')
verify_logfile(logfilepath, svntest.verify.UnorderedOutput(expected_data))
def property_delete(sbox):
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py Sat Nov 24 20:29:11 2012
@@ -35,7 +35,7 @@ else:
from cStringIO import StringIO
import svntest
-from svntest import main, verify, tree, wc
+from svntest import main, verify, tree, wc, sandbox
from svntest import Failure
logger = logging.getLogger()
@@ -1573,6 +1573,90 @@ def run_and_verify_status_xml(expected_e
pprint.pformat(expected_entries).splitlines(),
pprint.pformat(actual_entries).splitlines())))
+def run_and_verify_inherited_prop_xml(path_or_url,
+ expected_inherited_props,
+ expected_explicit_props,
+ propname=None,
+ peg_rev=None,
+ *args):
+ """If PROPNAME is None, then call run_and_verify_svn with proplist -v --xml
+ --show-inherited-props on PATH_OR_URL, otherwise call run_and_verify_svn
+ with propget PROPNAME --xml --show-inherited-props.
+
+ PATH_OR_URL is pegged at PEG_REV if the latter is not None. If PEG_REV
+ is none, then PATH_OR_URL is pegged at HEAD if a url.
+
+ EXPECTED_INHERITED_PROPS is a (possibly empty) dict mapping working copy
+ paths or URLs to dicts of inherited properties. EXPECTED_EXPLICIT_PROPS is
+ a (possibly empty) dict of the explicit properties expected on PATH_OR_URL.
+
+ Returns on success, raises on failure if EXPECTED_INHERITED_PROPS or
+ EXPECTED_EXPLICIT_PROPS don't match the results of proplist/propget.
+ """
+
+ if peg_rev is None:
+ if sandbox.is_url(path_or_url):
+ path_or_url = path_or_url + '@HEAD'
+ else:
+ path_or_url = path_or_url + '@' + str(peg_rev)
+
+ if (propname):
+ exit_code, output, errput = svntest.actions.run_and_verify_svn(
+ None, None, [], 'propget', propname, '--xml',
+ '--show-inherited-props', path_or_url, *args)
+ else:
+ exit_code, output, errput = svntest.actions.run_and_verify_svn(
+ None, None, [], 'proplist', '-v', '--xml', '--show-inherited-props',
+ path_or_url, *args)
+
+ if len(errput) > 0:
+ raise Failure
+
+ # Props inherited from within the WC are keyed on absolute paths.
+ expected_iprops = {}
+ for x in expected_inherited_props:
+ if sandbox.is_url(x):
+ expected_iprops[x] = expected_inherited_props[x]
+ else:
+ expected_iprops[os.path.abspath(x)] = expected_inherited_props[x]
+
+ actual_iprops = {}
+ actual_explicit_props = {}
+
+ doc = parseString(''.join(output))
+ targets = doc.getElementsByTagName('target')
+ for t in targets:
+
+ # Create actual inherited props.
+ iprops = t.getElementsByTagName('inherited_property')
+
+ if len(iprops) > 0:
+ actual_iprops[t.getAttribute('path')]={}
+
+ for i in iprops:
+ actual_iprops[t.getAttribute('path')][i.getAttribute('name')] = \
+ i.firstChild.nodeValue
+
+ # Create actual explicit props.
+ xprops = t.getElementsByTagName('property')
+
+ for x in xprops:
+ actual_explicit_props[x.getAttribute('name')] = x.firstChild.nodeValue
+
+ if expected_explicit_props != actual_explicit_props:
+ raise svntest.Failure(
+ 'Actual and expected explicit props do not match\n' +
+ '\n'.join(difflib.ndiff(
+ pprint.pformat(expected_explicit_props).splitlines(),
+ pprint.pformat(actual_explicit_props).splitlines())))
+
+ if expected_iprops != actual_iprops:
+ raise svntest.Failure(
+ 'Actual and expected inherited props do not match\n' +
+ '\n'.join(difflib.ndiff(
+ pprint.pformat(expected_iprops).splitlines(),
+ pprint.pformat(actual_iprops).splitlines())))
+
def run_and_verify_diff_summarize_xml(error_re_string = [],
expected_prefix = None,
expected_paths = [],
Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py Sat Nov 24 20:29:11 2012
@@ -174,6 +174,12 @@ work_dir = "svn-test-work"
# Constant for the merge info property.
SVN_PROP_MERGEINFO = "svn:mergeinfo"
+# Constant for the inheritabled auto-props property.
+SVN_PROP_INHERITABLE_AUTOPROPS = "svn:inheritable-auto-props"
+
+# Constant for the inheritabled ignores property.
+SVN_PROP_INHERITABLE_IGNORES = "svn:inheritable-ignores"
+
# Where we want all the repositories and working copies to live.
# Each test will have its own!
general_repo_dir = os.path.join(work_dir, "repositories")
@@ -952,12 +958,16 @@ def copy_repos(src_path, dst_path, head_
dump_re = re.compile(r'^\* Dumped revision (\d+)\.\r?$')
expect_revision = 0
+ dump_failed = False
for dump_line in dump_stderr:
match = dump_re.match(dump_line)
if not match or match.group(1) != str(expect_revision):
logger.warn('ERROR: dump failed: %s', dump_line.strip())
- raise SVNRepositoryCopyFailure
- expect_revision += 1
+ dump_failed = True
+ else:
+ expect_revision += 1
+ if dump_failed:
+ raise SVNRepositoryCopyFailure
if expect_revision != head_revision + 1:
logger.warn('ERROR: dump failed; did not see revision %s', head_revision)
raise SVNRepositoryCopyFailure
@@ -1229,10 +1239,12 @@ class TestSpawningThread(threading.Threa
"""A thread that runs test cases in their own processes.
Receives test numbers to run from the queue, and saves results into
the results field."""
- def __init__(self, queue):
+ def __init__(self, queue, progress_func, tests_total):
threading.Thread.__init__(self)
self.queue = queue
self.results = []
+ self.progress_func = progress_func
+ self.tests_total = tests_total
def run(self):
while True:
@@ -1243,6 +1255,11 @@ class TestSpawningThread(threading.Threa
self.run_one(next_index)
+ # signal progress
+ if self.progress_func:
+ self.progress_func(self.tests_total - self.queue.qsize(),
+ self.tests_total)
+
def run_one(self, index):
command = os.path.abspath(sys.argv[0])
@@ -1292,7 +1309,8 @@ class TestRunner:
def list(self, milestones_dict=None):
"""Print test doc strings. MILESTONES_DICT is an optional mapping
- of issue numbers to target milestones."""
+ of issue numbers to an list containing target milestones and who
+ the issue is assigned to."""
if options.mode_filter.upper() == 'ALL' \
or options.mode_filter.upper() == self.pred.list_mode().upper() \
or (options.mode_filter.upper() == 'PASS' \
@@ -1302,6 +1320,7 @@ class TestRunner:
if self.pred.issues:
if not options.milestone_filter or milestones_dict is None:
issues = self.pred.issues
+ tail += " [%s]" % ','.join(['#%s' % str(i) for i in issues])
else: # Limit listing by requested target milestone(s).
filter_issues = []
matches_filter = False
@@ -1310,13 +1329,16 @@ class TestRunner:
# If any one of them matches the MILESTONE_FILTER then we'll print
# them all.
for issue in self.pred.issues:
- # A safe starting assumption.
+ # Some safe starting assumptions.
milestone = 'unknown'
+ assigned_to = 'unknown'
if milestones_dict:
if milestones_dict.has_key(str(issue)):
- milestone = milestones_dict[str(issue)]
+ milestone = milestones_dict[str(issue)][0]
+ assigned_to = milestones_dict[str(issue)][1]
- filter_issues.append(str(issue) + '(' + milestone + ')')
+ filter_issues.append(
+ str(issue) + '(' + milestone + '/' + assigned_to + ')')
pattern = re.compile(options.milestone_filter)
if pattern.match(milestone):
matches_filter = True
@@ -1324,9 +1346,12 @@ class TestRunner:
# Did at least one of the associated issues meet our filter?
if matches_filter:
issues = filter_issues
-
- tail += " [%s]" % ','.join(['#%s' % str(i) for i in issues])
-
+ # Wrap the issue#/target-milestone/assigned-to string
+ # to the next line and add a line break to enhance
+ # readability.
+ tail += "\n %s" % '\n '.join(
+ ['#%s' % str(i) for i in issues])
+ tail += '\n'
# If there is no filter or this test made if through
# the filter then print it!
if options.milestone_filter is None or len(issues):
@@ -1499,7 +1524,8 @@ def _internal_run_tests(test_list, testn
for num in testnums:
number_queue.put(num)
- threads = [ TestSpawningThread(number_queue) for i in range(parallel) ]
+ threads = [ TestSpawningThread(number_queue, progress_func,
+ len(testnums)) for i in range(parallel) ]
for t in threads:
t.start()
@@ -1512,10 +1538,6 @@ def _internal_run_tests(test_list, testn
results += t.results
results.sort()
- # signal some kind of progress
- if progress_func:
- progress_func(len(testnums), len(testnums))
-
# terminate the line of dots
print("")
@@ -1666,7 +1688,12 @@ def run_tests(test_list, serial_only = F
sys.exit(execute_tests(test_list, serial_only))
-def get_target_milestones_for_issues(issue_numbers):
+def get_issue_details(issue_numbers):
+ """For each issue number in ISSUE_NUMBERS query the issue
+ tracker and determine what the target milestone is and
+ who the issue is assigned to. Return this information
+ as a dictionary mapping issue numbers to a list
+ [target_milestone, assigned_to]"""
xml_url = "http://subversion.tigris.org/issues/xml.cgi?id="
issue_dict = {}
@@ -1694,14 +1721,17 @@ def get_target_milestones_for_issues(iss
xmldoc = xml.dom.minidom.parse(issue_xml_f)
issue_xml_f.close()
- # Get the target milestone for each issue.
+ # For each issue: Get the target milestone and who
+ # the issue is assigned to.
issue_element = xmldoc.getElementsByTagName('issue')
for i in issue_element:
issue_id_element = i.getElementsByTagName('issue_id')
issue_id = issue_id_element[0].childNodes[0].nodeValue
milestone_element = i.getElementsByTagName('target_milestone')
milestone = milestone_element[0].childNodes[0].nodeValue
- issue_dict[issue_id] = milestone
+ assignment_element = i.getElementsByTagName('assigned_to')
+ assignment = assignment_element[0].childNodes[0].nodeValue
+ issue_dict[issue_id] = [milestone, assignment]
except:
print "ERROR: Unable to parse target milestones from issue tracker"
raise
@@ -1894,10 +1924,13 @@ def execute_tests(test_list, serial_only
options.mode_filter.upper() == test_mode or
(options.mode_filter.upper() == 'PASS' and test_mode == '')):
issues_dict[issue]=issue
- milestones_dict = get_target_milestones_for_issues(issues_dict.keys())
+ milestones_dict = get_issue_details(issues_dict.keys())
+
+ header = "Test # Mode Test Description\n"
+ if options.milestone_filter:
+ header += " Issue#(Target Mileston/Assigned To)\n"
+ header += "------ ----- ----------------"
- header = "Test # Mode Test Description\n" \
- "------ ----- ----------------"
printed_header = False
for testnum in testnums:
test_mode = TestRunner(test_list[testnum], testnum).get_mode().upper()