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 2013/02/23 02:25:44 UTC

svn commit: r1449262 [19/25] - in /subversion/branches/ev2-export: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ build/win32/ contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ notes/ note...

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/entries-dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/entries-dump.c?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/entries-dump.c (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/entries-dump.c Sat Feb 23 01:25:38 2013
@@ -38,6 +38,7 @@
 #include "private/svn_wc_private.h"
 
 #include "../../libsvn_wc/wc.h"
+#include "../../libsvn_wc/lock.h"
 
 static void
 str_value(const char *name, const char *value)
@@ -66,21 +67,30 @@ bool_value(const char *name, svn_boolean
 }
 
 static svn_error_t *
-entries_dump(const char *dir_path, apr_pool_t *pool)
+entries_dump(const char *dir_path, svn_wc_adm_access_t *related, apr_pool_t *pool)
 {
-  svn_wc_adm_access_t *adm_access;
+  svn_wc_adm_access_t *adm_access = NULL;
   apr_hash_t *entries;
   apr_hash_index_t *hi;
   svn_boolean_t locked;
   svn_error_t *err;
 
-  err = svn_wc_adm_open3(&adm_access, NULL, dir_path, FALSE, 0,
+  err = svn_wc_adm_open3(&adm_access, related, dir_path, FALSE, 0,
                          NULL, NULL, pool);
   if (!err)
     {
       SVN_ERR(svn_wc_locked(&locked, dir_path, pool));
       SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool));
     }
+  else if (err && err->apr_err == SVN_ERR_WC_LOCKED
+           && related
+           && ! strcmp(dir_path, svn_wc_adm_access_path(related)))
+    {
+      /* Common caller error: Can't open a baton when there is one. */
+      svn_error_clear(err);
+      SVN_ERR(svn_wc_locked(&locked, dir_path, pool));
+      SVN_ERR(svn_wc_entries_read(&entries, related, TRUE, pool));
+    }
   else
     {
       const char *dir_abspath, *lockfile_path;
@@ -102,12 +112,8 @@ entries_dump(const char *dir_path, apr_p
 
   for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
     {
-      const void *key;
-      void *value;
-      const svn_wc_entry_t *entry;
-
-      apr_hash_this(hi, &key, NULL, &value);
-      entry = value;
+      const char *key = svn__apr_hash_index_key(hi);
+      const svn_wc_entry_t *entry = svn__apr_hash_index_val(hi);
 
       SVN_ERR_ASSERT(strcmp(key, entry->name) == 0);
 
@@ -168,6 +174,7 @@ struct directory_walk_baton
   svn_wc_context_t *wc_ctx;
   const char *root_abspath;
   const char *prefix_path;
+  svn_wc_adm_access_t *adm_access;
 };
 
 /* svn_wc__node_found_func_t implementation for directory_dump */
@@ -252,6 +259,81 @@ directory_dump(const char *path,
   return svn_error_trace(svn_wc_context_destroy(bt.wc_ctx));
 }
 
+static svn_error_t *
+tree_dump_dir(const char *local_abspath,
+              svn_node_kind_t kind,
+              void *walk_baton,
+              apr_pool_t *scratch_pool)
+{
+  struct directory_walk_baton *bt = walk_baton;
+  const char *path;
+
+  if (kind != svn_node_dir)
+    return SVN_NO_ERROR;
+
+  /* If LOCAL_ABSPATH a child of or equal to ROOT_ABSPATH, then display
+     a relative path starting with PREFIX_PATH. */
+  path = svn_dirent_skip_ancestor(bt->root_abspath, local_abspath);
+  if (path)
+    path = svn_dirent_join(bt->prefix_path, path, scratch_pool);
+  else
+    path = local_abspath;
+
+  printf("entries = {}\n");
+  SVN_ERR(entries_dump(path, bt->adm_access, scratch_pool));
+
+  printf("dirs['%s'] = entries\n", path);
+  return SVN_NO_ERROR;
+
+}
+
+static svn_error_t *
+tree_dump_txn(void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool)
+{
+  struct directory_walk_baton *bt = baton;
+
+  SVN_ERR(svn_wc__internal_walk_children(bt->wc_ctx->db, bt->root_abspath, FALSE,
+                                         NULL, tree_dump_dir, bt,
+                                         svn_depth_infinity,
+                                         NULL, NULL, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+tree_dump(const char *path,
+          apr_pool_t *scratch_pool)
+{
+  struct directory_walk_baton bt;
+  svn_sqlite__db_t *sdb;
+  svn_wc__db_t *db;
+
+  bt.prefix_path = path;
+
+  /* Obtain an access baton to allow re-using the same wc_db for all access */
+  SVN_ERR(svn_wc_adm_open3(&bt.adm_access, NULL, path, FALSE, 0, NULL, NULL,
+                           scratch_pool));
+
+  db = svn_wc__adm_get_db(bt.adm_access);
+
+  SVN_ERR(svn_wc__context_create_with_db(&bt.wc_ctx, NULL, db, scratch_pool));
+
+  SVN_ERR(svn_dirent_get_absolute(&bt.root_abspath, path, scratch_pool));
+
+  /* And now get us a transaction on the database to avoid obtaining and
+     releasing locks all the time */
+  SVN_ERR(svn_wc__db_temp_borrow_sdb(&sdb, bt.wc_ctx->db, bt.root_abspath,
+                                     scratch_pool));
+
+  SVN_ERR(svn_sqlite__with_lock(sdb, tree_dump_txn, &bt, scratch_pool));
+
+  /* And close everything we've opened */
+  SVN_ERR(svn_wc_context_destroy(bt.wc_ctx));
+  SVN_ERR(svn_wc_adm_close2(bt.adm_access, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 int
 main(int argc, const char *argv[])
 {
@@ -263,7 +345,7 @@ main(int argc, const char *argv[])
 
   if (argc < 2 || argc > 4)
     {
-      fprintf(stderr, "USAGE: entries-dump [--entries|--subdirs] DIR_PATH\n");
+      fprintf(stderr, "USAGE: entries-dump [--entries|--subdirs|--tree-dump] DIR_PATH\n");
       exit(1);
     }
 
@@ -285,9 +367,11 @@ main(int argc, const char *argv[])
     cmd = NULL;
 
   if (!cmd || !strcmp(cmd, "--entries"))
-    err = entries_dump(path, pool);
+    err = entries_dump(path, NULL, pool);
   else if (!strcmp(cmd, "--subdirs"))
     err = directory_dump(path, pool);
+  else if (!strcmp(cmd, "--tree-dump"))
+    err = tree_dump(path, pool);
   else
     err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
                             "Invalid command '%s'",

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/externals_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/externals_tests.py Sat Feb 23 01:25:38 2013
@@ -2972,13 +2972,14 @@ def url_to_wc_copy_of_externals(sbox):
   external_tau_path = os.path.join(wc_dir, "External-WC-to-URL-Copy",
                                    "external", "tau")
   expected_stdout = verify.UnorderedOutput([
-    "\n",
     " U   " + external_root_path + "\n",
+    "\n",
     "Fetching external item into '" + external_ex_path + "':\n",
     "A    " + external_pi_path + "\n",
     "A    " + external_rho_path + "\n",
     "A    " + external_tau_path + "\n",
     "Checked out external at revision 2.\n",
+    "\n",
     "Checked out revision 2.\n",
     "A         " + external_root_path + "\n"
   ])
@@ -3131,9 +3132,9 @@ def pinned_externals(sbox):
 
   repo_X_mu = repo_url + '/X/mu'
 
-  expected_output = verify.RegexOutput([
+  expected_output = verify.RegexOutput(
     '^      1 jrandom            .* mu$'
-  ])
+  )
 
   svntest.actions.run_and_verify_svn(None, expected_output, [],
                                      'list', repo_X_mu, '-v')
@@ -3187,6 +3188,44 @@ def pinned_externals(sbox):
 
   svntest.actions.verify_disk(wc_dir, expected_disk)
 
+# Test for issue #3741 'externals not removed when working copy is made shallow'
+@Issue(3741)
+def update_dir_external_shallow(sbox):
+  "shallow update should remove externals"
+
+  sbox.build()
+
+  # Create an external in r2
+  sbox.simple_propset('svn:externals', '^/A/D/H X', 'A/B/E')
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  # Now make A/B/E shallow by updating with "--set-depth empty"
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A/B/E/alpha' : Item(status='D '),
+    'A/B/E/X'     : Item(verb='Removed external'),
+    'A/B/E/beta'  : Item(status='D '),
+  })
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output, None, None,
+                                        None, None, None, None, None, False,
+                                        '--set-depth=empty',
+                                        sbox.ospath('A/B/E'))
+
+  # And bring the external back by updating with "--set-depth infinity"
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    'A/B/E/X/psi'   : Item(status='A '),
+    'A/B/E/X/chi'   : Item(status='A '),
+    'A/B/E/X/omega' : Item(status='A '),
+    'A/B/E/alpha'   : Item(status='A '),
+    'A/B/E/beta'    : Item(status='A '),
+  })
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output, None, None,
+                                        None, None, None, None, None, False,
+                                        '--set-depth=infinity',
+                                        sbox.ospath('A/B/E'))
+
 
 ########################################################################
 # Run the tests
@@ -3239,6 +3278,7 @@ test_list = [ None,
               list_include_externals,
               move_with_file_externals,
               pinned_externals,
+              update_dir_external_shallow,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/info_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/info_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/info_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/info_tests.py Sat Feb 23 01:25:38 2013
@@ -34,6 +34,8 @@ logger = logging.getLogger()
 # Our testing module
 import svntest
 
+from prop_tests import binary_mime_type_on_text_file_warning
+
 # (abbreviation)
 Skip = svntest.testcase.Skip_deco
 SkipUnless = svntest.testcase.SkipUnless_deco
@@ -494,7 +496,9 @@ def binary_tree_conflict(sbox):
   sbox.build()
   wc_dir = sbox.wc_dir
 
-  sbox.simple_propset('svn:mime-type', 'binary/octet-stream', 'iota')
+  svntest.main.run_svn(binary_mime_type_on_text_file_warning,
+                       'propset', 'svn:mime-type', 'binary/octet-stream',
+                       sbox.ospath('iota'))
   sbox.simple_commit()
 
   iota = sbox.ospath('iota')

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/input_validation_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/input_validation_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/input_validation_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/input_validation_tests.py Sat Feb 23 01:25:38 2013
@@ -111,15 +111,15 @@ def invalid_delete_targets(sbox):
   "invalid targets for 'delete'"
   sbox.build(read_only=True)
   for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
-    run_and_verify_svn_in_wc(sbox, "svn: E205000: Cannot mix repository and working "
+    run_and_verify_svn_in_wc(sbox, "svn: E200009: Cannot mix repository and working "
                              "copy targets", 'delete', target1, target2)
 
 def invalid_diff_targets(sbox):
   "invalid targets for 'diff'"
   sbox.build(read_only=True)
-  for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
-    run_and_verify_svn_in_wc(sbox, "svn: E205000: Cannot mix repository and working "
-                             "copy targets", 'diff', target1, target2)
+  for (target1, target2, target3) in [("iota", "^/", "A/mu"), ("file://", "iota", "A/mu")]:
+    run_and_verify_svn_in_wc(sbox, "svn: E200009: Cannot mix repository and working "
+                             "copy targets", 'diff', target1, target2, target3)
 
 def invalid_export_targets(sbox):
   "invalid targets for 'export'"
@@ -202,14 +202,14 @@ def invalid_lock_targets(sbox):
   "wc paths and repo URL target mixture for 'lock'"
   sbox.build(read_only=True)
   for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
-    run_and_verify_svn_in_wc(sbox, "svn: E205000: Cannot mix repository and working "
+    run_and_verify_svn_in_wc(sbox, "svn: E200009: Cannot mix repository and working "
                              "copy targets", 'lock', target1, target2)
 
 def invalid_unlock_targets(sbox):
   "wc paths and repo URL target mixture for 'unlock'"
   sbox.build(read_only=True)
   for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
-    run_and_verify_svn_in_wc(sbox, "svn: E205000: Cannot mix repository and working "
+    run_and_verify_svn_in_wc(sbox, "svn: E200009: Cannot mix repository and working "
                              "copy targets", 'unlock', target1, target2)
 
 def invalid_status_targets(sbox):
@@ -243,7 +243,7 @@ def invalid_relocate_targets(sbox):
 def invalid_mkdir_targets(sbox):
   "invalid targets for 'mkdir'"
   sbox.build(read_only=True)
-  run_and_verify_svn_in_wc(sbox, "svn: E205000: Cannot mix repository and working "
+  run_and_verify_svn_in_wc(sbox, "svn: E200009: Cannot mix repository and working "
                            "copy targets", 'mkdir', "folder", "^/folder")
 
 def invalid_update_targets(sbox):
@@ -252,6 +252,47 @@ def invalid_update_targets(sbox):
   run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'update',
                            "^/")
 
+def delete_repos_root(sbox):
+  "do stupid things with the repository root"
+
+  sbox.build(read_only=True)
+  wc_dir = sbox.wc_dir
+  repo_url = sbox.repo_url
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+
+  expected_status.tweak('A/D/G', switched='S')
+  expected_status.remove('A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
+  svntest.actions.run_and_verify_switch(sbox.wc_dir, sbox.ospath('A/D/G'),
+                                        repo_url,
+                                        None, None, expected_status,
+                                        None, None, None, None, None, None,
+                                        '--set-depth', 'empty', '--ignore-ancestry')
+
+  expected_status.tweak('A/B/F', switched='S')
+  svntest.actions.run_and_verify_switch(sbox.wc_dir, sbox.ospath('A/B/F'),
+                                        repo_url,
+                                        None, None, expected_status,
+                                        None, None, None, None, None, None,
+                                        '--depth', 'empty', '--ignore-ancestry')
+
+  # Delete the wcroot (which happens to be the repository root)
+  expected_error = 'svn: E155035: \'.*\' is the root of a working copy ' + \
+                   'and cannot be deleted'
+  svntest.actions.run_and_verify_svn('Delete root', [], expected_error,
+                                     'rm', wc_dir)
+
+  # This should produce some error, because we can never commit this
+  expected_error = '.*repository root.*'
+  svntest.actions.run_and_verify_svn('Move root', None, expected_error,
+                                     'mv', sbox.ospath('A/D/G'),
+                                     sbox.ospath('Z'))
+
+  # And this currently fails with another nasty error about a wc-lock
+  expected_error = '.*repository root.*'
+  svntest.actions.run_and_verify_svn('Delete root', [], expected_error,
+                                     'rm', sbox.ospath('A/B/F'))
+
 ########################################################################
 # Run the tests
 
@@ -281,6 +322,7 @@ test_list = [ None,
               invalid_relocate_targets,
               invalid_mkdir_targets,
               invalid_update_targets,
+              delete_repos_root,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/lock_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/lock_tests.py Sat Feb 23 01:25:38 2013
@@ -1787,7 +1787,30 @@ def locks_stick_over_switch(sbox):
                                         repo_url + '/A',
                                         expected_output, None, expected_status)
 
-
+@Issue(4304)
+def lock_unlock_deleted(sbox):
+  "lock/unlock a deleted file"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'rm', sbox.ospath('A/mu'))
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status='D ')
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  expected_output = '\'mu\' locked by user \'jrandom\'.'
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+                                     'lock', sbox.ospath('A/mu'))
+  expected_status.tweak('A/mu', writelocked='K')
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  expected_output = '\'mu\' unlocked.'
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+                                     'unlock', sbox.ospath('A/mu'))
+  expected_status.tweak('A/mu', writelocked=None)
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 ########################################################################
 # Run the tests
@@ -1839,6 +1862,7 @@ test_list = [ None,
               lock_invalid_token,
               lock_multi_wc,
               locks_stick_over_switch,
+              lock_unlock_deleted,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/merge_authz_tests.py Sat Feb 23 01:25:38 2013
@@ -122,7 +122,7 @@ def mergeinfo_and_skipped_paths(sbox):
   A_COPY_2_H_path = os.path.join(wc_restricted, "A_COPY_2", "D", "H")
   A_COPY_3_path = os.path.join(wc_restricted, "A_COPY_3")
   omega_path = os.path.join(wc_restricted, "A_COPY", "D", "H", "omega")
-  zeta_path = os.path.join(wc_dir, "A", "D", "H", "zeta")
+  zeta_path = sbox.ospath("A/D/H/zeta")
 
   # Merge r4:8 into the restricted WC's A_COPY.
   #
@@ -212,6 +212,8 @@ def mergeinfo_and_skipped_paths(sbox):
   # always takes precedence in terms of getting *non*-inheritable mergeinfo.
   expected_output = wc.State(A_COPY_2_path, {
     'D/H/omega' : Item(status='U '),
+    # Below the skip
+    'D/G/rho'   : Item(status='  ', treeconflict='U'),
     })
   expected_mergeinfo_output = wc.State(A_COPY_2_path, {
     ''          : Item(status=' U'),
@@ -257,7 +259,7 @@ def mergeinfo_and_skipped_paths(sbox):
     })
   expected_skip = wc.State(A_COPY_2_path, {
     'B/E'     : Item(verb='Skipped missing target'),
-    'D/G/rho' : Item(verb='Skipped'),
+    'D/G'     : Item(verb='Skipped missing target'),
     'D/H/psi' : Item(verb='Skipped missing target'),
     })
   svntest.actions.run_and_verify_merge(A_COPY_2_path, '4', '8',
@@ -501,10 +503,10 @@ def merge_fails_if_subtree_is_deleted_on
                              svntest.main.wc_author2 + " = rw")})
 
   # Some paths we'll care about
-  Acopy_path = os.path.join(wc_dir, 'A_copy')
-  gamma_path = os.path.join(wc_dir, 'A', 'D', 'gamma')
-  Acopy_gamma_path = os.path.join(wc_dir, 'A_copy', 'D', 'gamma')
-  Acopy_D_path = os.path.join(wc_dir, 'A_copy', 'D')
+  Acopy_path = sbox.ospath('A_copy')
+  gamma_path = sbox.ospath('A/D/gamma')
+  Acopy_gamma_path = sbox.ospath('A_copy/D/gamma')
+  Acopy_D_path = sbox.ospath('A_copy/D')
   A_url = sbox.repo_url + '/A'
   Acopy_url = sbox.repo_url + '/A_copy'
 
@@ -622,12 +624,12 @@ def reintegrate_fails_if_no_root_access(
 
   # Some paths we'll care about
   wc_dir = sbox.wc_dir
-  A_path          = os.path.join(wc_dir, 'A')
-  A_COPY_path     = os.path.join(wc_dir, 'A_COPY')
-  beta_COPY_path  = os.path.join(wc_dir, 'A_COPY', 'B', 'E', 'beta')
-  rho_COPY_path   = os.path.join(wc_dir, 'A_COPY', 'D', 'G', 'rho')
-  omega_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D', 'H', 'omega')
-  psi_COPY_path   = os.path.join(wc_dir, 'A_COPY', 'D', 'H', 'psi')
+  A_path          = sbox.ospath('A')
+  A_COPY_path     = sbox.ospath('A_COPY')
+  beta_COPY_path  = sbox.ospath('A_COPY/B/E/beta')
+  rho_COPY_path   = sbox.ospath('A_COPY/D/G/rho')
+  omega_COPY_path = sbox.ospath('A_COPY/D/H/omega')
+  psi_COPY_path   = sbox.ospath('A_COPY/D/H/psi')
 
   # Copy A@1 to A_COPY in r2, and then make some changes to A in r3-6.
   sbox.build()
@@ -635,7 +637,7 @@ def reintegrate_fails_if_no_root_access(
   expected_disk, expected_status = set_up_branch(sbox)
 
   # Make a change on the branch, to A_COPY/mu, commit in r7.
-  svntest.main.file_write(os.path.join(wc_dir, "A_COPY", "mu"),
+  svntest.main.file_write(sbox.ospath("A_COPY/mu"),
                           "Changed on the branch.")
   expected_output = wc.State(wc_dir, {'A_COPY/mu' : Item(verb='Sending')})
   expected_status.tweak('A_COPY/mu', wc_rev=7)
@@ -735,6 +737,133 @@ def reintegrate_fails_if_no_root_access(
                                        None, True, True,
                                        '--reintegrate', A_path)
 
+#----------------------------------------------------------------------
+# Test for issue #4319 'faulty merge notifications when target subtree
+# unreadable'.
+@SkipUnless(svntest.main.server_has_mergeinfo)
+@Skip(svntest.main.is_ra_type_file)
+@Issue(4319)
+@XFail()
+def merge_notifications_and_authz_skips(sbox):
+  "merge notifications when target subtree unreadable"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  deep_source_tree = sbox.ospath('A/C/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z')
+  deep_source_file = sbox.ospath('A/C/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/nu')
+  branch_root = sbox.ospath('branch')
+
+  # r2 - branch ^/A to ^/branch
+  sbox.simple_copy('A', 'branch')
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  # r3 - Add a deep subtree
+  svntest.actions.run_and_verify_svn(None, None, [], 'mkdir',
+                                     deep_source_tree, '--parents')
+  svntest.main.file_write(deep_source_file, "This is the file 'nu'.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'add', deep_source_file)
+  sbox.simple_commit()
+
+  # 
+  # Create a restrictive authz where part of the merge source and part
+  # of the target are inaccesible.
+  sbox.simple_update(revision=0)
+  write_restrictive_svnserve_conf(sbox.repo_dir)
+  write_authz_file(sbox, {"/" : svntest.main.wc_author +"=rw",
+                          # Make a subtree in the merge target inaccessible.
+                          "/branch/C" : svntest.main.wc_author + "=",
+                          })
+  sbox.simple_update()
+
+  expected_output = wc.State(branch_root, {
+    })
+  expected_mergeinfo_output = wc.State(branch_root, {
+    ''  : Item(status=' U'),
+    })
+  expected_elision_output = wc.State(branch_root, {
+    })
+  expected_status = wc.State(branch_root, {
+    ''          : Item(status=' M', wc_rev=3),
+    'D/H/chi'   : Item(status='  ', wc_rev=3),
+    'D/H/omega' : Item(status='  ', wc_rev=3),
+    'D/H/psi'   : Item(status='  ', wc_rev=3),
+    'D/H'       : Item(status='  ', wc_rev=3),
+    'D/gamma'   : Item(status='  ', wc_rev=3),
+    'D'         : Item(status='  ', wc_rev=3),
+    'D/G'       : Item(status='  ', wc_rev=3),
+    'D/G/pi'    : Item(status='  ', wc_rev=3),
+    'D/G/rho'   : Item(status='  ', wc_rev=3),
+    'D/G/tau'   : Item(status='  ', wc_rev=3),
+    'B/lambda'  : Item(status='  ', wc_rev=3),
+    'B/E'       : Item(status='  ', wc_rev=3),
+    'B/E/alpha' : Item(status='  ', wc_rev=3),
+    'B/E/beta'  : Item(status='  ', wc_rev=3),
+    'B/F'       : Item(status='  ', wc_rev=3),
+    'B'         : Item(status='  ', wc_rev=3),
+    'mu'        : Item(status='  ', wc_rev=3),
+    })
+  expected_disk = wc.State('', {
+    ''          : Item(props={SVN_PROP_MERGEINFO : '/A:2-3*'}),
+    'D/H/omega' : Item("This is the file 'omega'.\n"),
+    'D/H/chi'   : Item("This is the file 'chi'.\n"),
+    'D/H/psi'   : Item("This is the file 'psi'.\n"),
+    'D/H'       : Item(),
+    'D/gamma'   : Item("This is the file 'gamma'.\n"),
+    'D'         : Item(),
+    'D/G'       : Item(),
+    'D/G/pi'    : Item("This is the file 'pi'.\n"),
+    'D/G/rho'   : Item("This is the file 'rho'.\n"),
+    'D/G/tau'   : Item("This is the file 'tau'.\n"),
+    'B/lambda'  : Item("This is the file 'lambda'.\n"),
+    'B/E'       : Item(),
+    'B/E/alpha' : Item("This is the file 'alpha'.\n"),
+    'B/E/beta'  : Item("This is the file 'beta'.\n"),
+    'B/F'       : Item(),
+    'B'         : Item(),
+    'mu'        : Item("This is the file 'mu'.\n"),
+    })
+  expected_skip = wc.State(branch_root,
+                           {'C' : Item(verb='Skipped missing target')})
+  # This fails because notifications for all the added subtrees under
+  # branch/C occur:
+  #
+  #   >svn merge ^^/A branch -r1:3
+  #   Skipped missing target: 'branch\C'
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z\nu
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T\U\V\W
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T\U\V
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T\U
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S\T
+  #      A branch\C\J\K\L\M\N\O\P\Q\R\S
+  #      A branch\C\J\K\L\M\N\O\P\Q\R
+  #      A branch\C\J\K\L\M\N\O\P\Q
+  #      A branch\C\J\K\L\M\N\O\P
+  #      A branch\C\J\K\L\M\N\O
+  #      A branch\C\J\K\L\M\N
+  #      A branch\C\J\K\L\M
+  #      A branch\C\J\K\L
+  #      A branch\C\J\K
+  #      A branch\C\J
+  #   --- Recording mergeinfo for merge of r2 through r3 into 'branch':
+  #    U   branch
+  #   Summary of conflicts:
+  #     Skipped paths: 1
+  svntest.actions.run_and_verify_merge(branch_root, 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)
+
 ########################################################################
 # Run the tests
 
@@ -744,6 +873,7 @@ test_list = [ None,
               mergeinfo_and_skipped_paths,
               merge_fails_if_subtree_is_deleted_on_src,
               reintegrate_fails_if_no_root_access,
+              merge_notifications_and_authz_skips,
              ]
 serial_only = True
 

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/merge_automatic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/merge_automatic_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/merge_automatic_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/merge_automatic_tests.py Sat Feb 23 01:25:38 2013
@@ -984,6 +984,147 @@ def merge_to_reverse_cherry_subtree_to_m
                                        None, None, None, None,
                                        None, 1, 0, A_COPY_path)
 
+#----------------------------------------------------------------------
+# Automatic merges should notice ancestory for replaced files
+@SkipUnless(server_has_mergeinfo)
+def merge_replacement(sbox):
+  "notice ancestory for replaced files"
+
+  A_path = sbox.ospath('A')
+  A_COPY_path = sbox.ospath('A_copy')
+  A_COPY_mu_path = sbox.ospath('A_copy/mu')
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  sbox.simple_copy('A', 'A_copy')
+  # Commit as r2
+  sbox.simple_commit()
+
+  sbox.simple_rm('A_copy/B/lambda')
+  sbox.simple_copy('A_copy/D/gamma', 'A_copy/B/lambda')
+
+  sbox.simple_rm('A_copy/mu')
+  svntest.main.file_write(A_COPY_mu_path, "Branch edit to 'mu'.\n")
+  sbox.simple_add('A_copy/mu')
+
+  # Commit as r3
+  sbox.simple_commit()
+
+  expected_output = wc.State(A_path, {
+    'B/lambda'   : Item(status='R '),
+    'mu'         : Item(status='R '),
+    })
+  expected_mergeinfo_output = wc.State(A_path, {
+    ''  : Item(status=' U'),
+    })
+  expected_elision_output = wc.State(A_path, {
+    })
+
+  expected_status = wc.State(A_path, {
+    ''           : Item(status=' M', wc_rev='1'),
+    'B'          : Item(status='  ', wc_rev='1'),
+    'mu'         : Item(status='R ', copied='+', wc_rev='-'),
+    'B/E'        : Item(status='  ', wc_rev='1'),
+    'B/E/alpha'  : Item(status='  ', wc_rev='1'),
+    'B/E/beta'   : Item(status='  ', wc_rev='1'),
+    'B/lambda'   : Item(status='R ', copied='+', wc_rev='-'),
+    'B/F'        : Item(status='  ', wc_rev='1'),
+    'C'          : Item(status='  ', wc_rev='1'),
+    'D'          : Item(status='  ', wc_rev='1'),
+    'D/G'        : Item(status='  ', wc_rev='1'),
+    'D/G/pi'     : Item(status='  ', wc_rev='1'),
+    'D/G/rho'    : Item(status='  ', wc_rev='1'),
+    'D/G/tau'    : Item(status='  ', wc_rev='1'),
+    'D/gamma'    : Item(status='  ', wc_rev='1'),
+    'D/H'        : Item(status='  ', wc_rev='1'),
+    'D/H/chi'    : Item(status='  ', wc_rev='1'),
+    'D/H/psi'    : Item(status='  ', wc_rev='1'),
+    'D/H/omega'  : Item(status='  ', wc_rev='1'),
+    })
+
+  expected_disk = wc.State('', {
+    ''           : Item(props={SVN_PROP_MERGEINFO : '/A_copy:2-3'}),
+    'B'          : Item(),
+    'mu'         : Item("Branch edit to 'mu'.\n"),
+    'B/E'        : Item(),
+    'B/E/alpha'  : Item("This is the file 'alpha'.\n"),
+    'B/E/beta'   : Item("This is the file 'beta'.\n"),
+    'B/lambda'   : Item("This is the file 'gamma'.\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("This is the file 'rho'.\n"),
+    '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("This is the file 'psi'.\n"),
+    'D/H/omega'  : Item("This is the file 'omega'.\n"),
+    })
+
+  expected_skip = wc.State(A_COPY_path, { })
+
+  svntest.actions.run_and_verify_merge(A_path, None, None,
+                                       sbox.repo_url + '/A_copy', None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, None, None, None,
+                                       None, 1, 0, A_path)
+
+@SkipUnless(server_has_mergeinfo)
+@Issue(4313)
+
+# Test for issue #4313 'replaced merges source causes assertion during
+# automatic merge'
+def auto_merge_handles_replacements_in_merge_source(sbox):
+  "automerge handles replacements in merge source"
+
+  sbox.build()
+
+  A_path = sbox.ospath('A')
+  branch1_path = sbox.ospath('branch-1')
+  branch2_path = sbox.ospath('branch-2')
+
+  # r2 - Make two branches.
+  sbox.simple_copy('A', 'branch-1')
+  sbox.simple_copy('A', 'branch-2')
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  # r3 - Replace 'A' with 'branch-1'.
+  svntest.main.run_svn(None, 'del', A_path)
+  svntest.main.run_svn(None, 'copy', branch1_path, A_path)
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  # Merge^/A to branch-2, it should be a no-op but for mergeinfo changes,
+  # but it *should* work.  Previously this failed because automatic merges
+  # weren't adhering to the merge source normalization rules, resulting in
+  # this assertion:
+  #
+  #   >svn merge ^/A branch-2
+  #   ..\..\..\subversion\libsvn_client\merge.c:4568: (apr_err=235000)
+  #   svn: E235000: In file '..\..\..\subversion\libsvn_client\merge.c'
+  #     line 4568: assertion failed (apr_hash_count(implicit_src_mergeinfo)
+  #     == 1)
+  #
+  #   This application has requested the Runtime to terminate it in an
+  #   unusual way.
+  #   Please contact the application's support team for more information.
+  svntest.actions.run_and_verify_svn(
+    None,
+    ["--- Recording mergeinfo for merge of r2 into '" + branch2_path + "':\n",
+     " U   " + branch2_path + "\n",
+     "--- Recording mergeinfo for merge of r3 into '" + branch2_path + "':\n",
+     " G   " + branch2_path + "\n"],
+    [], 'merge', sbox.repo_url + '/A', branch2_path)
+
 ########################################################################
 # Run the tests
 
@@ -1009,6 +1150,8 @@ test_list = [ None,
               cherry3_fwd,
               subtree_to_and_fro,
               merge_to_reverse_cherry_subtree_to_merge_to,
+              merge_replacement,
+              auto_merge_handles_replacements_in_merge_source,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/merge_reintegrate_tests.py Sat Feb 23 01:25:38 2013
@@ -48,6 +48,62 @@ from merge_tests import set_up_branch
 from merge_tests import expected_merge_output
 
 #----------------------------------------------------------------------
+def run_reintegrate(src_url, tgt_path):
+  """Run 'svn merge --reintegrate SRC_URL TGT_PATH'. Raise an error if
+     there is nothing on stdout, anything on stderr, or a non-zero exit
+     code.
+  """
+  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
+                                     'merge', '--reintegrate',
+                                     src_url, tgt_path)
+
+def run_reintegrate_expect_error(src_url, tgt_path,
+                                 expected_stdout, expected_stderr):
+  """Run 'svn merge --reintegrate SRC_URL TGT_PATH'. Raise an error
+     unless stdout and stderr both match and the exit code is non-zero.
+     Every line of stderr must match the regex EXPECTED_STDERR.
+  """
+  expected_stderr += "|(.*apr_err.*)"  # In case of debug build
+
+  # The actions.run_and_verify_* methods are happy if one line of the error
+  # matches the regex, but we want to check that every line matches.
+  # So we will pass the stderr to svntest.verify.verify_outputs()
+  # ourselves, but as the 'actual_stdout' argument, that way each line of
+  # error must match the regex.
+  exit_code, out, err = svntest.actions.run_and_verify_svn(
+                          None, expected_stdout, svntest.verify.AnyOutput,
+                          'merge', '--reintegrate',
+                          src_url, tgt_path)
+  assert exit_code
+  svntest.verify.verify_outputs(
+                   "Reintegrate failed but not in the way expected",
+                   err, None,
+                   expected_stderr, None,
+                   True) # Match *all* lines
+
+def run_and_verify_reintegrate(tgt_dir, src_url,
+                               output_tree,
+                               mergeinfo_output_tree,
+                               elision_output_tree,
+                               disk_tree, status_tree, skip_tree,
+                               error_re_string = None,
+                               check_props = True,
+                               dry_run = True):
+  """Run 'svn merge --reintegrate SRC_URL TGT_DIR'. Raise an error if
+     there is nothing on stdout, anything on stderr, or a non-zero exit
+     code, or if the expected ERROR_RE_STRING or any of the given expected
+     trees don't match.
+  """
+  svntest.actions.run_and_verify_merge(
+                    tgt_dir, None, None, src_url, None,
+                    output_tree, mergeinfo_output_tree, elision_output_tree,
+                    disk_tree, status_tree, skip_tree,
+                    error_re_string,
+                    None, None, None, None, check_props, dry_run,
+                    '--reintegrate', tgt_dir)
+
+
+#----------------------------------------------------------------------
 @SkipUnless(server_has_mergeinfo)
 @Issue(3640)
 def basic_reintegrate(sbox):
@@ -204,17 +260,15 @@ def basic_reintegrate(sbox):
   })
   k_expected_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A_COPY:2-8'})
   expected_skip = wc.State(A_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        k_expected_disk,
                                        k_expected_status,
                                        expected_skip,
-                                       None, None, None, None,
-                                       None, True, True,
-                                       '--reintegrate', A_path)
+                                       None, True, True)
 
   # Test issue #3640:
   #
@@ -263,17 +317,15 @@ def basic_reintegrate(sbox):
   expected_status.tweak(wc_rev=9)
   k_expected_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A_COPY:2-9'})
   expected_skip = wc.State(A_MOVED_path, {})
-  svntest.actions.run_and_verify_merge(A_MOVED_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_MOVED_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        k_expected_disk,
                                        expected_status,
                                        expected_skip,
-                                       None, None, None, None,
-                                       None, True, True,
-                                       '--reintegrate', A_MOVED_path)
+                                       None, True, True)
 
 #----------------------------------------------------------------------
 def reintegrate_with_rename(sbox):
@@ -492,17 +544,15 @@ def reintegrate_with_rename(sbox):
                           contents="This is the file 'tau'.\n")
     })
   expected_skip = wc.State(A_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        k_expected_disk,
                                        k_expected_status,
                                        expected_skip,
-                                       None, None, None, None,
-                                       None, True, True,
-                                       '--reintegrate', A_path)
+                                       None, True, True)
 
   # Finally, commit the result of the merge (r10).
   expected_output = wc.State(wc_dir, {
@@ -625,17 +675,15 @@ def reintegrate_branch_never_merged_to(s
     'D/H/psi'      : Item("New content"),
   })
   expected_skip = wc.State(A_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        k_expected_disk,
                                        k_expected_status,
                                        expected_skip,
-                                       None, None, None, None,
-                                       None, True, True,
-                                       '--reintegrate', A_path)
+                                       None, True, True)
 
   # Finally, commit the result of the merge (r9).
   expected_output = wc.State(wc_dir, {
@@ -656,15 +704,22 @@ def reintegrate_fail_on_modified_wc(sbox
   sbox.build()
   wc_dir = sbox.wc_dir
   A_path = sbox.ospath('A')
+  A_COPY_path = sbox.ospath('A_COPY')
   mu_path = os.path.join(A_path, "mu")
   ignored_expected_disk, ignored_expected_status = set_up_branch(sbox)
+
+  # Do a 'sync' merge first so that the following merge really needs to be a
+  # reintegrate, so that an equivalent automatic merge would behave the same.
+  svntest.main.run_svn(None, 'merge', sbox.repo_url + '/A', A_COPY_path)
+  sbox.simple_commit()
+
   svntest.main.file_write(mu_path, "Changed on 'trunk' (the merge target).")
   sbox.simple_update() # avoid mixed-revision error
-  svntest.actions.run_and_verify_merge(
-    A_path, None, None, sbox.repo_url + '/A_COPY', None, None, None, None,
+  run_and_verify_reintegrate(
+    A_path, sbox.repo_url + '/A_COPY', None, None, None,
     None, None, None,
     ".*Cannot merge into a working copy that has local modifications.*",
-    None, None, None, None, True, False, '--reintegrate', A_path)
+    True, False)
 
 #----------------------------------------------------------------------
 def reintegrate_fail_on_mixed_rev_wc(sbox):
@@ -683,11 +738,11 @@ def reintegrate_fail_on_mixed_rev_wc(sbo
   svntest.actions.run_and_verify_commit(wc_dir, expected_output,
                                         expected_status, None, wc_dir)
   # Try merging into that same wc, expecting failure.
-  svntest.actions.run_and_verify_merge(
-    A_path, None, None, sbox.repo_url + '/A_COPY', None, None, None, None,
+  run_and_verify_reintegrate(
+    A_path, sbox.repo_url + '/A_COPY', None, None, None,
     None, None, None,
     ".*Cannot merge into mixed-revision working copy.*",
-    None, None, None, None, True, False, '--reintegrate', A_path)
+    True, False)
 
 #----------------------------------------------------------------------
 def reintegrate_fail_on_switched_wc(sbox):
@@ -695,10 +750,29 @@ def reintegrate_fail_on_switched_wc(sbox
   sbox.build()
   wc_dir = sbox.wc_dir
   A_path = sbox.ospath('A')
+  A_COPY_path = sbox.ospath('A_COPY')
   G_path = os.path.join(A_path, "D", "G")
   switch_url = sbox.repo_url + "/A/D/H"
   expected_disk, expected_status = set_up_branch(sbox)
 
+  # Do a 'sync' merge first so that the following merge really needs to be a
+  # reintegrate, so that an equivalent automatic merge would behave the same.
+  expected_disk.tweak(
+    'A_COPY/D/H/psi',
+    'A_COPY/D/G/rho',
+    'A_COPY/B/E/beta',
+    'A_COPY/D/H/omega',
+    contents="New content")
+  expected_status.tweak(
+    'A_COPY/D/H/psi',
+    'A_COPY/D/G/rho',
+    'A_COPY/B/E/beta',
+    'A_COPY/D/H/omega',
+    'A_COPY',
+    wc_rev=7)
+  svntest.main.run_svn(None, 'merge', sbox.repo_url + '/A', A_COPY_path)
+  sbox.simple_commit()
+
   # Switch a subdir of the target.
   expected_output = svntest.wc.State(wc_dir, {
     'A/D/G/pi'          : Item(status='D '),
@@ -716,10 +790,10 @@ def reintegrate_fail_on_switched_wc(sbox
     })
   expected_status.remove('A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
   expected_status.add({
-    'A/D/G'       : Item(status='  ', wc_rev=6, switched='S'),
-    'A/D/G/chi'   : Item(status='  ', wc_rev=6),
-    'A/D/G/psi'   : Item(status='  ', wc_rev=6),
-    'A/D/G/omega' : Item(status='  ', wc_rev=6),
+    'A/D/G'       : Item(status='  ', wc_rev=7, switched='S'),
+    'A/D/G/chi'   : Item(status='  ', wc_rev=7),
+    'A/D/G/psi'   : Item(status='  ', wc_rev=7),
+    'A/D/G/omega' : Item(status='  ', wc_rev=7),
     })
   svntest.actions.run_and_verify_switch(wc_dir,
                                         G_path,
@@ -730,11 +804,11 @@ def reintegrate_fail_on_switched_wc(sbox
                                         None, None, None, None, None,
                                         False, '--ignore-ancestry')
   sbox.simple_update() # avoid mixed-revision error
-  svntest.actions.run_and_verify_merge(
-    A_path, None, None, sbox.repo_url + '/A_COPY', None, None, None, None,
+  run_and_verify_reintegrate(
+    A_path, sbox.repo_url + '/A_COPY', None, None, None,
     None, None, None,
     ".*Cannot merge into a working copy with a switched subtree.*",
-    None, None, None, None, True, False, '--reintegrate', A_path)
+    True, False)
 
 #----------------------------------------------------------------------
 # Test for issue #3603 'allow reintegrate merges into WCs with
@@ -804,16 +878,15 @@ def reintegrate_on_shallow_wc(sbox):
     'D'         : Item(), # Don't expect anything under D, its depth is empty!
     })
   expected_A_skip = wc.State(A_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_A_disk,
                                        expected_A_status,
                                        expected_A_skip,
-                                       None, None, None, None,
-                                       None, 1, 1, "--reintegrate", A_path)
+                                       None, 1, 1)
 
   # Now revert the reintegrate and make a second change on the
   # branch in r4, but this time change a subtree that corresponds
@@ -832,22 +905,25 @@ def reintegrate_on_shallow_wc(sbox):
   expected_A_disk.tweak('D', props={SVN_PROP_MERGEINFO : '/A_COPY/D:2-4*'})
   # ... a depth-restricted item is skipped ...
   expected_A_skip.add({
-      'D/H/psi' : Item(verb='Skipped')
+      'D/H' : Item(verb='Skipped missing target')
+  })
+  expected_output.add({
+    # Below the skip
+    'D/H/psi'           : Item(status='  ', treeconflict='U'),
   })
   # Currently this fails due to r1424469.  For a full explanation see
   # http://svn.haxx.se/dev/archive-2012-12/0472.shtml
   # and http://svn.haxx.se/dev/archive-2012-12/0475.shtml
   expected_A_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A_COPY:2-4'})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_A_disk,
                                        expected_A_status,
                                        expected_A_skip,
-                                       None, None, None, None,
-                                       None, 1, 1, "--reintegrate", A_path)
+                                       None, 1, 1)
 
 #----------------------------------------------------------------------
 @SkipUnless(server_has_mergeinfo)
@@ -916,16 +992,15 @@ def reintegrate_fail_on_stale_source(sbo
     'D/H/omega' : Item("New content"),
     })
   expected_skip = wc.State(A_path, { })
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status,
                                        expected_skip,
-                                       [], None, None, None, None, True, True,
-                                       '--reintegrate', A_path)
+                                       [], True, True)
 
 #----------------------------------------------------------------------
 def merge_file_with_space_in_its_path(sbox):
