You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/09/15 21:32:38 UTC

svn commit: r997472 [39/41] - in /subversion/branches/py-tests-as-modules: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/server-side/ notes/ notes/tree-conflicts/ notes/wc-ng/ subversion/bindings/javahl/native/ subversi...

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/switch_tests.py?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/switch_tests.py Wed Sep 15 19:32:26 2010
@@ -29,6 +29,7 @@ import shutil, re, os
 
 # Our testing module
 import svntest
+from svntest import verify, actions, main
 
 # (abbreviation)
 Skip = svntest.testcase.Skip
@@ -37,6 +38,8 @@ XFail = svntest.testcase.XFail
 Item = svntest.wc.StateItem
 
 from svntest.main import SVN_PROP_MERGEINFO, server_has_mergeinfo
+from externals_tests import change_external
+
 
 ### Bummer.  It would be really nice to have easy access to the URL
 ### member of our entries files so that switches could be testing by
@@ -564,7 +567,10 @@ def relocate_deleted_missing_copied(sbox
     'A/D2/H/omega' : Item(status='  ', wc_rev='-', copied='+'),
     'A/D2/H/psi'   : Item(status='  ', wc_rev='-', copied='+'),
     })
-  expected_status.tweak('A/B/F', status='! ', wc_rev='?')
+  if svntest.main.wc_is_singledb(wc_dir):
+    expected_status.tweak('A/B/F', status='! ', wc_rev='1')
+  else:
+    expected_status.tweak('A/B/F', status='! ', wc_rev='?')
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
   # Relocate
@@ -578,20 +584,28 @@ def relocate_deleted_missing_copied(sbox
 
   # Deleted and missing entries should be preserved, so update should
   # show only A/B/F being reinstated
-  expected_output = svntest.wc.State(wc_dir, {
-    'A/B/F' : Item(status='A '),
-    })
+  if svntest.main.wc_is_singledb(wc_dir):
+    expected_output = svntest.wc.State(wc_dir, {
+        'A/B/F' : Item(verb='Restored'),
+        })
+  else:
+    expected_output = svntest.wc.State(wc_dir, {
+        'A/B/F' : Item(status='A '),
+        })
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.remove('A/mu')
   expected_disk.add({
     'A/D2'       : Item(),
     'A/D2/gamma'   : Item("This is the file 'gamma'.\n"),
-    'A/D2/G'       : Item(),
     'A/D2/H'       : Item(),
     'A/D2/H/chi'   : Item("This is the file 'chi'.\n"),
     'A/D2/H/omega' : Item("This is the file 'omega'.\n"),
     'A/D2/H/psi'   : Item("This is the file 'psi'.\n"),
     })
+  if not svntest.main.wc_is_singledb(wc_dir):
+    expected_disk.add({
+        'A/D2/G'       : Item(),
+        })
   expected_status.add({
     'A/B/F'       : Item(status='  ', wc_rev='2'),
     })
@@ -802,35 +816,92 @@ def bad_intermediate_urls(sbox):
   "bad intermediate urls in use"
   sbox.build()
   wc_dir = sbox.wc_dir
+  url = sbox.repo_url
+
+  A = os.path.join(wc_dir, 'A')
+  A_Z = os.path.join(wc_dir, 'A', 'Z')
+  url_A_C = url + '/A/C'
+  url_A_C_A = url + '/A/C/A'
+  url_A_C_A_Z = url + '/A/C/A/Z'
 
   # We'll be switching our working copy to (a modified) A/C in the Greek tree.
 
   # First, make an extra subdirectory in C to match one in the root, plus
   # another one inside of that.
-  C_url = sbox.repo_url + '/A/C'
-  C_A_url = sbox.repo_url + '/A/C/A'
-  C_A_Z_url = sbox.repo_url + '/A/C/A/Z'
   svntest.actions.run_and_verify_svn(None,
                                      ['\n', 'Committed revision 2.\n'], [],
                                      'mkdir', '-m', 'log msg',
-                                     C_A_url, C_A_Z_url)
+                                     url_A_C_A, url_A_C_A_Z)
 
   # Now, we'll drop a conflicting path under the root.
-  A_path = os.path.join(wc_dir, 'A')
-  A_Z_path = os.path.join(A_path, 'Z')
-  svntest.main.file_append(A_Z_path, 'Look, Mom, no ... switch success.')
+  svntest.main.file_append(A_Z, 'Look, Mom, a ... tree conflict.')
 
-  # This switch should fail for reasons of obstruction.
-  exit_code, out, err = svntest.main.run_svn(1, 'switch',
-                                             C_url, wc_dir)
-  if not err:
-    raise svntest.Failure
+  #svntest.factory.make(sbox, """
+  #  svn switch url/A/C wc_dir
+  #  # svn info A
+  #  # check that we can recover from the tree conflict
+  #  rm A/Z
+  #  svn up
+  #  """)
+  #exit(0)
+
+  # svn switch url/A/C wc_dir
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/mu'              : Item(status='D '),
+    'A/Z'               : Item(status='  ', treeconflict='C'),
+    'A/C'               : Item(status='D '),
+    'A/B'               : Item(status='D '),
+    'A/D'               : Item(status='D '),
+    'iota'              : Item(status='D '),
+  })
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('iota', 'A/B', 'A/B/E', 'A/B/E/beta', 'A/B/E/alpha',
+    'A/B/F', 'A/B/lambda', 'A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/pi',
+    'A/D/G/tau', 'A/D/H', 'A/D/H/psi', 'A/D/H/omega', 'A/D/H/chi',
+    'A/D/gamma', 'A/mu', 'A/C')
+  expected_disk.add({
+    'A/Z'               : Item(contents="Look, Mom, a ... tree conflict."),
+  })
 
-  # However, the URL for A should now reflect A/C/A, not something else.
+  expected_status = actions.get_virginal_state(wc_dir, 2)
+  expected_status.remove('iota', 'A/B', 'A/B/E', 'A/B/E/beta', 'A/B/E/alpha',
+    'A/B/F', 'A/B/lambda', 'A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/pi',
+    'A/D/G/tau', 'A/D/H', 'A/D/H/psi', 'A/D/H/omega', 'A/D/H/chi',
+    'A/D/gamma', 'A/mu', 'A/C')
+  expected_status.add({
+    'A/Z'               : Item(status='? ', treeconflict='C'),
+  })
+
+  actions.run_and_verify_switch(wc_dir, wc_dir, url_A_C, expected_output,
+    expected_disk, expected_status, None, None, None, None, None, False)
+
+  
+  # However, the URL for wc/A should now reflect ^/A/C/A, not something else.
   expected_infos = [
       { 'URL' : '.*/A/C/A$' },
     ]
-  svntest.actions.run_and_verify_info(expected_infos, A_path)
+  svntest.actions.run_and_verify_info(expected_infos, A)
+
+
+  # check that we can recover from the tree conflict
+  # rm A/Z
+  os.remove(A_Z)
+
+  # svn up
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/Z'               : Item(status='A '),
+  })
+
+  expected_disk.tweak('A/Z', contents=None)
+
+  expected_status.tweak(status='  ', wc_rev='2')
+  expected_status.tweak('A/Z', treeconflict=None)
+
+  actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+    expected_status, None, None, None, None, None, False, wc_dir)
+
+
 
 
 #----------------------------------------------------------------------
@@ -839,42 +910,84 @@ def bad_intermediate_urls(sbox):
 
 def obstructed_switch(sbox):
   "obstructed switch"
+  #svntest.factory.make(sbox, """svn cp -m msgcopy url/A/B/E url/A/B/Esave
+  #                              svn rm A/B/E/alpha
+  #                              svn commit
+  #                              echo "hello" >> A/B/E/alpha
+  #                              svn switch url/A/B/Esave A/B/E
+  #                              svn status
+  #                              svn info A/B/E/alpha""")
   sbox.build()
   wc_dir = sbox.wc_dir
+  url = sbox.repo_url
 
-  E_url      = sbox.repo_url + '/A/B/E'
-  E_url2     = sbox.repo_url + '/A/B/Esave'
-  svntest.actions.run_and_verify_svn(None,
-                                     ['\n', 'Committed revision 2.\n'], [],
-                                     'cp', '-m', 'msgcopy', E_url, E_url2)
+  A_B_E = os.path.join(wc_dir, 'A', 'B', 'E')
+  A_B_E_alpha = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
+  url_A_B_E = url + '/A/B/E'
+  url_A_B_Esave = url + '/A/B/Esave'
 
-  E_path     = os.path.join(wc_dir, 'A', 'B', 'E')
-  alpha_path = os.path.join(E_path, 'alpha')
-  svntest.actions.run_and_verify_svn(None, None, [], 'rm', alpha_path)
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  # svn cp -m msgcopy url/A/B/E url/A/B/Esave
+  expected_stdout = verify.UnorderedOutput([
+    '\n',
+    'Committed revision 2.\n',
+  ])
+
+  actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'cp', '-m',
+    'msgcopy', url_A_B_E, url_A_B_Esave)
+
+  # svn rm A/B/E/alpha
+  expected_stdout = ['D         ' + A_B_E_alpha + '\n']
+
+  actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'rm',
+    A_B_E_alpha)
+
+  # svn commit
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E/alpha'       : Item(verb='Deleting'),
+  })
+
+  expected_status = actions.get_virginal_state(wc_dir, 1)
   expected_status.remove('A/B/E/alpha')
+
+  actions.run_and_verify_commit(wc_dir, expected_output, expected_status,
+    None, wc_dir)
+
+  # echo "hello" >> A/B/E/alpha
+  main.file_append(A_B_E_alpha, 'hello')
+
+  # svn switch url/A/B/Esave A/B/E
   expected_output = svntest.wc.State(wc_dir, {
-    'A/B/E/alpha' : Item(verb='Deleting'),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output, expected_status,
-                                        None, wc_dir)
+    'A/B/E/alpha'       : Item(status='  ', treeconflict='C'),
+  })
 
-  svntest.main.file_append(alpha_path, "hello")
-  exit_code, out, err = svntest.main.run_svn(1, 'sw', E_url2, E_path)
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/B/E/alpha', contents='hello')
 
-  for line in err:
-    if line.find("file of the same name already exists") != -1:
-      break
-  else:
-    raise svntest.Failure
+  expected_status.add({
+    'A/B/E/alpha'       : Item(status='? ', treeconflict='C'),
+  })
+  expected_status.tweak('A/B/E', wc_rev='3', switched='S')
+  expected_status.tweak('A/B/E/beta', wc_rev='3')
 
-  os.remove(alpha_path)
-  svntest.actions.run_and_verify_svn(None, None, [], 'sw', E_url2, E_path)
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', wc_rev=3)
-  expected_status.tweak('A/B/E', switched='S')
-  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+  actions.run_and_verify_switch(wc_dir, A_B_E, url_A_B_Esave,
+    expected_output, expected_disk, expected_status, None, None, None, None,
+    None, False)
+
+  # svn status
+  expected_status.add({
+    'A/B/Esave'         : Item(status='  '),
+    'A/B/Esave/beta'    : Item(status='  '),
+    'A/B/Esave/alpha'   : Item(status='  '),
+  })
+
+  actions.run_and_verify_unquiet_status(wc_dir, expected_status)
+
+  # svn info A/B/E/alpha
+  expected_stdout = verify.RegexOutput(
+                      ".*local unversioned, incoming add upon switch",
+                      match_all=False)
+  actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'info',
+    A_B_E_alpha)
 
 
 #----------------------------------------------------------------------
@@ -1230,194 +1343,248 @@ def forced_switch(sbox):
                                         '--force')
 
 #----------------------------------------------------------------------
-
+# This test currently XFails for serf as the different order of
+# operations is not handled here.
 def forced_switch_failures(sbox):
   "forced switch detects tree conflicts"