@@ -955,9 +1030,7 @@ def merge_file_with_space_in_its_path(sb
                                      "ci", "-m", "r4", wc_dir)
 
   target_url = sbox.repo_url + '/some%20dir/file2'
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     "merge", "--reintegrate", target_url,
-                                     file1)
+  run_reintegrate(target_url, file1)
 
 #----------------------------------------------------------------------
 @SkipUnless(server_has_mergeinfo)
@@ -1175,16 +1248,15 @@ def reintegrate_with_subtree_mergeinfo(s
     'D/H/omega' : Item("New content"),
     })
   expected_A_skip = wc.State(A_COPY_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_A_disk,
                                        expected_A_status,
                                        expected_A_skip,
-                                       None, None, None, None,
-                                       None, 1, 1, "--reintegrate", A_path)
+                                       None, 1, 1)
 
   # Make some more changes to A_COPY so that the same revisions have *not*
   # been uniformly applied from A to A_COPY.  In this case the reintegrate
@@ -1224,19 +1296,10 @@ def reintegrate_with_subtree_mergeinfo(s
   # to it from A, the merge should fail.  Further we expect an error message
   # that highlights the fact that A_COPY/D is the offending subtree.
   #
-  # The actions.run_and_verify_* methods are happy if one line of the error
-  # matches the regex, but we want to know that the error actually provides
-  # specific information about the paths that are stopping --reintegrate from
-  # working.  So we will pass the stderr to svntest.verify.verify_outputs()
-  # ourselves, but as the 'actual_stdout' argument, that way each line of
-  # error must match the regex.
-  exit_code, out, err = svntest.actions.run_and_verify_svn(
-    None, [], svntest.verify.AnyOutput,
-    'merge', '--reintegrate', sbox.repo_url + '/A_COPY', A_path)
-
-  svntest.verify.verify_outputs("Reintegrate failed but not "
-                                "in the way expected",
-                                err, None,
+  # We want to know that the error provides specific information about the
+  # paths that are stopping --reintegrate from working.
+  run_reintegrate_expect_error(sbox.repo_url + '/A_COPY', A_path,
+                               [],
                                 "(svn: E195016: Reintegrate can only be used if "
                                 "revisions 2 through 15 were previously "
                                 "merged from .*/A to the reintegrate source, "
@@ -1245,10 +1308,7 @@ def reintegrate_with_subtree_mergeinfo(s
                                 "|(    Missing ranges: /A/D:8\n)"
                                 "|(  A_COPY/mu\n)"
                                 "|(    Missing ranges: /A/mu:2-12\n)"
-                                "|(\n)"
-                                "|(.*apr_err.*)", # In case of debug build
-                                None,
-                                True) # Match *all* lines of stdout
+                                "|(\n)")
 
   # Test another common situation that can break reintegrate as a result
   # of copies and moves:
@@ -1295,6 +1355,14 @@ def reintegrate_with_subtree_mergeinfo(s
   expected_status.remove('A/D/gamma')
   expected_status.add({'A/D/gamma_moved' : Item(status='  ', wc_rev=16)})
 
+  # Why is gamma_moved notified as ' G' rather than ' U'?  It was
+  # added by the merge and there is only a single editor drive, so
+  # how can any prop changes be merged to it?  The answer is that
+  # the merge code does some quiet housekeeping, merging gamma_moved's
+  # inherited mergeinfo into its incoming mergeinfo, see
+  # http://subversion.tigris.org/issues/show_bug.cgi?id=4309
+  # This test is not covering issue #4309 so we let the current
+  # behavior pass.
   # r17 - B) Synch merge from A to A_COPY
   svntest.actions.run_and_verify_svn(
     None,
@@ -1304,7 +1372,7 @@ def reintegrate_with_subtree_mergeinfo(s
                            'D    ' + gamma_COPY_path + '\n',
                            ' U   ' + A_COPY_path     + '\n',
                            ' U   ' + D_COPY_path     + '\n',
-                           ' U   ' + gamma_moved_COPY_path + '\n']),
+                           ' G   ' + gamma_moved_COPY_path + '\n']),
     [], 'merge', sbox.repo_url + '/A',  A_COPY_path)
   expected_output = wc.State(
     wc_dir,
@@ -1374,7 +1442,7 @@ def reintegrate_with_subtree_mergeinfo(s
     ''              : Item(status=' U'),
     'mu'            : Item(status=' G'),
     'D'             : Item(status=' U'),
-    'D/gamma_moved' : Item(status=' U'),
+    'D/gamma_moved' : Item(status=' G'), # More issue #4309 (see above)
     })
   expected_elision_output = wc.State(A_path, {
     })
@@ -1418,26 +1486,49 @@ def reintegrate_with_subtree_mergeinfo(s
     '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"),
+    # What's with all this mergeinfo?
+    #
+    # '/A/D/gamma_moved:2-7,9-12' - Incoming from the merge source.  Yes,
+    # this mergeinfo describes non-existent path-revs, this is the effect
+    # of issue #3669 'inheritance can result in mergeinfo describing
+    # nonexistent sources', but there is already a test for that issue so
+    # we tolerate it here.
+    #
+    # '/A_COPY/D/gamma_moved:17-19' - Describes the merge performed.
+    #
+    # '/A_COPY_3/D/gamma:9' - Explicit prior to the merge.
+    #
+    #'/A_COPY_3/D/gamma_moved:9' - Incoming from the merge source.
+    # For the curious, this was originally created in r17 when we merged
+    # ^/A to A_COPY.  This merge added A_COPY/D/gamma_moved, which had
+    # explicit mergeinfo and due to issue #4309 'wrong notification and
+    # bogus mergeinfo during merge which adds subtree with mergeinfo'
+    # this file inherited this bogus mergeinfo from A_COPY/D.  Yes, this
+    # is all quite ugly as the intersection or multiple known issues
+    # is likely to be.  However, given that none of this mergeinfo is
+    # particularly harmful and that this test is *not* about issues #3669
+    # or #4309, we are tolerting it.
     'D/gamma_moved' : Item(
       "Even newer content", props={SVN_PROP_MERGEINFO :
+                                   '/A/D/gamma_moved:2-7,9-12\n'
                                    '/A_COPY/D/gamma_moved:17-19\n'
-                                   '/A_COPY_3/D/gamma:9'}),
+                                   '/A_COPY_3/D/gamma:9\n'
+                                   '/A_COPY_3/D/gamma_moved:9'}),
     '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_A_skip = wc.State(A_COPY_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_A_disk,
                                        expected_A_status,
                                        expected_A_skip,