-  sbox.build()
+  #  svntest.factory.make(sbox,
+  #    """
+  #    # Add a directory to obstruct a file.
+  #    mkdir A/B/F/pi
+  #  
+  #    # Add a file to obstruct a directory.
+  #    echo "The file 'H'" > A/C/H
+  #  
+  #    # Test three cases where forced switch should cause a tree conflict
+  #  
+  #    # 1) A forced switch that tries to add a file when an unversioned
+  #    #    directory of the same name already exists.  (Currently fails)
+  #    svn switch --force url/A/D A/C
+  #  
+  #    # 2) A forced switch that tries to add a dir when a file of the same
+  #    #    name already exists. (Tree conflict)
+  #    svn switch --force url/A/D/G A/B/F
+  #    svn info A/B/F/pi
+  #  
+  #    # 3) A forced update that tries to add a directory when a versioned
+  #    #    directory of the same name already exists.
+  #  
+  #    # Make dir A/D/H/I in repos.
+  #    svn mkdir -m "Log message" url/A/D/H/I
+  #  
+  #    # Make A/D/G/I and co A/D/H/I into it.
+  #    mkdir A/D/G/I
+  #    svn co url/A/D/H/I A/D/G/I
+  #  
+  #    # Try the forced switch.  A/D/G/I obstructs the dir A/D/G/I coming
+  #    # from the repos, causing an error.
+  #    svn switch --force url/A/D/H A/D/G
+  #  
+  #    # Delete all three obstructions and finish the update.
+  #    rm -rf A/D/G/I
+  #    rm A/B/F/pi
+  #    rm A/C/H
+  #  
+  #    # A/B/F is switched to A/D/G
+  #    # A/C is switched to A/D
+  #    # A/D/G is switched to A/D/H
+  #    svn up
+  #    """)
+  #  exit(0)
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  url = sbox.repo_url
+
+  A_B_F = os.path.join(wc_dir, 'A', 'B', 'F')
+  A_B_F_pi = os.path.join(wc_dir, 'A', 'B', 'F', 'pi')
+  A_C = os.path.join(wc_dir, 'A', 'C')
+  A_C_H = os.path.join(wc_dir, 'A', 'C', 'H')
+  A_D_G = os.path.join(wc_dir, 'A', 'D', 'G')
+  A_D_G_I = os.path.join(wc_dir, 'A', 'D', 'G', 'I')
+  url_A_D = url + '/A/D'
+  url_A_D_G = url + '/A/D/G'
+  url_A_D_H = url + '/A/D/H'
+  url_A_D_H_I = url + '/A/D/H/I'
 
   # Add a directory to obstruct a file.
-  pi_path = os.path.join(sbox.wc_dir, 'A', 'B', 'F', 'pi')
-  os.mkdir(pi_path)
+  # mkdir A/B/F/pi
+  os.makedirs(A_B_F_pi)
 
   # Add a file to obstruct a directory.
-  H_path = os.path.join(sbox.wc_dir, 'A', 'C', 'H')
-  svntest.main.file_write(H_path, "The file 'H'\n")
+  # echo "The file 'H'" > A/C/H
+  main.file_write(A_C_H, "The file 'H'\n")
 
   # Test three cases where forced switch should cause a tree conflict
-
   # 1) A forced switch that tries to add a file when an unversioned
   #    directory of the same name already exists.  (Currently fails)
+  # svn switch --force url/A/D A/C
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/C/G'             : Item(status='A '),
+    'A/C/G/pi'          : Item(status='A '),
+    'A/C/G/rho'         : Item(status='A '),
+    'A/C/G/tau'         : Item(status='A '),
+    'A/C/gamma'         : Item(status='A '),
+    'A/C/H'             : Item(status='  ', treeconflict='C'),
+  })
+
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.add({
-    'A/C'               : Item(),
-    'A/C/gamma'         : Item("This is the file 'gamma'.\n"),
-    'A/C/H'             : Item("The file 'H'\n"),
+    'A/C/gamma'         : Item(contents="This is the file 'gamma'.\n"),
     'A/C/G'             : Item(),
-    'A/C/G/rho'         : Item("This is the file 'rho'.\n"),
-    'A/C/G/pi'          : Item("This is the file 'pi'.\n"),
-    'A/C/G/tau'         : Item("This is the file 'tau'.\n"),
-    })
-  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+    'A/C/G/pi'          : Item(contents="This is the file 'pi'.\n"),
+    'A/C/G/rho'         : Item(contents="This is the file 'rho'.\n"),
+    'A/C/G/tau'         : Item(contents="This is the file 'tau'.\n"),
+    'A/C/H'             : Item(contents="The file 'H'\n"),
+    'A/B/F/pi'          : Item(),
+  })
+
+  expected_status = actions.get_virginal_state(wc_dir, 1)
   expected_status.add({
-    'A/C'               : Item(status='! ', wc_rev='1', switched='S'),
     'A/C/G'             : Item(status='  ', wc_rev='1'),
-    'A/C/G/pi'          : Item(status='  ', wc_rev='1'),
     'A/C/G/rho'         : Item(status='  ', wc_rev='1'),
     'A/C/G/tau'         : Item(status='  ', wc_rev='1'),
+    'A/C/G/pi'          : Item(status='  ', wc_rev='1'),
+    'A/C/H'             : Item(status='? ', treeconflict='C'),
     'A/C/gamma'         : Item(status='  ', wc_rev='1'),
-    })
-  svntest.actions.run_and_verify_switch(sbox.wc_dir,
-                                        os.path.join(sbox.wc_dir, 'A', 'C'),
-                                        sbox.repo_url + "/A/D",
-                                        None, None, None,
-                                        ".*Failed to add directory .*" + \
-                                        ": a non-directory object of the" + \
-                                        " same name already exists\n",
-                                        None, None, None, None, 0, '--force')
+  })
+  expected_status.tweak('A/C', switched='S')
+
+  actions.run_and_verify_switch(wc_dir, A_C, url_A_D, expected_output,
+    expected_disk, expected_status, None, None, None, None, None, False,
+    '--force')
+
 
   # 2) A forced switch that tries to add a dir when a file of the same
-  #    name already exists.  (Currently fails)
+  #    name already exists. (Tree conflict)
+  # svn switch --force url/A/D/G A/B/F
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/F/rho'         : Item(status='A '),
+    'A/B/F/pi'          : Item(status='  ', treeconflict='C'),
+    'A/B/F/tau'         : Item(status='A '),
+  })
+
   expected_disk.add({
-    'A/B/F/pi'          : Item(),
-    })
+    'A/B/F/rho'         : Item(contents="This is the file 'rho'.\n"),
+    'A/B/F/tau'         : Item(contents="This is the file 'tau'.\n"),
+  })
+
   expected_status.add({
-    'A/B/F'             : Item(status='! ', wc_rev='1', switched='S'),
-    })
-  svntest.actions.run_and_verify_switch(sbox.wc_dir,
-                                        os.path.join(sbox.wc_dir,
-                                                     'A', 'B', 'F'),
-                                        sbox.repo_url + "/A/D/G",
-                                        None, None, None,
-                                        ".*Failed to add file .*" + \
-                                        ": a non-file object of the " + \
-                                        "same name already exists\n",
-                                        None, None, None, None, 0, '--force')
+    'A/B/F/tau'         : Item(status='  ', wc_rev='1'),
+    'A/B/F/pi'          : Item(status='? ', treeconflict='C'),
+    'A/B/F/rho'         : Item(status='  ', wc_rev='1'),
+  })
+  expected_status.tweak('A/B/F', switched='S')
+
+  actions.run_and_verify_switch(wc_dir, A_B_F, url_A_D_G, expected_output,
+    expected_disk, expected_status, None, None, None, None, None, False,
+    '--force')
+
+  # svn info A/B/F/pi
+  expected_stdout = verify.ExpectedOutput(
+    'Tree conflict: local unversioned, incoming add upon switch\n',
+    match_all=False)
+
+  actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'info',
+    A_B_F_pi)
+
 
   # 3) A forced update that tries to add a directory when a versioned
   #    directory of the same name already exists.
-
   # Make dir A/D/H/I in repos.
-  I_url = sbox.repo_url + "/A/D/H/I"
-  exit_code, so, se = svntest.actions.run_and_verify_svn(
-    "Unexpected error during mkdir",
-    ['\n', 'Committed revision 2.\n'], [],
-    "mkdir", I_url, "-m", "Log Message")
+  # svn mkdir -m "Log message" url/A/D/H/I
+  expected_stdout = verify.UnorderedOutput([
+    '\n',
+    'Committed revision 2.\n',
+  ])
+
+  actions.run_and_verify_svn2('OUTPUT', expected_stdout, [], 0, 'mkdir',
+    '-m', 'Log message', url_A_D_H_I)
 
   # Make A/D/G/I and co A/D/H/I into it.
-  I_path = os.path.join(sbox.wc_dir, 'A', 'D', 'G', 'I')
-  os.mkdir(I_path)
-  exit_code, so, se = svntest.actions.run_and_verify_svn(
-    "Unexpected error during co",
-    ['Checked out revision 2.\n'], [],
-    "co", I_url, I_path)
+  # mkdir A/D/G/I
+  os.makedirs(A_D_G_I)
+
+  # svn co url/A/D/H/I A/D/G/I
+  expected_output = svntest.wc.State(wc_dir, {})
+
+  expected_disk.add({
+    'A/D/G/I'           : Item(),
+  })
+
+  exit_code, so, se = svntest.actions.run_and_verify_svn( 
+    "Unexpected error during co", 
+    ['Checked out revision 2.\n'], [], 
+    "co", url_A_D_H_I, A_D_G_I)
 
   # Try the forced switch.  A/D/G/I obstructs the dir A/D/G/I coming
   # from the repos, causing an error.
-  G_path = os.path.join(sbox.wc_dir, 'A', 'D', 'G')
-  svntest.actions.run_and_verify_switch(sbox.wc_dir,
-                                        G_path,
-                                        sbox.repo_url + "/A/D/H",
-                                        None, None, None,
-                                        "Failed to add directory '.*I'."
-                                        "*already exists",
-                                        None, None, None, None, False,
-                                        '--force')
+  # svn switch --force url/A/D/H A/D/G
+  expected_error = ('Failed to add directory.*' + re.escape(A_D_G_I) +
+                    '.*a separate working copy.*already exists')
+
+  actions.run_and_verify_switch(wc_dir, A_D_G, url_A_D_H, None, None, None,
+    expected_error, None, None, None, None, False, '--force')
 
   # Delete all three obstructions and finish the update.
-  svntest.main.safe_rmtree(I_path)
-  svntest.main.safe_rmtree(pi_path)
-  os.remove(H_path)
+  # rm -rf A/D/G/I
+  main.safe_rmtree(A_D_G_I)
 
-  # For our expected disk start with the standard greek tree.
-  expected_disk = svntest.main.greek_state.copy()
+  # rm A/B/F/pi
+  main.safe_rmtree(A_B_F_pi)
+
+  # rm A/C/H
+  os.remove(A_C_H)
 
-  ### There has to be a simpler way to do this...but it will do for now.
   # A/B/F is switched to A/D/G
-  new_A_B_F = svntest.wc.State('', {
-    "A/B/F"       : Item(),
-    "A/B/F/rho"   : Item("This is the file 'rho'.\n"),
-    "A/B/F/pi"    : Item("This is the file 'pi'.\n"),
-    "A/B/F/tau"   : Item("This is the file 'tau'.\n"),
-    })
   # A/C is switched to A/D
-  new_A_C = svntest.wc.State('', {
-    "A/C"         : Item(),
-    "A/C/gamma"   : Item("This is the file 'gamma'.\n"),
-    "A/C/G"       : Item(),
-    "A/C/G/pi"    : Item("This is the file 'pi'.\n"),
-    "A/C/G/rho"   : Item("This is the file 'rho'.\n"),
-    "A/C/G/tau"   : Item("This is the file 'tau'.\n"),
-    "A/C/H"       : Item(),
-    "A/C/H/chi"   : Item("This is the file 'chi'.\n"),
-    "A/C/H/I"     : Item(),
-    "A/C/H/omega" : Item("This is the file 'omega'.\n"),
-    "A/C/H/psi"   : Item("This is the file 'psi'.\n"),
-    })
   # A/D/G is switched to A/D/H