-                                       None, None, None, None,
-                                       None, 1, 1, "--reintegrate", A_path)
+                                       None, 1, 1)
 
 #----------------------------------------------------------------------
 @SkipUnless(server_has_mergeinfo)
@@ -1494,9 +1585,7 @@ def multiple_reintegrates_from_the_same_
 
   # r11 - Reintegrate the feature branch back to 'A'.
   svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-  svntest.actions.run_and_verify_svn(None, None, [], 'merge', '--reintegrate',
-                                     sbox.repo_url + '/A_FEATURE_BRANCH',
-                                     A_path)
+  run_reintegrate(sbox.repo_url + '/A_FEATURE_BRANCH', A_path)
   svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
                                      "Reintegrate feature branch back to 'A'",
                                      wc_dir)
@@ -1588,17 +1677,15 @@ def multiple_reintegrates_from_the_same_
     'D/H/omega' : Item("New content"),
     })
   expected_skip = wc.State(A_path, { })
-  svntest.actions.run_and_verify_merge(A_path, None, None,
+  run_and_verify_reintegrate(A_path,
                                        sbox.repo_url + '/A_FEATURE_BRANCH',
-                                       None,
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status,
                                        expected_skip,
-                                       None, None, None, None,
-                                       None, 1, 1, '--reintegrate', A_path)
+                                       None, 1, 1)
   svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
                                      "2nd Reintegrate feature branch back to 'A'",
                                      wc_dir)
@@ -1746,16 +1833,15 @@ def reintegrate_with_self_referential_me
   #  ..\..\..\subversion\libsvn_fs_fs\tree.c:2886: (apr_err=160013)
   #  ..\..\..\subversion\libsvn_fs_fs\tree.c:669: (apr_err=160013)
   #  svn: File not found: revision 4, path '/A2'
-  svntest.actions.run_and_verify_merge(A2_path, None, None,
-                                       sbox.repo_url + '/A2.1', None,
+  run_and_verify_reintegrate(A2_path,
+                                       sbox.repo_url + '/A2.1',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status,
                                        expected_skip,
-                                       None, None, None, None,
-                                       None, 1, 0, '--reintegrate', A2_path)
+                                       None, 1, 0)
 
 #----------------------------------------------------------------------
 # Test for issue #3577 '1.7 subtree mergeinfo recording breaks reintegrate'.
@@ -1878,16 +1964,15 @@ def reintegrate_with_subtree_merges(sbox
     'D/H/omega' : Item("New content"),
     })
   expected_A_skip = wc.State(A_COPY_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_A_disk,
                                        expected_A_status,
                                        expected_A_skip,
-                                       None, None, None, None,
-                                       None, 1, 1, "--reintegrate", A_path)
+                                       None, 1, 1)
 
 #----------------------------------------------------------------------
 # Test for issue #3654 'added subtrees with mergeinfo break reintegrate'.