-  new_A_D_G = svntest.wc.State('', {
-    "A/D/G"       : Item(),
-    "A/D/G/chi"   : Item("This is the file 'chi'.\n"),
-    "A/D/G/omega" : Item("This is the file 'omega'.\n"),
-    "A/D/G/I"     : Item(),
-    "A/D/G/psi"   : Item("This is the file 'psi'.\n"),
-    "A/D/H"       : Item(),
-    "A/D/H/chi"   : Item("This is the file 'chi'.\n"),
-    "A/D/H/omega" : Item("This is the file 'omega'.\n"),
-    "A/D/H/I"     : Item(),
-    "A/D/H/psi"   : Item("This is the file 'psi'.\n"),
-    "iota"        : Item("This is the file 'iota'.\n"),
-    })
-  # Remove the three switched subtrees and replace with their new contents.
-  expected_disk.remove('A/B/F', 'A/C',
-                       'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
-  expected_disk.add_state('', new_A_B_F)
-  expected_disk.add_state('', new_A_C)
-  expected_disk.add_state('', new_A_D_G)
-
-  expected_status = svntest.wc.State(sbox.wc_dir, {
-    ""            : Item(),
-    "A"           : Item(),
-    "A/B"         : Item(),
-    "A/B/lambda"  : Item(),
-    "A/B/E"       : Item(),
-    "A/B/E/alpha" : Item(),
-    "A/B/E/beta"  : Item(),
-    "A/B/F"       : Item(switched='S'),
-    "A/B/F/rho"   : Item(),
-    "A/B/F/pi"    : Item(),
-    "A/B/F/tau"   : Item(),
-    "A/mu"        : Item(),
-    "A/C"         : Item(switched='S'),
-    "A/C/gamma"   : Item(),
-    "A/C/G"       : Item(),
-    "A/C/G/pi"    : Item(),
-    "A/C/G/rho"   : Item(),
-    "A/C/G/tau"   : Item(),
-    "A/C/H"       : Item(),
-    "A/C/H/chi"   : Item(),
-    "A/C/H/I"     : Item(),
-    "A/C/H/omega" : Item(),
-    "A/C/H/psi"   : Item(),
-    "A/D"         : Item(),
-    "A/D/gamma"   : Item(),
-    "A/D/G"       : Item(switched='S'),
-    "A/D/G/chi"   : Item(),
-    "A/D/G/omega" : Item(),
-    "A/D/G/I"     : Item(),
-    "A/D/G/psi"   : Item(),
-    "A/D/H"       : Item(),
-    "A/D/H/chi"   : Item(),
-    "A/D/H/omega" : Item(),
-    "A/D/H/I"     : Item(),
-    "A/D/H/psi"   : Item(),
-    "iota"        : Item(),
-    })
-  expected_status.tweak(status='  ', wc_rev=2)
-  svntest.actions.run_and_verify_update(sbox.wc_dir,
-                                        None,
-                                        expected_disk,
-                                        expected_status,
-                                        None, None, None, None, None, False)
+  # svn up
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/C/H'             : Item(status='A '),
+    'A/C/H/omega'       : Item(status='A '),
+    'A/C/H/chi'         : Item(status='A '),
+    'A/C/H/I'           : Item(status='A '),
+    'A/C/H/psi'         : Item(status='A '),
+    'A/D/G/omega'       : Item(status='A '),
+    'A/D/G/I'           : Item(status='A '),
+    'A/D/G/psi'         : Item(status='A '),
+    'A/D/H/I'           : Item(status='A '),
+    'A/B/F/pi'          : Item(status='A '),
+  })
+
+  expected_disk.remove('A/D/G/tau', 'A/D/G/rho', 'A/D/G/pi')
+  expected_disk.add({
+    'A/D/H/I'           : Item(),
+    'A/D/G/omega'       : Item(contents="This is the file 'omega'.\n"),
+    'A/D/G/psi'         : Item(contents="This is the file 'psi'.\n"),
+    'A/D/G/chi'         : Item(contents="This is the file 'chi'.\n"),
+    'A/C/H/I'           : Item(),
+    'A/C/H/omega'       : Item(contents="This is the file 'omega'.\n"),
+    'A/C/H/psi'         : Item(contents="This is the file 'psi'.\n"),
+    'A/C/H/chi'         : Item(contents="This is the file 'chi'.\n"),
+  })
+  expected_disk.tweak('A/C/H', contents=None)
+  expected_disk.tweak('A/B/F/pi', contents="This is the file 'pi'.\n")
+
+  expected_status.remove('A/D/G/tau', 'A/D/G/rho', 'A/D/G/pi')
+  expected_status.add({
+    'A/D/G/omega'       : Item(status='  ', wc_rev='2'),
+    'A/D/G/I'           : Item(status='  ', wc_rev='2'),
+    'A/D/G/psi'         : Item(status='  ', wc_rev='2'),
+    'A/D/G/chi'         : Item(status='  ', wc_rev='2'),
+    'A/D/H/I'           : Item(status='  ', wc_rev='2'),
+    'A/C/H/psi'         : Item(status='  ', wc_rev='2'),
+    'A/C/H/omega'       : Item(status='  ', wc_rev='2'),
+    'A/C/H/chi'         : Item(status='  ', wc_rev='2'),
+    'A/C/H/I'           : Item(status='  ', wc_rev='2'),
+  })
+  expected_status.tweak(wc_rev='2', status='  ')
+  expected_status.tweak('A/B/F/pi', 'A/C/H', treeconflict=None)
+  expected_status.tweak('A/D/G', switched='S')
+
+  actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+    expected_status, None, None, None, None, None, False, wc_dir)
+
 
 def switch_with_obstructing_local_adds(sbox):
   "switch tolerates WC adds"
@@ -1455,11 +1622,8 @@ def switch_with_obstructing_local_adds(s
 
   # Setup expected results of switch.
   expected_output = svntest.wc.State(sbox.wc_dir, {
-    "A/B/F/gamma"   : Item(status='E '),
-    "A/B/F/G"       : Item(status='E '),
-    "A/B/F/G/pi"    : Item(status='C '),
-    "A/B/F/G/rho"   : Item(status='A '),
-    "A/B/F/G/tau"   : Item(status='E '),
+    "A/B/F/gamma"   : Item(status='  ', treeconflict='C'),
+    "A/B/F/G"       : Item(status='  ', treeconflict='C'),
     "A/B/F/H"       : Item(status='A '),
     "A/B/F/H/chi"   : Item(status='A '),
     "A/B/F/H/omega" : Item(status='A '),
@@ -1470,13 +1634,7 @@ def switch_with_obstructing_local_adds(s
   expected_disk.add({
     "A/B/F/gamma"     : Item("This is the file 'gamma'.\n"),
     "A/B/F/G"         : Item(),
-    "A/B/F/G/pi"      : Item("\n".join(["<<<<<<< .mine",
-                                        "This is the OBSTRUCTING file 'pi'.",
-                                        "=======",
-                                        "This is the file 'pi'.",
-                                        ">>>>>>> .r1",
-                                        ""])),
-    "A/B/F/G/rho"     : Item("This is the file 'rho'.\n"),
+    "A/B/F/G/pi"      : Item("This is the OBSTRUCTING file 'pi'.\n"),
     "A/B/F/G/tau"     : Item("This is the file 'tau'.\n"),
     "A/B/F/G/upsilon" : Item("This is the unversioned file 'upsilon'.\n"),
     "A/B/F/H"         : Item(),
@@ -1488,18 +1646,17 @@ def switch_with_obstructing_local_adds(s
   expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
   expected_status.tweak('A/B/F', switched='S')
   expected_status.add({
-    "A/B/F/gamma"     : Item(status='  ', wc_rev=1),
-    "A/B/F/G"         : Item(status='  ', wc_rev=1),
-    "A/B/F/G/pi"      : Item(status='C ', wc_rev=1),
-    "A/B/F/G/rho"     : Item(status='  ', wc_rev=1),
-    "A/B/F/G/tau"     : Item(status='  ', wc_rev=1),
-    "A/B/F/G/upsilon" : Item(status='A ', wc_rev=0),
-    "A/B/F/H"         : Item(status='  ', wc_rev=1),
-    "A/B/F/H/chi"     : Item(status='  ', wc_rev=1),
-    "A/B/F/H/omega"   : Item(status='  ', wc_rev=1),
-    "A/B/F/H/psi"     : Item(status='  ', wc_rev=1),
-    "A/B/F/I"         : Item(status='A ', wc_rev=0),
-    })
+    'A/B/F/gamma'     : Item(status='R ', treeconflict='C', wc_rev='1'),
+    'A/B/F/G'         : Item(status='A ', treeconflict='C', wc_rev='0'),
+    'A/B/F/G/pi'      : Item(status='A ', wc_rev='0'),
+    'A/B/F/G/tau'     : Item(status='A ', wc_rev='0'),
+    'A/B/F/G/upsilon' : Item(status='A ', wc_rev='0'),
+    'A/B/F/H'         : Item(status='  ', wc_rev='1'),
+    'A/B/F/H/chi'     : Item(status='  ', wc_rev='1'),
+    'A/B/F/H/omega'   : Item(status='  ', wc_rev='1'),
+    'A/B/F/H/psi'     : Item(status='  ', wc_rev='1'),
+    'A/B/F/I'         : Item(status='A ', wc_rev='0'),
+  })
 
   # "Extra" files that we expect to result from the conflicts.
   extra_files = ['pi\.r0', 'pi\.r1', 'pi\.mine']
@@ -1653,8 +1810,6 @@ def mergeinfo_switch_elision(sbox):
     'F'       : Item(),
     })
   expected_skip = svntest.wc.State(B_COPY_1_path, { })
-  saved_cwd = os.getcwd()
-
   svntest.actions.run_and_verify_merge(B_COPY_1_path, '2', '4',
                                        sbox.repo_url + '/A/B', None,
                                        expected_output,
@@ -1701,8 +1856,6 @@ def mergeinfo_switch_elision(sbox):
     'beta'  : Item("New content"),
     })
   expected_skip = svntest.wc.State(E_COPY_2_path, { })
-  saved_cwd = os.getcwd()
-
   svntest.actions.run_and_verify_merge(E_COPY_2_path, '2', '4',
                                        sbox.repo_url + '/A/B/E', None,
                                        expected_output,
@@ -2319,6 +2472,8 @@ j = os.path.join
 def tree_conflicts_on_switch_1_1(sbox):
   "tree conflicts 1.1: tree del, leaf edit on switch"
 
+  sbox.build()
+
   # use case 1, as in notes/tree-conflicts/use-cases.txt
   # 1.1) local tree delete, incoming leaf edit
 
@@ -2336,6 +2491,10 @@ def tree_conflicts_on_switch_1_1(sbox):
   })
 
   expected_disk = disk_empty_dirs.copy()
+  if  svntest.main.wc_is_singledb(sbox.wc_dir):
+    expected_disk.remove('D/D1', 'DF/D1', 'DD/D1', 'DD/D1/D2',
+                         'DDF/D1', 'DDF/D1/D2',
+                         'DDD/D1', 'DDD/D1/D2', 'DDD/D1/D2/D3')
 
   # The files delta, epsilon, and zeta are incoming additions, but since
   # they are all within locally deleted trees they should also be schedule
@@ -2403,6 +2562,8 @@ def tree_conflicts_on_switch_1_1(sbox):
 def tree_conflicts_on_switch_1_2(sbox):
   "tree conflicts 1.2: tree del, leaf del on switch"
 
+  sbox.build()
+
   # 1.2) local tree delete, incoming leaf delete
 
   expected_output = deep_trees_conflict_output.copy()
@@ -2442,6 +2603,10 @@ def tree_conflicts_on_switch_1_2(sbox):
   expected_disk.remove('D/D1',
                        'DD/D1/D2',
                        'DDD/D1/D2/D3')
+  if svntest.main.wc_is_singledb(sbox.wc_dir):
+    expected_disk.remove('DF/D1', 'DD/D1',
+                         'DDF/D1', 'DDF/D1/D2',
+                         'DDD/D1', 'DDD/D1/D2')
 
   expected_info = {
     'F/alpha' : {
@@ -2925,6 +3090,33 @@ def copy_with_switched_subdir(sbox):
   # should either be the tree of E, or nothing at all.
   svntest.actions.run_and_verify_status(wc_dir, state)
 
+### regression test for issue #3597
+def relocate_with_relative_externals(sbox):
+  "relocate a directory containing relative externals"
+  
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Add a relative external.
+  change_external(os.path.join(wc_dir, 'A', 'B'), "^/A/D/G G-ext", commit=True)
+  svntest.actions.run_and_verify_svn(None, None, [], 'update', wc_dir)
+  
+  # Move our repository to another location.
+  repo_dir = sbox.repo_dir
+  repo_url = sbox.repo_url
+  other_repo_dir, other_repo_url = sbox.add_repo_path('other')
+  svntest.main.copy_repos(repo_dir, other_repo_dir, 2, 0)
+  svntest.main.safe_rmtree(repo_dir, 1)
+
+  # Now relocate our working copy.
+  svntest.actions.run_and_verify_svn(None, None, [], 'switch', '--relocate',
+                                     repo_url, other_repo_url, wc_dir)
+
+  # Check the URL of the external -- was it updated to point to the
+  # .other repository URL?
+  svntest.actions.run_and_verify_info([{ 'URL' : '.*.other/A/D/G$' }],
+                                      os.path.join(wc_dir, 'A', 'B', 'G-ext'))
+
 
 ########################################################################
 # Run the tests
@@ -2951,7 +3143,8 @@ test_list = [ None,
               switch_change_repos_root,
               relocate_and_propset,
               forced_switch,
-              forced_switch_failures,
+              XFail(forced_switch_failures,
+                    svntest.main.is_ra_type_dav_serf),
               switch_scheduled_add,
               SkipUnless(mergeinfo_switch_elision, server_has_mergeinfo),
               switch_with_obstructing_local_adds,
@@ -2969,7 +3162,8 @@ test_list = [ None,
               single_file_relocate,
               relocate_with_switched_children,
               XFail(copy_with_switched_subdir),
-             ]
+              XFail(relocate_with_relative_externals),
+              ]
 
 if __name__ == '__main__':
   svntest.main.run_tests(test_list)

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/trans_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/trans_tests.py?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/trans_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/trans_tests.py Wed Sep 15 19:32:26 2010
@@ -868,9 +868,10 @@ def props_only_file_update(sbox):
 
   # We used to leave some temporary files around. Make sure that we don't.
   temps = os.listdir(os.path.join(wc_dir, svntest.main.get_admin_name(), 'tmp'))
-  temps.remove('prop-base')
-  temps.remove('props')
-  temps.remove('text-base')
+  if os.path.exists(os.path.join(wc_dir, svntest.main.get_admin_name(),
+                                 'tmp', 'props')):
+    temps.remove('prop-base')
+    temps.remove('props')
   if temps:
     print('Temporary files leftover: %s' % (', '.join(temps),))
     raise svntest.Failure

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/tree_conflict_tests.py?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/tree_conflict_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/tree_conflict_tests.py Wed Sep 15 19:32:26 2010
@@ -51,7 +51,7 @@ def verbose_print(line):
 
 # If verbose mode is enabled, print the (assumed newline-terminated) LINES.
 def verbose_printlines(lines):
-  if main.verbose_mode:
+  if main.options.verbose:
     for line in lines:
       sys.stdout.write(line)
 
@@ -107,6 +107,7 @@ def incoming_paths(root_dir, parent_dir)
     'F1' : os.path.join(root_dir,   "F1"),
     'F'  : os.path.join(parent_dir, "F"),
     'F2' : os.path.join(parent_dir, "F2-in"),
+    'F3' : os.path.join(root_dir,   "F3"),
     'D1' : os.path.join(root_dir,   "D1"),
     'D'  : os.path.join(parent_dir, "D"),
     'D2' : os.path.join(parent_dir, "D2-in"),
@@ -120,6 +121,7 @@ def localmod_paths(root_dir, parent_dir)
     'F1' : os.path.join(root_dir,   "F1"),
     'F'  : os.path.join(parent_dir, "F"),
     'F2' : os.path.join(parent_dir, "F2-local"),
+    'F3' : os.path.join(root_dir,   "F3"),
     'D1' : os.path.join(root_dir,   "D1"),
     'D'  : os.path.join(parent_dir, "D"),
     'D2' : os.path.join(parent_dir, "D2-local"),
@@ -127,8 +129,9 @@ def localmod_paths(root_dir, parent_dir)
 
 # Perform the action MODACTION on the WC items given by PATHS. The
 # available actions can be seen within this function.
-def modify(modaction, paths):
+def modify(modaction, paths, is_init=True):
   F1 = paths['F1']  # existing file to copy from
+  F3 = paths['F3']  # existing file to copy from
   F  = paths['F']   # target file
   F2 = paths['F2']  # non-existing file to copy/move to
   D1 = paths['D1']  # existing dir to copy from
@@ -161,7 +164,10 @@ def modify(modaction, paths):
     main.run_svn(None, 'add', D)
     main.run_svn(None, 'pset', 'dprop2', 'A prop of added dir D.', D)
   elif modaction == 'fC':  # file Copy (from F1)
-    main.run_svn(None, 'copy', F1, F)
+    if is_init:
+      main.run_svn(None, 'copy', F1, F)
+    else:
+      main.run_svn(None, 'copy', F3, F)
   elif modaction == 'dC':  # dir Copy (from D1)
     main.run_svn(None, 'copy', D1, D)
   elif modaction == 'fM':  # file Move (to F2)
@@ -199,6 +205,7 @@ def modify(modaction, paths):
 
 # File names:
 #   F1 = any existing file
+#   F3 = any existing file
 #   F  = the file-path being acted on
 #   F2 = any non-existent file-path
 #   D1 = any existing dir
@@ -316,8 +323,10 @@ def set_up_repos(wc_dir, br_dir, scenari
   # create the file F1 and dir D1 which the tests regard as pre-existing
   paths = incoming_paths(wc_dir, wc_dir)  # second arg is bogus but unimportant
   F1 = paths['F1']  # existing file to copy from
+  F3 = paths['F3']  # existing file to copy from
   main.file_write(F1, "This is initially file F1.\n")
-  main.run_svn(None, 'add', F1)
+  main.file_write(F3, "This is initially file F3.\n")
+  main.run_svn(None, 'add', F1, F3)
   D1 = paths['D1']  # existing dir to copy from
   main.run_svn(None, 'mkdir', D1)
 
@@ -411,7 +420,7 @@ def ensure_tree_conflict(sbox, operation
 
       verbose_print("--- Making local mods")
       for modaction in loc_action:
-        modify(modaction, localmod_paths(".", target_path))
+        modify(modaction, localmod_paths(".", target_path), is_init=False)
       if commit_local_mods:
         run_and_verify_svn(None, AnyOutput, [],
                            'commit', target_path,
@@ -695,102 +704,11 @@ def merge_dir_add_onto_not_none(sbox):
 
 #----------------------------------------------------------------------
 
-def keep_local_del_tc_inside(sbox):
-  "--keep-local del on dir with TCs inside"
-  #          A/C       <-  delete with --keep-local
-  # A  +  C  A/C/dir
-  # A  +  C  A/C/file
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  C   = os.path.join(wc_dir, "A", "C")
-  dir = os.path.join(wc_dir, "A", "C", "dir")
-  file = os.path.join(wc_dir, "A", "C", "file")
-
-  # Add dir
-  main.run_svn(None, 'mkdir', dir)
-
-  # Add file
-  content = "This is the file 'file'.\n"
-  main.file_append(file, content)
-  main.run_svn(None, 'add', file)
-
-  main.run_svn(None, 'commit', '-m', 'Add dir and file', wc_dir)
-
-  # Remove dir and file in r3.
-  main.run_svn(None, 'delete', dir, file)
-  main.run_svn(None, 'commit', '-m', 'Remove dir and file', wc_dir)
-
-  # Warp back to -r2, dir and file coming back.
-  main.run_svn(None, 'update', '-r2', wc_dir)
-
-  # Set a meaningless prop on each dir and file
-  run_and_verify_svn(None,
-                     ["property 'propname' set on '" + dir + "'\n"],
-                     [], 'ps', 'propname', 'propval', dir)
-  run_and_verify_svn(None,
-                     ["property 'propname' set on '" + file + "'\n"],
-                     [], 'ps', 'propname', 'propval', file)
-
-  # Update WC to HEAD, tree conflicts result dir and file
-  # because there are local mods on the props.
-  expected_output = wc.State(wc_dir, {
-    'A/C/dir' : Item(status='  ', treeconflict='C'),
-    'A/C/file' : Item(status='  ', treeconflict='C'),
-    })
-
-  expected_disk = main.greek_state.copy()
-  expected_disk.add({
-    'A/C/dir' : Item(props={'propname' : 'propval'}),
-    'A/C/file' : Item(contents=content, props={'propname' : 'propval'}),
-    })
-
-  expected_status = get_virginal_state(wc_dir, 2)
-  expected_status.tweak(wc_rev='3')
-  expected_status.add({
-    'A/C/dir' : Item(status='A ', wc_rev='-', copied='+', treeconflict='C'),
-    'A/C/file' : Item(status='A ', wc_rev='-', copied='+', treeconflict='C'),
-    })
-  run_and_verify_update(wc_dir,
-                        expected_output, expected_disk, expected_status,
-                        None, None, None, None, None, 1,
-                        wc_dir)
-
-  # Delete A/C with --keep-local, in effect disarming the tree-conflicts.
-  run_and_verify_svn(None,
-                     verify.UnorderedOutput(['D         ' + C + '\n',
-                                             'D         ' + dir + '\n',
-                                             'D         ' + file + '\n']),
-                     [], 'delete', C, '--keep-local')
-
-  # Verify deletion status
-  # Note: the tree conflicts are still in the status.
-  expected_status.tweak('A/C', status='D ')
-  expected_status.tweak('A/C/dir', status='? ', copied=None, wc_rev=None)
-  expected_status.tweak('A/C/file', status='? ', copied=None, wc_rev=None)
-
-  run_and_verify_status(wc_dir, expected_status)
-
-  # Commit, remove the "disarmed" tree-conflict.
-  expected_output = wc.State(wc_dir, { 'A/C' : Item(verb='Deleting') })
-
-  expected_status.remove('A/C', 'A/C/dir', 'A/C/file')
-
-  run_and_verify_commit(wc_dir,
-                        expected_output, expected_status, None,
-                        wc_dir)
-
-#----------------------------------------------------------------------
-
 def force_del_tc_inside(sbox):
   "--force del on dir with TCs inside"
   ### This test is currently marked XFail because we don't remove tree
   ### conflicts upon "delete --force" yet. They linger and block
   ### the commit.
-  ### This should be handled the same as with --keep-local, but
-  ### the code does not have the proper antennae for that yet.
-  ### Fixing that separately.
 
   #          A/C       <-  delete with --force
   # A  +  C  A/C/dir
@@ -878,95 +796,6 @@ def force_del_tc_inside(sbox):
 
 #----------------------------------------------------------------------
 
-def keep_local_del_tc_is_target(sbox):
-  "--keep-local del on tree-conflicted targets"
-  #          A/C
-  # A  +  C  A/C/dir   <-  delete with --keep-local
-  # A  +  C  A/C/file  <-  delete with --keep-local
-  ### This test currently XFails because the tree-conflicts on dir and
-  ### file remain in the WC but were supposed to be unversioned by a commit
-  ### (because of a delete --keep-local).
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  C   = os.path.join(wc_dir, "A", "C")
-  dir = os.path.join(wc_dir, "A", "C", "dir")
-  file = os.path.join(wc_dir, "A", "C", "file")
-
-  # Add dir
-  main.run_svn(None, 'mkdir', dir)
-
-  # Add file
-  content = "This is the file 'file'.\n"
-  main.file_append(file, content)
-  main.run_svn(None, 'add', file)
-
-  main.run_svn(None, 'commit', '-m', 'Add dir and file', wc_dir)
-
-  # Remove dir and file in r3.
-  main.run_svn(None, 'delete', dir, file)
-  main.run_svn(None, 'commit', '-m', 'Remove dir and file', wc_dir)
-
-  # Warp back to -r2, dir and file coming back.
-  main.run_svn(None, 'update', '-r2', wc_dir)
-
-  # Set a meaningless prop on each dir and file
-  run_and_verify_svn(None,
-                     ["property 'propname' set on '" + dir + "'\n"],
-                     [], 'ps', 'propname', 'propval', dir)
-  run_and_verify_svn(None,
-                     ["property 'propname' set on '" + file + "'\n"],
-                     [], 'ps', 'propname', 'propval', file)
-
-  # Update WC to HEAD, tree conflicts result dir and file
-  # because there are local mods on the props.
-  expected_output = wc.State(wc_dir, {
-    'A/C/dir' : Item(status='  ', treeconflict='C'),
-    'A/C/file' : Item(status='  ', treeconflict='C'),
-    })
-
-  expected_disk = main.greek_state.copy()
-  expected_disk.add({
-    'A/C/dir' : Item(props={'propname' : 'propval'}),
-    'A/C/file' : Item(contents=content, props={'propname' : 'propval'}),
-    })
-
-  expected_status = get_virginal_state(wc_dir, 2)
-  expected_status.tweak(wc_rev='3')
-  expected_status.add({
-    'A/C/dir' : Item(status='A ', wc_rev='-', copied='+', treeconflict='C'),
-    'A/C/file' : Item(status='A ', wc_rev='-', copied='+', treeconflict='C'),
-    })
-  run_and_verify_update(wc_dir,
-                        expected_output, expected_disk, expected_status,
-                        None, None, None, None, None, 1,
-                        wc_dir)
-
-  # Delete nodes with --keep-local, in effect disarming the tree-conflicts.
-  run_and_verify_svn(None,
-                     ['D         ' + dir + '\n',
-                      'D         ' + file + '\n'],
-                     [],
-                     'delete', dir, file, '--keep-local')
-
-  expected_status.tweak('A/C/dir', status='? ', copied=None, wc_rev=None)
-  expected_status.tweak('A/C/file', status='? ', copied=None, wc_rev=None)
-  run_and_verify_status(wc_dir, expected_status)
-
-  # Commit, remove the "disarmed" tree-conflict.
-  expected_output = wc.State(wc_dir, {})
-
-  ### This is why this test currently XFails. We want the conflicts
-  ### on the unversioned nodes to go away.
-  expected_status.remove('A/C/dir', 'A/C/file')
-
-  run_and_verify_commit(wc_dir,
-                        expected_output, expected_status, None,
-                        wc_dir)
-
-#----------------------------------------------------------------------
-
 def force_del_tc_is_target(sbox):
   "--force del on tree-conflicted targets"
   #          A/C
@@ -1125,7 +954,10 @@ def query_absent_tree_conflicted_dir(sbo
   ## svn: Expected node '/.../tree_conflict_tests-20/A/C' to be added.
 
   # using status:
-  run_and_verify_status(C_C_path, None)
+  expected_output = wc.State(wc_dir, {
+    'A/C/C' : Item(status='? ', treeconflict='C'),
+    })
+  run_and_verify_status(C_C_path, expected_output)
 
   # using info:
   run_and_verify_svn(None, None, [], 'info', C_C_path)
@@ -1251,11 +1083,9 @@ test_list = [ None,
               XFail(merge_dir_del_onto_not_same),
               merge_dir_del_onto_not_dir,
               merge_dir_add_onto_not_none,
-              keep_local_del_tc_inside,
               XFail(force_del_tc_inside),
-              XFail(keep_local_del_tc_is_target),
               XFail(force_del_tc_is_target),
-              XFail(query_absent_tree_conflicted_dir),
+              query_absent_tree_conflicted_dir,
               XFail(up_add_onto_add_revert),
               XFail(lock_update_only),
              ]

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/update_tests.py?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/update_tests.py Wed Sep 15 19:32:26 2010
@@ -26,10 +26,11 @@
 
 # General modules
 import sys, re, os, subprocess
+import time
 
 # Our testing module
 import svntest
-from svntest import wc
+from svntest import wc, actions, verify
 from merge_tests import expected_merge_output
 from merge_tests import set_up_branch
 
@@ -324,17 +325,23 @@ def update_missing(sbox):
   svntest.main.safe_rmtree(E_path)
   svntest.main.safe_rmtree(H_path)
 
+  # In single-db mode all missing items will just be restored
+  if svntest.main.wc_is_singledb(wc_dir):
+    A_or_Restored = Item(verb='Restored')
+  else:
+    A_or_Restored = Item(status='A ')
+
   # Create expected output tree for an update of the missing items by name
   expected_output = svntest.wc.State(wc_dir, {
     'A/mu'        : Item(verb='Restored'),
     'A/D/G/rho'   : Item(verb='Restored'),
-    'A/B/E' : Item(status='A '),
-    'A/B/E/alpha' : Item(status='A '),
-    'A/B/E/beta' : Item(status='A '),
-    'A/D/H' : Item(status='A '),
-    'A/D/H/chi' : Item(status='A '),
-    'A/D/H/omega' : Item(status='A '),
-    'A/D/H/psi' : Item(status='A '),
+    'A/B/E'       : A_or_Restored,
+    'A/B/E/alpha' : A_or_Restored,
+    'A/B/E/beta'  : A_or_Restored,
+    'A/D/H'       : A_or_Restored,
+    'A/D/H/chi'   : A_or_Restored,
+    'A/D/H/omega' : A_or_Restored,
+    'A/D/H/psi'   : A_or_Restored,
     })
 
   # Create expected disk tree for the update.
@@ -793,15 +800,25 @@ def obstructed_update_alters_wc_props(sb
 
   # Update the WC to that newer rev to trigger the obstruction.
   #print "Updating WC"
-  expected_output = svntest.wc.State(wc_dir, {})
+  # svntest.factory.make(sbox, 'svn update')
+  # exit(0)
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/foo'             : Item(status='  ', treeconflict='C'),
+  })
+
   expected_disk = svntest.main.greek_state.copy()
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  error_re = 'Failed to add directory.*object of the same name already exists'
-  svntest.actions.run_and_verify_update(wc_dir,
-                                        expected_output,
-                                        expected_disk,
-                                        expected_status,
-                                        error_re)
+  expected_disk.add({
+    'A/foo'             : Item(contents="an obstruction"),
+  })
+
+  expected_status = actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({
+    'A/foo'             : Item(status='? ', treeconflict='C'),
+  })
+
+  actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+    expected_status, None, None, None, None, None, False, wc_dir)
+
 
   # Remove the file which caused the obstruction.
   #print "Removing obstruction"
@@ -1062,6 +1079,17 @@ def update_deleted_missing_dir(sbox):
     'A/D/H' : Item(status='D '),
     })
 
+  # In single-db mode the missing items are restored before the update
+  if svntest.main.wc_is_singledb(wc_dir):
+    expected_output.add({
+      'A/D/H/psi'         : Item(verb='Restored'),
+      'A/D/H/omega'       : Item(verb='Restored'),
+      'A/D/H/chi'         : Item(verb='Restored'),
+      'A/B/E/beta'        : Item(verb='Restored'),
+      'A/B/E/alpha'       : Item(verb='Restored')
+      # A/B/E and A/D/H are also restored, but are then overriden by the delete
+    })
+
   # Create expected disk tree for the update.
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
@@ -1087,6 +1115,12 @@ def update_deleted_missing_dir(sbox):
   # This time we're updating the whole working copy
   expected_status.tweak(wc_rev=2)
 
+  # And now we don't expect restore operations
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E' : Item(status='D '),
+    'A/D/H' : Item(status='D '),
+    })
+
   # Do the update, on the whole working copy this time
   svntest.actions.run_and_verify_update(wc_dir,
                                         expected_output,
@@ -1134,12 +1168,23 @@ def another_hudson_problem(sbox):
   # Update missing directory to receive the delete, this should mark G
   # as 'deleted' and should not alter gamma's entry.
 
+  if not svntest.main.wc_is_singledb(wc_dir):
+    expected_output = ['D    '+G_path+'\n',
+                       'Updated to revision 3.\n',
+                       ]
+  else:
+    expected_output = ['Restored \'' + G_path + '\'\n',
+                       'Restored \'' + G_path + os.path.sep + 'pi\'\n',
+                       'Restored \'' + G_path + os.path.sep + 'rho\'\n',
+                       'Restored \'' + G_path + os.path.sep + 'tau\'\n',
+                       'D    '+G_path+'\n',
+                       'Updated to revision 3.\n',
+                       ]
+
   # Sigh, I can't get run_and_verify_update to work (but not because
   # of issue 919 as far as I can tell)
   svntest.actions.run_and_verify_svn(None,
-                                     ['D    '+G_path+'\n',
-                                      'Updated to revision 3.\n',
-                                      ], [],
+                                     expected_output, [],
                                      'up', G_path)
 
   # Both G and gamma should be 'deleted', update should produce no output
@@ -1545,6 +1590,9 @@ def nested_in_read_only(sbox):
   sbox.build()
   wc_dir = sbox.wc_dir
 
+  if svntest.main.wc_is_singledb(wc_dir):
+    raise svntest.Skip('Unsupported in single-db')
+
   # Delete/commit a file
   alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
   svntest.actions.run_and_verify_svn(None, None, [], 'rm', alpha_path)
@@ -2147,46 +2195,126 @@ def forced_update_failures(sbox):
 
   # A forced update that tries to add a file when an unversioned directory
   # of the same name already exists should fail.
-  F_Path = os.path.join(wc_backup, 'A', 'B', 'F')
-  svntest.actions.run_and_verify_update(F_Path, None, None, None,
-                                        ".*Failed to add file.*" + \
-                                        "a non-file object of the " + \
-                                        "same name already exists",
-                                        None, None, None, None, 0, F_Path,
-                                        '--force')
+  #svntest.factory.make(sbox, """svn up --force $WC_DIR.backup/A/B/F""")
+  #exit(0)
+  backup_A_B_F = os.path.join(wc_backup, 'A', 'B', 'F')
+
+  # svn up --force $WC_DIR.backup/A/B/F
+  expected_output = svntest.wc.State(wc_backup, {
+    'A/B/F/nu'          : Item(status='  ', treeconflict='C'),
+  })
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'A/B/F/nu'          : Item(),
+    'A/C/I'             :
+    Item(contents="This is the file 'I'...shouldn't I be a dir?\n"),
+  })
+
+  expected_status = actions.get_virginal_state(wc_backup, 1)
+  expected_status.add({
+    'A/B/F/nu'          : Item(status='? ', treeconflict='C'),
+  })
+  expected_status.tweak('A/B/F', wc_rev='2')
+
+  actions.run_and_verify_update(wc_backup, expected_output,
+    expected_disk, expected_status, None, None, None, None, None, False,
+    '--force', backup_A_B_F)
+
 
   # A forced update that tries to add a directory when an unversioned file
   # of the same name already exists should fail.