@@ -1961,9 +2046,7 @@ def added_subtrees_with_mergeinfo_break_
 
   # r14 - Reintegrate A_COPY to A.
   svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
-                                     'merge', '--reintegrate',
-                                     sbox.repo_url + '/A_COPY', A_path)
+  run_reintegrate(sbox.repo_url + '/A_COPY', A_path)
   svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
                                      'Reintegrate A_COPY to A.',
                                      wc_dir)
@@ -2073,16 +2156,15 @@ def added_subtrees_with_mergeinfo_break_
     'D/H/omega' : Item("New content"),
     })
   expected_skip = wc.State(A_COPY_path, {})
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status,
                                        expected_skip,
-                                       None, None, None, None,
-                                       None, 1, 1, "--reintegrate", A_path)
+                                       None, 1, 1)
 
 #----------------------------------------------------------------------
 # Test for issue #3648 '2-URL merges incorrectly reverse-merge mergeinfo
@@ -2322,14 +2404,14 @@ def reintegrate_creates_bogus_mergeinfo(
     })
   expected_skip = wc.State(A_COPY_path, {})
 
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       A_COPY_url, None,
+  run_and_verify_reintegrate(A_path,
+                                       A_COPY_url,
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk, None, expected_skip,
-                                       None, None, None, None, None,
-                                       1, 1, "--reintegrate", A_path)
+                                       None,
+                                       1, 1)
 
 
 #----------------------------------------------------------------------
@@ -2391,8 +2473,7 @@ def no_source_subtree_mergeinfo(sbox):
   svntest.main.run_svn(None, 'update', wc_dir)
 
   # Reintegrate branch-1 subtree to trunk subtree
-  svntest.main.run_svn(None, 'merge', '--reintegrate',
-                       '^/A/B1/E', sbox.ospath('A/B/E'))
+  run_reintegrate('^/A/B1/E', sbox.ospath('A/B/E'))
   svntest.main.run_svn(None, 'commit', '-m', 'log message', wc_dir)
   svntest.main.run_svn(None, 'update', wc_dir)
 
@@ -2446,22 +2527,13 @@ def no_source_subtree_mergeinfo(sbox):
       })
   expected_skip = wc.State(sbox.ospath('A/B'), {
       })
-  svntest.actions.run_and_verify_merge(sbox.ospath('A/B'),
-                                       None, None, '^/A/B2', None,
+  run_and_verify_reintegrate(sbox.ospath('A/B'),
+                                       '^/A/B2',
                                        expected_output, expected_mergeinfo,
                                        expected_elision, expected_disk,
                                        None, expected_skip,
-                                       None, None, None, None, None,
-                                       1, 1, '--reintegrate',
-                                       sbox.ospath('A/B'))
-  # For 1.6 testsuite use:
-  # svntest.actions.run_and_verify_merge(sbox.ospath('A/B'),
-  #                                      None, None, '^/A/B2',
-  #                                      expected_output,
-  #                                      expected_disk,
-  #                                      None, expected_skip,
-  #                                      None, None, None, None, None,
-  #                                      1, 1, '--reintegrate')
+                                       None,
+                                       1, 1)
 
 #----------------------------------------------------------------------
 @SkipUnless(server_has_mergeinfo)