-  C_Path = os.path.join(wc_backup, 'A', 'C')
-  svntest.actions.run_and_verify_update(C_Path, None, None, None,
-                                        ".*Failed to add directory.*" + \
-                                        "a non-directory object of the " + \
-                                        "same name already exists",
-                                        None, None, None, None, 0, C_Path,
-                                        '--force')
-
-  # Clean-up what we have done so far.  Remove the unversioned file A/C/I
-  # and the unversioned directory A/B/F/nu.  Then update the backup to
-  # r2, except for A/C, update that to r1 so A/C/I isn't present.
-  # working copy.
-  os.remove(I_path)
-  os.rmdir(nu_path)
-  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
-                                     'up', wc_backup)
-  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
-                                     'up', '-r', '1', C_Path)
-
-  # Checkout %URL%/A/C/I@2 directly to A/C/I.  A/C, being at r1, views
-  # this as an unversioned object.
-  I_url = sbox.repo_url + "/A/C/I"
-  exit_code, so, se = svntest.actions.run_and_verify_svn(
-    "Unexpected error during co",
-    ['Checked out revision 2.\n'], [],
-    "co", I_url, I_path)
-  svntest.actions.run_and_verify_update(C_Path, None, None, None,
-                               "Failed to add directory '.*I'.*already exists",
-                                        None, None, None, None, 0, C_Path,
-                                        '--force')
+  # svntest.factory.make(sbox, """
+  #   svn up --force wc_dir_backup/A/C
+  #   rm -rf wc_dir_backup/A/C/I wc_dir_backup/A/B/F/nu
+  #   svn up wc_dir_backup
+  #   svn up -r1 wc_dir_backup/A/C
+  #   svn co url/A/C/I wc_dir_backup/A/C/I
+  #   svn up --force wc_dir_backup/A/C
+  #   """)
+  # exit(0)
+  url = sbox.repo_url
+  wc_dir_backup = sbox.wc_dir + '.backup'
+
+  backup_A_B_F_nu = os.path.join(wc_dir_backup, 'A', 'B', 'F', 'nu')
+  backup_A_C = os.path.join(wc_dir_backup, 'A', 'C')
+  backup_A_C_I = os.path.join(wc_dir_backup, 'A', 'C', 'I')
+  url_A_C_I = url + '/A/C/I'
+
+  # svn up --force wc_dir_backup/A/C
+  expected_output = svntest.wc.State(wc_dir_backup, {
+    'A/C/I'             : Item(status='  ', treeconflict='C'),
+  })
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'A/B/F/nu'          : Item(),
+    'A/C/I'             :
+    Item(contents="This is the file 'I'...shouldn't I be a dir?\n"),
+  })
+
+  expected_status = actions.get_virginal_state(wc_dir_backup, 1)
+  expected_status.add({
+    'A/C/I'             : Item(status='? ', treeconflict='C'),
+    'A/B/F/nu'          : Item(status='? ', treeconflict='C'),
+  })
+  expected_status.tweak('A/C', 'A/B/F', wc_rev='2')
+
+  actions.run_and_verify_update(wc_dir_backup, expected_output,
+    expected_disk, expected_status, None, None, None, None, None, False,
+    '--force', backup_A_C)
+
+  # rm -rf wc_dir_backup/A/C/I wc_dir_backup/A/B/F/nu
+  os.remove(backup_A_C_I)
+  svntest.main.safe_rmtree(backup_A_B_F_nu)
+
+  # svn up wc_dir_backup
+  expected_output = svntest.wc.State(wc_dir_backup, {
+    'A/C/I'             : Item(status='A '),
+    'A/B/F/nu'          : Item(status='A '),
+  })
+
+  expected_disk.tweak('A/B/F/nu', contents="This is the file 'nu'\n")
+  expected_disk.tweak('A/C/I', contents=None)
+
+  expected_status.tweak(wc_rev='2', status='  ')
+  expected_status.tweak('A/C/I', 'A/B/F/nu', treeconflict=None)
+
+  actions.run_and_verify_update(wc_dir_backup, expected_output,
+    expected_disk, expected_status, None, None, None, None, None, False,
+    wc_dir_backup)
+
+  # svn up -r1 wc_dir_backup/A/C
+  expected_output = svntest.wc.State(wc_dir_backup, {
+    'A/C/I'             : Item(status='D '),
+  })
+
+  expected_disk.remove('A/C/I')
+
+  expected_status.remove('A/C/I')
+  expected_status.tweak('A/C', wc_rev='1')
+
+  actions.run_and_verify_update(wc_dir_backup, expected_output,
+    expected_disk, expected_status, None, None, None, None, None, False,
+    '-r1', backup_A_C)
+
+  # svn co url/A/C/I wc_dir_backup/A/C/I
+  expected_output = svntest.wc.State(wc_dir_backup, {})
+
+  expected_disk = svntest.wc.State(wc_dir, {})
+
+  actions.run_and_verify_checkout2(False, url_A_C_I, backup_A_C_I,
+    expected_output, expected_disk, None, None, None, None)
+
+  # svn up --force wc_dir_backup/A/C
+  expected_error = (
+    "svn: Failed to add directory .*I.*working copy with the same name "
+    + "already exists"
+  )
+
+  actions.run_and_verify_update(wc_dir_backup, None, None, None,
+    expected_error, None, None, None, None, False, '--force', backup_A_C)
+
 
 #----------------------------------------------------------------------
 # Test for issue #2556. The tests maps a virtual drive to a working copy
@@ -2803,44 +2931,17 @@ def update_with_obstructing_additions(sb
     })
 
   expected_status.tweak('', 'iota', status='  ', wc_rev=4)
-  expected_status.tweak('omicron', status='A ', copied='+', wc_rev='-',
+  expected_status.tweak('omicron', status='R ', copied='+', wc_rev='-',
                         treeconflict='C')
 
-  ### ugh. this update will leave the working copy in a BROKEN state.
-  ### the incoming add is flagged as a tree conflict against our local-copy.
-  ### the file will be "skipped" during the update, and the file will be
-  ### dropped on the floor. 'omicron' is then left in the same "local-copy"
-  ### scheduling state (schedule-add). however, this is incorrect because
-  ### the directory says it is r4 which *includes* an 'omicron', yet we
-  ### have discarded all knowledge of it. the update *should* place the
-  ### incoming 'omicron' into the "revert base" and mark our local copy as
-  ### a schedule-replace.
-  ###
-  ### see: http://svn.haxx.se/dev/archive-2009-04/0760.shtml
   svntest.actions.run_and_verify_update(wc_dir, expected_output,
                                         expected_disk, expected_status,
                                         None, None, None, None, None, False,
                                         wc_dir, '-N')
 
   # Resolve the tree conflict.
-  svntest.main.run_svn(None, 'resolve', '--accept', 'working', omicron_path)
+  svntest.main.run_svn(None, 'resolved', omicron_path)
 
-  ### in wc-1, I believe we see the local-copy as a different revision
-  ### than the parent directory (entry->revision is overloaded; normally,
-  ### it is supposed to represent the BASE revision; we drop a copyfrom
-  ### rev in there, making it appear different from the parent), so we
-  ### send the mixed-rev in the update report (UNVERIFIED; this is
-  ### speculation on cause; the effect is known, as follows). given the
-  ### mixed-rev report, the server will send down another add, reporting
-  ### another conflict.
-  ###
-  ### in wc-ng, a local-copy does not have a revision (it hasn't been
-  ### committed yet!). further, all BASE information has been lost, so
-  ### there is no knowledge of a BASE 'omicron', which is not-present or
-  ### at an old revision, or whatever. thus, wc-ng sees "r4" for the
-  ### directory and thinks there are no sub-items to report as different.
-  ### the server returns with "you're up to date" rather than sending
-  ### another add. thus, no conflict occurs on 'omicron'.
   expected_output = wc.State(wc_dir, { })
 
   expected_status.tweak('omicron', treeconflict=None)
@@ -4235,20 +4336,34 @@ def restarted_update_should_delete_dir_p
                                         expected_status, None, other_wc)
 
   # Back in the first working copy, create an obstructing path and
-  # update. The update will be interrupted, resulting in an incomplete
-  # dir which still has the property.
+  # update. The update will flag a tree conflict.
   svntest.main.file_write(zeta_path, 'Obstructing file\n')
-  error_re = 'Failed to add file.*file of the same name already exists'
 
-  svntest.actions.run_and_verify_update(wc_dir, None, None, None,
-                                        error_re)
+  #svntest.factory.make(sbox, 'svn up')
+  #exit(0)
+  # svn up
+  expected_output = svntest.wc.State(wc_dir, {
+    'A'                 : Item(status=' U'),
+    'A/zeta'            : Item(status='  ', treeconflict='C'),
+  })
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'A/zeta'            : Item(contents="Obstructing file\n"),
+  })
+
+  expected_status = actions.get_virginal_state(wc_dir, 3)
+  expected_status.add({
+    'A/zeta'            : Item(status='? ', treeconflict='C'),
+  })
+
+  actions.run_and_verify_update(wc_dir, expected_output, expected_disk,
+    expected_status, None, None, None, None, None, False, wc_dir)
 
   # Now, delete the obstructing path and rerun the update.
-  # A's property should disappear.
   os.unlink(zeta_path)
 
   expected_output = svntest.wc.State(wc_dir, {
-    'A'      : Item(status=' U'),
     'A/zeta' : Item(status='A '),
     })
 
@@ -4304,6 +4419,8 @@ def tree_conflicts_on_update_1_1(sbox):
   # use case 1, as in notes/tree-conflicts/use-cases.txt
   # 1.1) local tree delete, incoming leaf edit
 
+  sbox.build()
+
   expected_output = deep_trees_conflict_output.copy()
   expected_output.add({
     'DDF/D1/D2'         : Item(status='D '),
@@ -4318,6 +4435,10 @@ def tree_conflicts_on_update_1_1(sbox):
   })
 
   expected_disk = disk_empty_dirs.copy()
+  if svntest.main.wc_is_singledb(sbox.wc_dir):
+    expected_disk.remove('D/D1', 'DF/D1', 'DD/D1', 'DD/D1/D2',
+                         'DDF/D1', 'DDF/D1/D2',
+                         'DDD/D1', 'DDD/D1/D2', 'DDD/D1/D2/D3')
 
   # The files delta, epsilon, and zeta are incoming additions, but since
   # they are all within locally deleted trees they should also be schedule
@@ -4386,6 +4507,8 @@ def tree_conflicts_on_update_1_2(sbox):
 
   # 1.2) local tree delete, incoming leaf delete
 