@@ -2578,16 +2650,15 @@ def reintegrate_replaced_source(sbox):
     'D/H/omega' : Item("New content"),
     })
   expected_skip = wc.State(A_path, { })
-  svntest.actions.run_and_verify_merge(A_path, None, None,
-                                       sbox.repo_url + '/A_COPY', None,
+  run_and_verify_reintegrate(A_path,
+                                       sbox.repo_url + '/A_COPY',
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status,
                                        expected_skip,
-                                       [], None, None, None, None, True, True,
-                                       '--reintegrate', A_path)
+                                       [], True, True)
 
 #----------------------------------------------------------------------
 @SkipUnless(svntest.main.is_posix_os)
@@ -2624,8 +2695,7 @@ def reintegrate_symlink_deletion(sbox):
 
   ## reintegrate
   # ### TODO: verify something here
-  svntest.main.run_svn(None, 'merge', '--reintegrate',
-                       A_COPY_url, A_path)
+  run_reintegrate(A_COPY_url, A_path)
 
 #----------------------------------------------------------------------
 def no_op_reintegrate(sbox):
@@ -2645,8 +2715,7 @@ def no_op_reintegrate(sbox):
 
   # Reintegrate; there are no relevant changes on the branch.
   # ### TODO: Check the result more carefully than merely that it completed.
-  svntest.main.run_svn(None, 'merge', '--reintegrate',
-                       sbox.repo_url + '/A_COPY', A_path)
+  run_reintegrate(sbox.repo_url + '/A_COPY', A_path)
 
 #----------------------------------------------------------------------
 def renamed_branch_reintegrate(sbox):
@@ -2685,8 +2754,7 @@ def renamed_branch_reintegrate(sbox):
 
   # Reintegrate; there are no relevant changes on the branch.
   # ### TODO: Check the result more carefully than merely that it completed.
-  svntest.main.run_svn(None, 'merge', '--reintegrate',
-                       sbox.repo_url + '/RENAMED@8', A_path)
+  run_reintegrate(sbox.repo_url + '/RENAMED@8', A_path)
 
 ########################################################################
 # Run the tests