+  sbox.build()
+
   expected_output = deep_trees_conflict_output.copy()
   expected_output.add({
     'DDD/D1/D2'         : Item(status='D '),
@@ -4423,6 +4546,10 @@ def tree_conflicts_on_update_1_2(sbox):
   expected_disk.remove('D/D1',
                        'DD/D1/D2',
                        'DDD/D1/D2/D3')
+  if svntest.main.wc_is_singledb(sbox.wc_dir):
+    expected_disk.remove('DF/D1', 'DD/D1',
+                         'DDF/D1', 'DDF/D1/D2',
+                         'DDD/D1', 'DDD/D1/D2')
 
   expected_info = {
     'F/alpha' : {
@@ -4827,8 +4954,6 @@ def tree_conflicts_on_update_3(sbox):
 #----------------------------------------------------------------------
 # Test for issue #3354 'update fails when file with local mods is moved
 # and modified'
-#
-# Marked as XFail until issue #3354 is resolved.
 def update_moves_and_modifies_an_edited_file(sbox):
   "update moves and modifies a file with edits"
 
@@ -5470,6 +5595,160 @@ def mergeinfo_updates_merge_with_local_m
                                      'pg', SVN_PROP_MERGEINFO, '-R',
                                      A_COPY_path)
 
+#----------------------------------------------------------------------
+# Test for receiving modified properties on added files that were originally
+# moved from somewhere else. (Triggers locate_copyfrom behavior)
+def add_moved_file_has_props(sbox):
+  """update adding moved file receives modified props"""
+  sbox.build()
+
+  wc_dir = sbox.wc_dir
+
+  G = os.path.join(os.path.join(wc_dir, 'A', 'D', 'G'))
+  pi  = os.path.join(G, 'pi')
+  G_new = os.path.join(wc_dir, 'G_new')
+
+  # Give pi some property
+  svntest.main.run_svn(None, 'ps', 'svn:eol-style', 'native', pi)
+  svntest.main.run_svn(None, 'ci', wc_dir, '-m', 'added eol-style')
+
+  svntest.actions.run_and_verify_svn(None, 'At revision 2.', [], 'up', wc_dir)
+
+  # Now move pi to a different place
+  svntest.main.run_svn(None, 'mkdir', G_new)
+  svntest.main.run_svn(None, 'mv', pi, G_new)
+  svntest.main.run_svn(None, 'ci', wc_dir, '-m', 'Moved pi to G_new')
+
+  svntest.actions.run_and_verify_svn(None, 'At revision 3.', [], 'up', wc_dir)
+
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
+  expected_status.remove('A/D/G/pi')
+  expected_status.add({
+    'G_new'    : Item (status='  ', wc_rev=3),
+    'G_new/pi' : Item (status='  ', wc_rev=3),
+  })
+
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  svntest.main.run_svn(None, 'up', '-r', '0', G_new)
+  svntest.main.run_svn(None, 'up', wc_dir)
+
+  # This shouldn't show property modifications, but at r982550 it did.
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+#----------------------------------------------------------------------
+# Test for receiving modified properties on added files that were originally
+# moved from somewhere else. (Triggers locate_copyfrom behavior). This is
+# an extended variant that has another property change on the new path
+def add_moved_file_has_props2(sbox):
+  """update adding moved node receives 2* props"""
+  sbox.build()
+
+  wc_dir = sbox.wc_dir
+
+  G = os.path.join(os.path.join(wc_dir, 'A', 'D', 'G'))
+  pi  = os.path.join(G, 'pi')
+  G_new = os.path.join(wc_dir, 'G_new')
+
+  # Give pi some property
+  svntest.main.run_svn(None, 'ps', 'svn:eol-style', 'native', pi)
+  svntest.main.run_svn(None, 'ci', wc_dir, '-m', 'added eol-style')
+
+  svntest.actions.run_and_verify_svn(None, 'At revision 2.', [], 'up', wc_dir)
+
+  # Now move pi to a different place
+  svntest.main.run_svn(None, 'mkdir', G_new)
+  svntest.main.run_svn(None, 'mv', pi, G_new)
+  svntest.main.run_svn(None, 'ps', 'svn:eol-style', 'CR', os.path.join(G_new, 'pi'))
+
+  svntest.main.run_svn(None, 'ci', wc_dir, '-m', 'Moved pi to G_new')
+
+  svntest.actions.run_and_verify_svn(None, 'At revision 3.', [], 'up', wc_dir)
+
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
+  expected_status.remove('A/D/G/pi')
+  expected_status.add({
+    'G_new'    : Item (status='  ', wc_rev=3),
+    'G_new/pi' : Item (status='  ', wc_rev=3),
+  })
+
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  svntest.main.run_svn(None, 'up', '-r', '0', G_new)
+  svntest.main.run_svn(None, 'up', wc_dir)
+
+  # This shouldn't show local modifications, but currently it
+  # shows a property conflict on G_new/pi.
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+
+# A regression test for a 1.7-dev crash upon updating a WC to a different
+# revision when it contained an excluded dir.
+def update_with_excluded_subdir(sbox):
+  """update with an excluded subdir"""
+  sbox.build()
+
+  wc_dir = sbox.wc_dir
+
+  G = os.path.join(os.path.join(wc_dir, 'A', 'D', 'G'))
+
+  # Make the directory 'G' excluded.
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/D/G' : Item(status='D '),
+    })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
+  svntest.actions.run_and_verify_update(wc_dir, expected_output,
+                                        expected_disk, expected_status,
+                                        None, None, None, None, None, False,
+                                        '--set-depth=exclude', G)
+
+  # Commit a new revision so there is something to update to.
+  svntest.main.run_svn(None, 'mkdir', '-m', '', sbox.repo_url + '/New')
+
+  # Test updating the WC.
+  expected_output = svntest.wc.State(wc_dir, {
+    'New' : Item(status='A ') })
+  expected_disk.add({
+    'New' : Item() })
+  expected_status.add({
+    'New' : Item(status='  ') })
+  expected_status.tweak(wc_rev=2)
+  svntest.actions.run_and_verify_update(wc_dir, expected_output,
+                                        expected_disk, expected_status)
+
+#----------------------------------------------------------------------
+# Test for issue #3471 'svn up touches file w/ lock & svn:keywords property'
+#
+# Marked as XFail until the issue is fixed.
+def update_with_file_lock_and_keywords_property_set(sbox):
+  """update with file lock & keywords property set"""
+  sbox.build()
+
+  wc_dir = sbox.wc_dir
+
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+  svntest.main.file_append(mu_path, '$Id$')
+  svntest.main.run_svn(None, 'ps', 'svn:keywords', 'Id', mu_path)
+  svntest.main.run_svn(None, 'lock', mu_path)
+  mu_ts_before_update = os.path.getmtime(mu_path)
+
+  # Make sure we are at a different timestamp to really notice a mtime change
+  time.sleep(1)
+
+  # Issue #3471 manifests itself here; The timestamp of 'mu' gets updated 
+  # to the time of the last "svn up".
+  sbox.simple_update()
+  mu_ts_after_update = os.path.getmtime(mu_path)
+  if (mu_ts_before_update != mu_ts_after_update):
+    print("The timestamp of 'mu' before and after update does not match.")
+    raise svntest.Failure
+  
+
 #######################################################################
 # Run the tests
 
@@ -5538,6 +5817,10 @@ test_list = [ None,
               XFail(update_deleted_locked_files),
               XFail(update_empty_hides_entries),
               mergeinfo_updates_merge_with_local_mods,
+              add_moved_file_has_props,
+              XFail(add_moved_file_has_props2),
+              update_with_excluded_subdir,
+              XFail(update_with_file_lock_and_keywords_property_set)
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/upgrade_tests.py?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/upgrade_tests.py Wed Sep 15 19:32:26 2010
@@ -37,6 +37,7 @@ import tarfile
 import tempfile
 
 import svntest
+from svntest import wc
 
 Item = svntest.wc.StateItem
 XFail = svntest.testcase.XFail
@@ -52,12 +53,16 @@ def get_current_format():
   return int(re.search("\n#define SVN_WC__VERSION (\d+)\n", format_file).group(1))
 
 
-def replace_sbox_with_tarfile(sbox, tar_filename):
+def replace_sbox_with_tarfile(sbox, tar_filename,
+                              dir=None):
   try:
     svntest.main.safe_rmtree(sbox.wc_dir)
   except OSError, e:
     pass
 
+  if not dir:
+    dir = tar_filename.split('.')[0]
+
   tarpath = os.path.join(os.path.dirname(sys.argv[0]), 'upgrade_tests_data',
                          tar_filename)
   t = tarfile.open(tarpath, 'r:bz2')
@@ -65,8 +70,7 @@ def replace_sbox_with_tarfile(sbox, tar_
   for member in t.getmembers():
     t.extract(member, extract_dir)
 
-  shutil.move(os.path.join(extract_dir, tar_filename.split('.')[0]),
-              sbox.wc_dir)
+  shutil.move(os.path.join(extract_dir, dir), sbox.wc_dir)
 
 
 def check_format(sbox, expected_format):
@@ -82,9 +86,19 @@ def check_format(sbox, expected_format):
       raise svntest.Failure("found format '%d'; expected '%d'; in wc '%s'" %
                             (found_format, expected_format, root))
 
+    if svntest.main.wc_is_singledb(sbox.wc_dir):
+      dirs[:] = []
+
     if dot_svn in dirs:
       dirs.remove(dot_svn)
 
+def check_pristine(sbox, files):
+  for file in files:
+    file_path = sbox.ospath(file)
+    file_text = open(file_path, 'r').read()
+    file_pristine = open(svntest.wc.text_base_path(file_path), 'r').read()
+    if (file_text != file_pristine):
+      raise svntest.Failure("pristine mismatch for '%s'" % (file))
 
 def check_dav_cache(dir_path, wc_id, expected_dav_caches):
   dot_svn = svntest.main.get_admin_name()
@@ -104,6 +118,60 @@ def check_dav_cache(dir_path, wc_id, exp
 
   db.close()
 
+# Very simple working copy property diff handler for single line textual properties
+# Should probably be moved to svntest/actions.py after some major refactoring.
+def simple_property_verify(dir_path, expected_props):
+
+  # Shows all items in dict1 that are not also in dict2
+  def diff_props(dict1, dict2, name, match):
+
+    equal = True;
+    for key in dict1:
+      node = dict1[key]
+      node2 = dict2.get(key, None)
+      if node2:
+        for prop in node:
+          v1 = node[prop]
+          v2 = node2.get(prop, None)
+
+          if not v2:
+            print('\'%s\' property on \'%s\' not found in %s' %
+                  (prop, key, name))
+            equal = False
+          if match and v1 != v2:
+            print('Expected \'%s\' on \'%s\' to be \'%s\', but found \'%s\'' %
+                  (prop, key, v1, v2))
+            equal = False
+      else:
+        print('\'%s\': %s not found in %s' % (key, dict1[key], name))
+        equal = False
+
+    return equal
+
+
+  exit_code, output, errput = svntest.main.run_svn(None, 'proplist', '-R',
+                                                   '-v', dir_path)
+
+  actual_props = {}
+  target = None
+  name = None
+
+  for i in output:
+    if i.startswith('Properties on '):
+      target = i[15+len(dir_path)+1:-3].replace(os.path.sep, '/')
+    elif not i.startswith('    '):
+      name = i.strip()
+    else:
+      v = actual_props.get(target, {})
+      v[name] = i.strip()
+      actual_props[target] = v
+
+  v1 = diff_props(expected_props, actual_props, 'actual', True)
+  v2 = diff_props(actual_props, expected_props, 'expected', False)
+
+  if not v1 or not v2:
+    print('Actual properties: %s' % actual_props)
+    raise svntest.Failure("Properties unequal")
 
 def run_and_verify_status_no_server(wc_dir, expected_status):
   "same as svntest.actions.run_and_verify_status(), but without '-u'"
@@ -142,6 +210,7 @@ def basic_upgrade(sbox):
   # Now check the contents of the working copy
   expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
   run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+  check_pristine(sbox, ['iota', 'A/mu'])
 
 def upgrade_with_externals(sbox):
   "upgrade with externals"
@@ -160,6 +229,8 @@ def upgrade_with_externals(sbox):
 
   # Actually check the format number of the upgraded working copy
   check_format(sbox, get_current_format())
+  check_pristine(sbox, ['iota', 'A/mu',
+                        'A/D/x/lambda', 'A/D/x/E/alpha'])
 
 def upgrade_1_5_body(sbox, subcommand):
   replace_sbox_with_tarfile(sbox, 'upgrade_1_5.tar.bz2')
@@ -180,6 +251,7 @@ def upgrade_1_5_body(sbox, subcommand):
   # Now check the contents of the working copy
   expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
   run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+  check_pristine(sbox, ['iota', 'A/mu'])
 
 
 def upgrade_1_5(sbox):
@@ -341,6 +413,238 @@ def basic_upgrade_1_0(sbox):
   svntest.actions.run_and_verify_info(expected_infos,
                                       os.path.join(sbox.wc_dir, 'DELETED'))
 
+  check_pristine(sbox, ['iota', 'A/mu', 'A/D/H/zeta'])
+
+# Helper function for the x3 tests.
+def do_x3_upgrade(sbox):
+  # Attempt to use the working copy, this should give an error
+  expected_stderr = wc_is_too_old_regex
+  svntest.actions.run_and_verify_svn(None, None, expected_stderr,
+                                     'info', sbox.wc_dir)
+
+
+  # Now upgrade the working copy
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'upgrade', sbox.wc_dir)
+
+  # Actually check the format number of the upgraded working copy
+  check_format(sbox, get_current_format())
+
+  # Now check the contents of the working copy
+  expected_status = svntest.wc.State(sbox.wc_dir,
+    {
+      ''                  : Item(status='  ', wc_rev='2'),
+      'A'                 : Item(status='  ', wc_rev='2'),
+      'A/D'               : Item(status='  ', wc_rev='2'),
+      'A/D/H'             : Item(status='  ', wc_rev='2'),
+      'A/D/H/omega'       : Item(status='  ', wc_rev='2'),
+      'A/D/H/psi'         : Item(status='D ', wc_rev='2'),
+      'A/D/H/new'         : Item(status='A ', copied='+', wc_rev='-'),
+      'A/D/H/chi'         : Item(status='R ', copied='+', wc_rev='-'),
+      'A/D/gamma'         : Item(status='D ', wc_rev='2'),
+      'A/D/G'             : Item(status='  ', wc_rev='2'),
+      'A/B_new'           : Item(status='A ', copied='+', wc_rev='-'),
+      'A/B_new/B'         : Item(status='A ', copied='+', wc_rev='-'),
+      'A/B_new/B/E'       : Item(status=' M', copied='+', wc_rev='-'),
+      'A/B_new/B/E/alpha' : Item(status='  ', copied='+', wc_rev='-'),
+      'A/B_new/B/E/beta'  : Item(status='R ', copied='+', wc_rev='-'),
+      'A/B_new/B/new'     : Item(status='A ', copied='+', wc_rev='-'),
+      'A/B_new/B/lambda'  : Item(status='R ', copied='+', wc_rev='-'),
+      'A/B_new/B/F'       : Item(status='  ', copied='+', wc_rev='-'),
+      'A/B_new/E'         : Item(status=' M', copied='+', wc_rev='-'),
+      'A/B_new/E/alpha'   : Item(status=' M', copied='+', wc_rev='-'),
+      'A/B_new/E/beta'    : Item(status='RM', copied='+', wc_rev='-'),
+      'A/B_new/lambda'    : Item(status='R ', copied='+', wc_rev='-'),
+      'A/B_new/new'       : Item(status='A ', copied='+', wc_rev='-'),
+      'A/B_new/F'         : Item(status='  ', copied='+', wc_rev='-'),
+      'A/B'               : Item(status='  ', wc_rev='2'),
+      'A/B/E'             : Item(status='  ', wc_rev='2'),
+      'A/B/E/beta'        : Item(status='RM', copied='+', wc_rev='-'),
+      'A/B/E/alpha'       : Item(status=' M', wc_rev='2'),
+      'A/B/F'             : Item(status='  ', wc_rev='2'),
+      'A/B/lambda'        : Item(status='R ', copied='+', wc_rev='-'),
+      'A/B/new'           : Item(status='A ', copied='+', wc_rev='-'),
+      'A/G_new'           : Item(status='A ', copied='+', wc_rev='-'),
+      'A/G_new/rho'       : Item(status='R ', copied='+', wc_rev='-'),
+      'iota'              : Item(status='  ', wc_rev='2'),
+      'A_new'             : Item(status='A ', wc_rev='0'),
+      'A_new/alpha'       : Item(status='A ', copied='+', wc_rev='-'),
+    })
+  run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+
+  simple_property_verify(sbox.wc_dir, {
+      'A/B_new/E/beta'    : {'x3'           : '3x',
+                             'svn:eol-style': 'native'},
+      'A/B/E/beta'        : {'s'            : 't',
+                             'svn:eol-style': 'native'},
+      'A/B_new/B/E/alpha' : {'svn:eol-style': 'native'},
+      'A/B/E/alpha'       : {'q': 'r',
+                             'svn:eol-style': 'native'},
+      'A_new/alpha'       : {'svn:eol-style': 'native'},
+      'A/B_new/B/new'     : {'svn:eol-style': 'native'},
+      'A/B_new/E/alpha'   : {'svn:eol-style': 'native',
+                             'u': 'v'},
+      'A/B_new/B/E'       : {'q': 'r'},
+      'A/B_new/lambda'    : {'svn:eol-style': 'native'},
+      'A/B_new/E'         : {'x3': '3x'},
+      'A/B_new/new'       : {'svn:eol-style': 'native'},
+      'A/B/lambda'        : {'svn:eol-style': 'native'},
+      'A/B_new/B/E/beta'  : {'svn:eol-style': 'native'},
+      'A/B_new/B/lambda'  : {'svn:eol-style': 'native'},
+      'A/B/new'           : {'svn:eol-style': 'native'},
+      'A/G_new/rho'       : {'svn:eol-style': 'native'}
+  })
+
+  svntest.actions.run_and_verify_svn(None, 'Reverted.*', [],
+                                     'revert', '-R', sbox.wc_dir)
+
+  expected_status = svntest.wc.State(sbox.wc_dir,
+    {
+      ''                  : Item(status='  ', wc_rev='2'),
+      'A'                 : Item(status='  ', wc_rev='2'),
+      'A/D'               : Item(status='  ', wc_rev='2'),
+      'A/D/H'             : Item(status='  ', wc_rev='2'),
+      'A/D/H/omega'       : Item(status='  ', wc_rev='2'),
+      'A/D/H/psi'         : Item(status='  ', wc_rev='2'),
+      'A/D/H/chi'         : Item(status='  ', wc_rev='2'),
+      'A/D/gamma'         : Item(status='  ', wc_rev='2'),
+      'A/D/G'             : Item(status='  ', wc_rev='2'),
+      'A/B'               : Item(status='  ', wc_rev='2'),
+      'A/B/F'             : Item(status='  ', wc_rev='2'),
+      'A/B/E'             : Item(status='  ', wc_rev='2'),
+      'A/B/E/beta'        : Item(status='  ', wc_rev='2'),
+      'A/B/E/alpha'       : Item(status='  ', wc_rev='2'),
+      'A/B/lambda'        : Item(status='  ', wc_rev='2'),
+      'iota'              : Item(status='  ', wc_rev='2'),
+    })
+  run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+
+  simple_property_verify(sbox.wc_dir, {
+      'A/B/E/beta'        : {'svn:eol-style': 'native'},
+#      'A/B/lambda'        : {'svn:eol-style': 'native'},
+      'A/B/E/alpha'       : {'svn:eol-style': 'native'}
+  })
+
+def x3_1_4_0(sbox):
+  "3x same wc upgrade 1.4.0 test"
+
+  sbox.build(create_wc = False)
+  replace_sbox_with_tarfile(sbox, 'wc-3x-1.4.0.tar.bz2', dir='wc-1.4.0')
+
+  do_x3_upgrade(sbox)
+
+def x3_1_4_6(sbox):
+  "3x same wc upgrade 1.4.6 test"
+
+  sbox.build(create_wc = False)
+  replace_sbox_with_tarfile(sbox, 'wc-3x-1.4.6.tar.bz2', dir='wc-1.4.6')
+
+  do_x3_upgrade(sbox)
+
+def x3_1_6_12(sbox):
+  "3x same wc upgrade 1.6.12 test"
+
+  sbox.build(create_wc = False)
+  replace_sbox_with_tarfile(sbox, 'wc-3x-1.6.12.tar.bz2', dir='wc-1.6.12')
+
+  do_x3_upgrade(sbox)
+
+def missing_dirs(sbox):
+  "missing directories and obstructing files"
+
+  # tarball wc looks like:
+  #   svn co URL wc
+  #   svn cp wc/A/B wc/A/B_new
+  #   rm -rf wc/A/B/E wc/A/D wc/A/B_new/E wc/A/B_new/F
+  #   touch wc/A/D wc/A/B_new/F
+
+  sbox.build(create_wc = False)
+  replace_sbox_with_tarfile(sbox, 'missing-dirs.tar.bz2')
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'upgrade', sbox.wc_dir)
+  expected_status = svntest.wc.State(sbox.wc_dir,
+    {
+      ''                  : Item(status='  ', wc_rev='1'),
+      'A'                 : Item(status='  ', wc_rev='1'),
+      'A/mu'              : Item(status='  ', wc_rev='1'),
+      'A/C'               : Item(status='  ', wc_rev='1'),
+      'A/D'               : Item(status='~ ', wc_rev='?'),
+      'A/B'               : Item(status='  ', wc_rev='1'),
+      'A/B/F'             : Item(status='  ', wc_rev='1'),
+      'A/B/E'             : Item(status='! ', wc_rev='?'),
+      'A/B/lambda'        : Item(status='  ', wc_rev='1'),
+      'iota'              : Item(status='  ', wc_rev='1'),
+      'A/B_new'           : Item(status='A ', wc_rev='-', copied='+'),
+      'A/B_new/E'         : Item(status='! ', wc_rev='?'),
+      'A/B_new/F'         : Item(status='~ ', wc_rev='?'),
+      'A/B_new/lambda'    : Item(status='  ', wc_rev='-', copied='+'),
+    })
+  if svntest.main.wc_is_singledb(sbox.wc_dir):
+    expected_status.tweak('A/D', 'A/B_new/F', status='! ')
+  run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+  
+def missing_dirs2(sbox):
+  "missing directories and obstructing dirs"
+
+  sbox.build(create_wc = False)
+  replace_sbox_with_tarfile(sbox, 'missing-dirs.tar.bz2')
+  os.remove(sbox.ospath('A/D'))
+  os.remove(sbox.ospath('A/B_new/F'))
+  os.mkdir(sbox.ospath('A/D'))
+  os.mkdir(sbox.ospath('A/B_new/F'))
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'upgrade', sbox.wc_dir)
+  expected_status = svntest.wc.State(sbox.wc_dir,
+    {
+      ''                  : Item(status='  ', wc_rev='1'),
+      'A'                 : Item(status='  ', wc_rev='1'),
+      'A/mu'              : Item(status='  ', wc_rev='1'),
+      'A/C'               : Item(status='  ', wc_rev='1'),
+      'A/D'               : Item(status='~ ', wc_rev='?'),
+      'A/B'               : Item(status='  ', wc_rev='1'),
+      'A/B/F'             : Item(status='  ', wc_rev='1'),
+      'A/B/E'             : Item(status='! ', wc_rev='?'),
+      'A/B/lambda'        : Item(status='  ', wc_rev='1'),
+      'iota'              : Item(status='  ', wc_rev='1'),
+      'A/B_new'           : Item(status='A ', wc_rev='-', copied='+'),
+      'A/B_new/E'         : Item(status='! ', wc_rev='?'),
+      'A/B_new/F'         : Item(status='~ ', wc_rev='?'),
+      'A/B_new/lambda'    : Item(status='  ', wc_rev='-', copied='+'),
+    })
+  if svntest.main.wc_is_singledb(sbox.wc_dir):
+    expected_status.tweak('A/D', 'A/B_new/F', status='! ')
+  run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+
+def delete_and_keep_local(sbox):
+  "check status delete and delete --keep-local"
+
+  sbox.build(create_wc = False)
+  replace_sbox_with_tarfile(sbox, 'wc-delete.tar.bz2')
+
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'upgrade', sbox.wc_dir)
+
+  expected_status = svntest.wc.State(sbox.wc_dir,
+    {
+      ''                  : Item(status='  ', wc_rev='0'),
+      'Normal'            : Item(status='  ', wc_rev='1'),
+      'Deleted-Keep-Local': Item(status='D ', wc_rev='1'),
+      'Deleted'           : Item(status='D ', wc_rev='1'),
+  })
+
+  run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+
+  # Deleted-Keep-Local should still exist after the upgrade
+  if not os.path.exists(os.path.join(sbox.wc_dir, 'Deleted-Keep-Local')):
+    raise svntest.Failure('wc/Deleted-Keep-Local should exist')
+
+  # Deleted-Keep-Local should be removed after the upgrade as it was
+  # schedule delete and doesn't contain unversioned changes.
+  if os.path.exists(os.path.join(sbox.wc_dir, 'Deleted')):
+    raise svntest.Failure('wc/Deleted should not exist')
+
+
+
 ########################################################################
 # Run the tests
 
@@ -352,7 +656,15 @@ test_list = [ None,
               update_1_5,
               logs_left_1_5,
               upgrade_wcprops,
-              basic_upgrade_1_0
+              basic_upgrade_1_0,
+              # Upgrading from 1.4.0-1.4.5 with specific states fails
+              # See issue #2530
+              XFail(x3_1_4_0),
+              x3_1_4_6,
+              x3_1_6_12,
+              missing_dirs,
+              missing_dirs2,
+              XFail(delete_and_keep_local),
              ]
 
 

Propchange: subversion/branches/py-tests-as-modules/subversion/tests/libsvn_client/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Wed Sep 15 19:32:26 2010
@@ -2,3 +2,4 @@
 client-test
 *.lo
 test-patch*
+test-wc*