You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2012/09/12 15:57:37 UTC

svn commit: r1383943 - in /subversion/branches/1.6.x: ./ subversion/bindings/swig/python/tests/ subversion/bindings/swig/python/tests/trac/versioncontrol/tests/ subversion/bindings/swig/ruby/test/ subversion/tests/cmdline/ subversion/tests/cmdline/svnt...

Author: stsp
Date: Wed Sep 12 13:57:35 2012
New Revision: 1383943

URL: http://svn.apache.org/viewvc?rev=1383943&view=rev
Log:
Reintegrate the 1.6.x-testsuite-apr-hash-order branch.

Affects test suite only, thus using the "somewhat looser voting system".

 * ^/subversion/branches/1.6.x-testsuite-apr-hash-order
   Various test suite fixes, mostly backported from trunk, to allow
   most of the test suite to PASS with APR 1.4.6.
   Notes:
     All backported changes were also backported to 1.7.x.
     Some 1.6.x-specific changes were made, see r1383371 and r1383408.

     The known remaining failures are:

     log_tests.py 30: log -g should ignore cyclic merges
     Can fail because 1.6.x is missing r1293229, which fixed occasionally
     missing merged-via notifications.
   
     diff_tests.py 32: repos-wc diff showing added entries with props
     Can fail because this test is missing various tweaks to account
     for random output order of 'svn diff' (this is independent of the
     APR 1.4.6 hash order problem).
   
     ruby swig test 'test_dump'
     Can fail because 1.6.x is missing r966458, which sorted property
     listings in dump files in alphabetical order, and this test does
     not parse dump files and sort properties for comparison.
   Votes:
     +1: stsp, brane

Modified:
    subversion/branches/1.6.x/   (props changed)
    subversion/branches/1.6.x/STATUS
    subversion/branches/1.6.x/subversion/bindings/swig/python/tests/repository.py
    subversion/branches/1.6.x/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py
    subversion/branches/1.6.x/subversion/bindings/swig/python/tests/wc.py
    subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_client.rb
    subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_wc.rb
    subversion/branches/1.6.x/subversion/tests/cmdline/diff_tests.py
    subversion/branches/1.6.x/subversion/tests/cmdline/lock_tests.py
    subversion/branches/1.6.x/subversion/tests/cmdline/stat_tests.py
    subversion/branches/1.6.x/subversion/tests/cmdline/svnadmin_tests.py
    subversion/branches/1.6.x/subversion/tests/cmdline/svnlook_tests.py
    subversion/branches/1.6.x/subversion/tests/cmdline/svnsync_tests.py
    subversion/branches/1.6.x/subversion/tests/cmdline/svntest/actions.py
    subversion/branches/1.6.x/subversion/tests/cmdline/svntest/verify.py
    subversion/branches/1.6.x/subversion/tests/cmdline/switch_tests.py
    subversion/branches/1.6.x/subversion/tests/cmdline/update_tests.py

Propchange: subversion/branches/1.6.x/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1240619,1241626,1291429,1291446,1291520,1291680,1291704,1291726,1291941,1292248,1292255,1292260,1292296,1292322,1292507,1292516,1292768,1292926,1310535,1310594
  Merged /subversion/branches/1.6.x-testsuite-apr-hash-order:r1383328-1383942

Modified: subversion/branches/1.6.x/STATUS
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/STATUS?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/STATUS (original)
+++ subversion/branches/1.6.x/STATUS Wed Sep 12 13:57:35 2012
@@ -45,31 +45,6 @@ Candidate changes:
      +0: gstein (haven't reviewed these specific revisions yet)
      -0: stsp (not a critical fix, serf is an optional dependency in 1.6.x)
 
- * ^/subversion/branches/1.6.x-testsuite-apr-hash-order
-   Various test suite fixes, mostly backported from trunk, to allow
-   most of the test suite to PASS with APR 1.4.6.
-   Notes:
-     All backported changes were also backported to 1.7.x.
-     Some 1.6.x-specific changes were made, see r1383371 and r1383408.
-
-     The known remaining failures are:
-
-     log_tests.py 30: log -g should ignore cyclic merges
-     Can fail because 1.6.x is missing r1293229, which fixed occasionally
-     missing merged-via notifications.
-   
-     diff_tests.py 32: repos-wc diff showing added entries with props
-     Can fail because this test is missing various tweaks to account
-     for random output order of 'svn diff' (this is independent of the
-     APR 1.4.6 hash order problem).
-   
-     ruby swig test 'test_dump'
-     Can fail because 1.6.x is missing r966458, which sorted property
-     listings in dump files in alphabetical order, and this test does
-     not parse dump files and sort properties for comparison.
-   Votes:
-     +1: stsp, brane
-
 Veto-blocked changes:
 =====================
 

Modified: subversion/branches/1.6.x/subversion/bindings/swig/python/tests/repository.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/bindings/swig/python/tests/repository.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/bindings/swig/python/tests/repository.py (original)
+++ subversion/branches/1.6.x/subversion/bindings/swig/python/tests/repository.py Wed Sep 12 13:57:35 2012
@@ -133,9 +133,11 @@ class SubversionRepositoryTestCase(unitt
     repos.dir_delta(prev_root, '', '', this_root, '', e_ptr, e_baton,
                     _authz_callback, 1, 1, 0, 0)
 
-    # Check results
-    self.assertEqual(editor.textdeltas[0].new_data, "This is a test.\n")
-    self.assertEqual(editor.textdeltas[1].new_data, "A test.\n")
+    # Check results.
+    # Ignore the order in which the editor delivers the two sibling files.
+    self.assertEqual(set([editor.textdeltas[0].new_data,
+                          editor.textdeltas[1].new_data]),
+                     set(["This is a test.\n", "A test.\n"]))
     self.assertEqual(len(editor.textdeltas),2)
 
   def test_retrieve_and_change_rev_prop(self):

Modified: subversion/branches/1.6.x/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py (original)
+++ subversion/branches/1.6.x/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py Wed Sep 12 13:57:35 2012
@@ -224,30 +224,50 @@ class SubversionRepositoryTestCase(unitt
 
     def test_diff_dir_different_revs(self):
         diffs = self.repos.get_deltas('trunk', 4, 'trunk', 8)
-        self._cmp_diff((None, ('trunk/dir1/dir2', 8),
-                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
-        self._cmp_diff((None, ('trunk/dir1/dir3', 8),
-                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
-        self._cmp_diff((None, ('trunk/README2.txt', 6),
-                        (Node.FILE, Changeset.ADD)), diffs.next())
-        self._cmp_diff((('trunk/dir2', 4), None,
-                        (Node.DIRECTORY, Changeset.DELETE)), diffs.next())
-        self._cmp_diff((('trunk/dir3', 4), None,
-                        (Node.DIRECTORY, Changeset.DELETE)), diffs.next())
+        expected = [
+          (None, ('trunk/README2.txt', 6),
+           (Node.FILE, Changeset.ADD)),
+          (None, ('trunk/dir1/dir2', 8),
+           (Node.DIRECTORY, Changeset.ADD)),
+          (None, ('trunk/dir1/dir3', 8),
+           (Node.DIRECTORY, Changeset.ADD)),
+          (('trunk/dir2', 4), None,
+           (Node.DIRECTORY, Changeset.DELETE)),
+          (('trunk/dir3', 4), None,
+           (Node.DIRECTORY, Changeset.DELETE)),
+        ]
+        actual = [diffs.next() for i in range(5)]
+        actual = sorted(actual,
+                        key=lambda diff: ((diff[0] or diff[1]).path,
+                                          (diff[0] or diff[1]).rev))
+        self.assertEqual(len(expected), len(actual))
+        for e,a in zip(expected, actual):
+          self._cmp_diff(e,a)
         self.assertRaises(StopIteration, diffs.next)
 
     def test_diff_dir_different_dirs(self):
         diffs = self.repos.get_deltas('trunk', 1, 'branches/v1x', 12)
-        self._cmp_diff((None, ('branches/v1x/dir1', 12),
-                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
-        self._cmp_diff((None, ('branches/v1x/dir1/dir2', 12),
-                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
-        self._cmp_diff((None, ('branches/v1x/dir1/dir3', 12),
-                        (Node.DIRECTORY, Changeset.ADD)), diffs.next())
-        self._cmp_diff((None, ('branches/v1x/README.txt', 12),
-                        (Node.FILE, Changeset.ADD)), diffs.next())
-        self._cmp_diff((None, ('branches/v1x/README2.txt', 12),
-                        (Node.FILE, Changeset.ADD)), diffs.next())
+        expected = [
+          (None, ('branches/v1x/README.txt', 12),
+           (Node.FILE, Changeset.ADD)),
+          (None, ('branches/v1x/README2.txt', 12),
+           (Node.FILE, Changeset.ADD)),
+          (None, ('branches/v1x/dir1', 12),
+           (Node.DIRECTORY, Changeset.ADD)),
+          (None, ('branches/v1x/dir1/dir2', 12),
+           (Node.DIRECTORY, Changeset.ADD)),
+          (None, ('branches/v1x/dir1/dir3', 12),
+           (Node.DIRECTORY, Changeset.ADD)),
+        ]
+        actual = [diffs.next() for i in range(5)]
+        actual = sorted(actual, key=lambda diff: (diff[1].path, diff[1].rev))
+        # for e,a in zip(expected, actual):
+        #   t.write("%r\n" % (e,))
+        #   t.write("%r\n" % ((None, (a[1].path, a[1].rev), (a[2], a[3])),) )
+        #   t.write('\n')
+        self.assertEqual(len(expected), len(actual))
+        for e,a in zip(expected, actual):
+          self._cmp_diff(e,a)
         self.assertRaises(StopIteration, diffs.next)
 
     def test_diff_dir_no_change(self):

Modified: subversion/branches/1.6.x/subversion/bindings/swig/python/tests/wc.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/bindings/swig/python/tests/wc.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/bindings/swig/python/tests/wc.py (original)
+++ subversion/branches/1.6.x/subversion/bindings/swig/python/tests/wc.py Wed Sep 12 13:57:35 2012
@@ -193,8 +193,9 @@ class SubversionWorkingCopyTestCase(unit
 
   def test_entries_read(self):
       entries = wc.entries_read(self.wc, True)
-
-      self.assertEqual(['', 'tags', 'branches', 'trunk'], list(entries.keys()))
+      keys = list(entries.keys())
+      keys.sort()
+      self.assertEqual(['', 'branches', 'tags', 'trunk'], keys)
 
   def test_get_ignores(self):
       self.assert_(isinstance(wc.get_ignores(None, self.wc), list))

Modified: subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_client.rb
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_client.rb?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_client.rb (original)
+++ subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_client.rb Wed Sep 12 13:57:35 2012
@@ -2303,7 +2303,9 @@ class SvnClientTest < Test::Unit::TestCa
 
   def test_changelists_get_without_block
     assert_changelists do |ctx, changelist_name|
-      ctx.changelists(changelist_name, @wc_path)
+      changelists = ctx.changelists(changelist_name, @wc_path)
+      changelists.each_value { |v| v.sort! }
+      changelists
     end
   end
 
@@ -2313,6 +2315,7 @@ class SvnClientTest < Test::Unit::TestCa
       ctx.changelists(changelist_name, @wc_path) do |path,cl_name|
         changelists[cl_name] << path
       end
+      changelists.each_value { |v| v.sort! }
       changelists
     end
   end

Modified: subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_wc.rb
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_wc.rb?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_wc.rb (original)
+++ subversion/branches/1.6.x/subversion/bindings/swig/ruby/test/test_wc.rb Wed Sep 12 13:57:35 2012
@@ -731,14 +731,15 @@ EOE
             :file_changed_prop_name => prop_name,
             :file_changed_prop_value => prop_value,
           }
-          expected_props, actual_result = yield(property_info, callbacks.result)
+          sorted_result = callbacks.result.sort_by {|r| r.first.to_s}
+          expected_props, actual_result = yield(property_info, sorted_result)
           dir_changed_props, file_changed_props, empty_changed_props = expected_props
           assert_equal([
                         [:dir_props_changed, @wc_path, dir_changed_props],
-                        [:file_changed, path1, file_changed_props],
                         [:file_added, path2, empty_changed_props],
+                        [:file_changed, path1, file_changed_props],
                        ],
-                       callbacks.result)
+                       sorted_result)
         end
       end
     end

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/diff_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/diff_tests.py Wed Sep 12 13:57:35 2012
@@ -1024,8 +1024,10 @@ def diff_base_to_repos(sbox):
     if not re_infoline.match(line):
       list2.append(line)
 
-  if list1 != list2:
-    raise svntest.Failure
+  # Two files in diff may be in any order.
+  list1 = svntest.verify.UnorderedOutput(list1)
+
+  svntest.verify.compare_and_display_lines('', '', list1, list2)
 
 
 #----------------------------------------------------------------------

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/lock_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/lock_tests.py Wed Sep 12 13:57:35 2012
@@ -1462,7 +1462,9 @@ test_list = [ None,
               SkipUnless(lock_and_exebit2, svntest.main.is_posix_os),
               commit_xml_unsafe_file_unlock,
               repos_lock_with_info,
-              unlock_already_unlocked_files,
+              # Issue 4126 unpredictable result
+              Skip(unlock_already_unlocked_files,
+                   svntest.main.is_ra_type_dav_serf),
               info_moved_path,
               ls_url_encoded,
               XFail(unlock_wrong_token, svntest.main.is_ra_type_dav),

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/stat_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/stat_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/stat_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/stat_tests.py Wed Sep 12 13:57:35 2012
@@ -781,38 +781,13 @@ def status_in_xml(sbox):
   else:
     raise svntest.Failure
 
-  template = ["<?xml version=\"1.0\"?>\n",
-              "<status>\n",
-              "<target\n",
-              "   path=\"%s\">\n" % (file_path),
-              "<entry\n",
-              "   path=\"%s\">\n" % (file_path),
-              "<wc-status\n",
-              "   props=\"none\"\n",
-              "   item=\"modified\"\n",
-              "   revision=\"1\">\n",
-              "<commit\n",
-              "   revision=\"1\">\n",
-              "<author>%s</author>\n" % svntest.main.wc_author,
-              time_str,
-              "</commit>\n",
-              "</wc-status>\n",
-              "</entry>\n",
-              "<against\n",
-              "   revision=\"1\"/>\n",
-              "</target>\n",
-              "</status>\n",
-             ]
+  expected_entries = {file_path : {'wcprops' : 'none',
+                                   'wcitem' : 'modified',
+                                   'wcrev' : '1',
+                                   'crev' : '1',
+                                   'author' : svntest.main.wc_author}}
 
-  exit_code, output, error = svntest.actions.run_and_verify_svn(None, None, [],
-                                                                'status',
-                                                                file_path,
-                                                                '--xml', '-u')
-
-  for i in range(0, len(output)):
-    if output[i] != template[i]:
-      print("ERROR: expected: %s actual: %s" % (template[i], output[i]))
-      raise svntest.Failure
+  svntest.actions.run_and_verify_status_xml(expected_entries, file_path, '-u')
 
 #----------------------------------------------------------------------
 
@@ -1049,53 +1024,23 @@ def status_update_with_incoming_props(sb
   else:
     raise svntest.Failure
 
-  xout = ["<?xml version=\"1.0\"?>\n",
-          "<status>\n",
-          "<target\n",
-          "   path=\"%s\">\n" % (wc_dir),
-          "<entry\n",
-          "   path=\"%s\">\n" % (A_path),
-          "<wc-status\n",
-          "   props=\"none\"\n",
-          "   item=\"normal\"\n",
-          "   revision=\"1\">\n",
-          "<commit\n",
-          "   revision=\"1\">\n",
-          "<author>%s</author>\n" % svntest.main.wc_author,
-          time_str,
-          "</commit>\n",
-          "</wc-status>\n",
-          "<repos-status\n",
-          "   props=\"modified\"\n",
-          "   item=\"none\">\n",
-          "</repos-status>\n",
-          "</entry>\n",
-          "<entry\n",
-          "   path=\"%s\">\n" % (wc_dir),
-          "<wc-status\n",
-          "   props=\"none\"\n",
-          "   item=\"normal\"\n",
-          "   revision=\"1\">\n",
-          "<commit\n",
-          "   revision=\"1\">\n",
-          "<author>%s</author>\n" % svntest.main.wc_author,
-          time_str,
-          "</commit>\n",
-          "</wc-status>\n",
-          "<repos-status\n",
-          "   props=\"modified\"\n",
-          "   item=\"none\">\n",
-          "</repos-status>\n",
-          "</entry>\n",
-          "<against\n",
-          "   revision=\"2\"/>\n",
-          "</target>\n",
-          "</status>\n",]
-
-  exit_code, output, error = svntest.actions.run_and_verify_svn(None, xout, [],
-                                                                'status',
-                                                                wc_dir,
-                                                                '--xml', '-uN')
+  expected_entries ={wc_dir : {'wcprops' : 'none',
+                               'wcitem' : 'normal',
+                               'wcrev' : '1',
+                               'crev' : '1',
+                               'author' : svntest.main.wc_author,
+                               'rprops' : 'modified',
+                               'ritem' : 'none'},
+                     A_path : {'wcprops' : 'none',
+                               'wcitem' : 'normal',
+                               'wcrev' : '1',
+                               'crev' : '1',
+                               'author' : svntest.main.wc_author,
+                               'rprops' : 'modified',
+                               'ritem' : 'none'},
+                     }
+
+  svntest.actions.run_and_verify_status_xml(expected_entries, wc_dir, '-uN')
 
 # more incoming prop updates.
 def status_update_verbose_with_incoming_props(sbox):

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/svnadmin_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/svnadmin_tests.py Wed Sep 12 13:57:35 2012
@@ -351,8 +351,9 @@ def hotcopy_dot(sbox):
   exit_code, backout, backerr = svntest.main.run_svnadmin("dump",
                                                           backup_dir,
                                                           '--quiet')
-  if origerr or backerr or origout != backout:
+  if origerr or backerr:
     raise svntest.Failure
+  svntest.verify.compare_dump_files("Dump files", "DUMP", origout, backout)
 
 #----------------------------------------------------------------------
 

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/svnlook_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/svnlook_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/svnlook_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/svnlook_tests.py Wed Sep 12 13:57:35 2012
@@ -105,35 +105,39 @@ def test_misc(sbox):
   # the 'svnlook tree --full-paths' output if demanding the whole repository
   treelist = run_svnlook('tree', repo_dir)
   treelistfull = run_svnlook('tree', '--full-paths', repo_dir)
+
   path = ''
-  n = 0
+  treelistexpand = []
   for entry in treelist:
     len1 = len(entry)
     len2 = len(entry.lstrip())
-    path = path[0:2*(len1-len2)-1] + entry.strip()
-    test = treelistfull[n].rstrip()
-    if n != 0:
-      test = "/" + test
-    if not path == test:
-      print("Unexpected result from tree with --full-paths:")
-      print("  entry            : %s" % entry.rstrip())
-      print("  with --full-paths: %s" % treelistfull[n].rstrip())
-      raise svntest.Failure
-    n = n + 1
+    path = path[0:2*(len1-len2)-1] + entry.strip() + '\n'
+    if path == '/\n':
+      treelistexpand.append(path)
+    else:
+      treelistexpand.append(path[1:])
+
+  treelistexpand = svntest.verify.UnorderedOutput(treelistexpand)
+  svntest.verify.compare_and_display_lines('Unexpected result from tree', '',
+                                           treelistexpand, treelistfull)
 
   # check if the 'svnlook tree' output is the ending of
   # the 'svnlook tree --full-paths' output if demanding
   # any part of the repository
-  n = 0
   treelist = run_svnlook('tree', repo_dir, '/A/B')
   treelistfull = run_svnlook('tree', '--full-paths', repo_dir, '/A/B')
+
+  path = ''
+  treelistexpand = []
   for entry in treelist:
-    if not treelistfull[n].endswith(entry.lstrip()):
-      print("Unexpected result from tree with --full-paths:")
-      print("  entry            : %s" % entry.rstrip())
-      print("  with --full-paths: %s" % treelistfull[n].rstrip())
-      raise svntest.Failure
-    n = n + 1
+    len1 = len(entry)
+    len2 = len(entry.lstrip())
+    path = path[0:2*(len1-len2)] + entry.strip() + '\n'
+    treelistexpand.append('/A/' + path)
+
+  treelistexpand = svntest.verify.UnorderedOutput(treelistexpand)
+  svntest.verify.compare_and_display_lines('Unexpected result from tree', '',
+                                           treelistexpand, treelistfull)
 
   treelist = run_svnlook('tree', repo_dir, '/')
   if treelist[0] != '/\n':
@@ -621,7 +625,7 @@ fp.close()"""
                     #  internal property, not really expected
                     '  svn:check-locks\n',
                     '  bogus_rev_prop\n', '  svn:date\n']
-  verify_logfile(logfilepath, expected_data)
+  verify_logfile(logfilepath, svntest.verify.UnorderedOutput(expected_data))
 
 ########################################################################
 # Run the tests

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/svnsync_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/svnsync_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/svnsync_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/svnsync_tests.py Wed Sep 12 13:57:35 2012
@@ -179,7 +179,7 @@ or another dump file."""
   else:
     exp_master_dumpfile_contents = master_dumpfile_contents
 
-  svntest.verify.compare_and_display_lines(
+  svntest.verify.compare_dump_files(
     "Dump files", "DUMP", exp_master_dumpfile_contents, dest_dump)
 
 

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/svntest/actions.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/svntest/actions.py Wed Sep 12 13:57:35 2012
@@ -448,7 +448,8 @@ class LogEntry:
       self.revprops = revprops
 
   def assert_changed_paths(self, changed_paths):
-    """Not implemented, so just raises svntest.Failure.
+    """Assert that changed_paths is the same as this entry's changed_paths
+    Raises svntest.Failure if not.
     """
     raise Failure('NOT IMPLEMENTED')
 
@@ -902,13 +903,21 @@ def run_and_verify_merge2(dir, rev1, rev
   if dry_run and out != out_dry:
     # Due to the way ra_serf works, it's possible that the dry-run and
     # real merge operations did the same thing, but the output came in
-    # a different order.  Let's see if maybe that's the case.
+    # a different order.  Let's see if maybe that's the case by comparing
+    # the outputs as unordered sets rather than as lists.
+    #
+    # This now happens for other RA layers with modern APR because the
+    # hash order now varies.
     #
-    # NOTE:  Would be nice to limit this dance to serf tests only, but...
-    out_copy = out[:]
-    out_dry_copy = out_dry[:]
-    out_copy.sort()
-    out_dry_copy.sort()
+    # The different orders of the real and dry-run merges may cause
+    # the "Merging rX through rY into" lines to be duplicated a
+    # different number of times in the two outputs.  The list-set
+    # conversion removes duplicates so these differences are ignored.
+    # It also removes "U some/path" duplicate lines.  Perhaps we
+    # should avoid that?
+    out_copy = set(out[:])
+    out_dry_copy = set(out_dry[:])
+
     if out_copy != out_dry_copy:
       print("=============================================================")
       print("Merge outputs differ")
@@ -1193,6 +1202,56 @@ def run_and_verify_unquiet_status(wc_dir
     tree.dump_tree_script(actual, wc_dir_name + os.sep)
     raise
 
+def run_and_verify_status_xml(expected_entries = [],
+                              *args):
+  """ Run 'status --xml' with arguments *ARGS.  If successful the output
+  is parsed into an XML document and will be verified by comparing against
+  EXPECTED_ENTRIES.
+  """
+
+  exit_code, output, errput = run_and_verify_svn(None, None, [],
+                                                 'status', '--xml', *args)
+
+  if len(errput) > 0:
+    raise Failure
+
+  doc = parseString(''.join(output))
+  entries = doc.getElementsByTagName('entry')
+
+  def getText(nodelist):
+    rc = []
+    for node in nodelist:
+        if node.nodeType == node.TEXT_NODE:
+            rc.append(node.data)
+    return ''.join(rc)
+
+  actual_entries = {}
+  for entry in entries:
+    wcstatus = entry.getElementsByTagName('wc-status')[0]
+    commit = entry.getElementsByTagName('commit')
+    author = entry.getElementsByTagName('author')
+    rstatus = entry.getElementsByTagName('repos-status')
+
+    actual_entry = {'wcprops' : wcstatus.getAttribute('props'),
+                    'wcitem' : wcstatus.getAttribute('item'),
+                    }
+    if wcstatus.hasAttribute('revision'):
+      actual_entry['wcrev'] = wcstatus.getAttribute('revision')
+    if (commit):
+      actual_entry['crev'] = commit[0].getAttribute('revision')
+    if (author):
+      actual_entry['author'] = getText(author[0].childNodes)
+    if (rstatus):
+      actual_entry['rprops'] = rstatus[0].getAttribute('props')
+      actual_entry['ritem'] = rstatus[0].getAttribute('item')
+
+    actual_entries[entry.getAttribute('path')] = actual_entry
+
+  if expected_entries != actual_entries:
+    raise Failure('\n' + '\n'.join(difflib.ndiff(
+          pprint.pformat(expected_entries).splitlines(),
+          pprint.pformat(actual_entries).splitlines())))
+
 def run_and_verify_diff_summarize_xml(error_re_string = [],
                                       expected_prefix = None,
                                       expected_paths = [],

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/svntest/verify.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/svntest/verify.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/svntest/verify.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/svntest/verify.py Wed Sep 12 13:57:35 2012
@@ -17,6 +17,8 @@
 ######################################################################
 
 import re, sys
+from difflib import ndiff
+import pprint
 
 import main, tree, wc  # general svntest routines in this module.
 from svntest import Failure
@@ -59,6 +61,10 @@ class SVNIncorrectDatatype(SVNUnexpected
   run_and_verify_* API"""
   pass
 
+class SVNDumpParseError(Failure):
+  """Exception raised if parsing a dump file fails"""
+  pass
+
 
 ######################################################################
 # Comparison of expected vs. actual output
@@ -359,3 +365,195 @@ def verify_exit_code(message, actual, ex
     display_lines(message, "Exit Code",
                   str(expected) + '\n', str(actual) + '\n')
     raise raisable
+
+# A simple dump file parser.  While sufficient for the current
+# testsuite it doesn't cope with all valid dump files.
+class DumpParser:
+  def __init__(self, lines):
+    self.current = 0
+    self.lines = lines
+    self.parsed = {}
+
+  def parse_line(self, regex, required=True):
+    m = re.match(regex, self.lines[self.current])
+    if not m:
+      if required:
+        raise SVNDumpParseError("expected '%s' at line %d\n%s"
+                                % (regex, self.current,
+                                   self.lines[self.current]))
+      else:
+        return None
+    self.current += 1
+    return m.group(1)
+
+  def parse_blank(self, required=True):
+    if self.lines[self.current] != '\n':  # Works on Windows
+      if required:
+        raise SVNDumpParseError("expected blank at line %d\n%s"
+                                % (self.current, self.lines[self.current]))
+      else:
+        return False
+    self.current += 1
+    return True
+
+  def parse_format(self):
+    return self.parse_line('SVN-fs-dump-format-version: ([0-9]+)$')
+
+  def parse_uuid(self):
+    return self.parse_line('UUID: ([0-9a-z-]+)$')
+
+  def parse_revision(self):
+    return self.parse_line('Revision-number: ([0-9]+)$')
+
+  def parse_prop_length(self, required=True):
+    return self.parse_line('Prop-content-length: ([0-9]+)$', required)
+
+  def parse_content_length(self, required=True):
+    return self.parse_line('Content-length: ([0-9]+)$', required)
+
+  def parse_path(self):
+    path = self.parse_line('Node-path: (.+)$', required=False)
+    if not path and self.lines[self.current] == 'Node-path: \n':
+      self.current += 1
+      path = ''
+    return path
+
+  def parse_kind(self):
+    return self.parse_line('Node-kind: (.+)$', required=False)
+
+  def parse_action(self):
+    return self.parse_line('Node-action: ([0-9a-z-]+)$')
+
+  def parse_copyfrom_rev(self):
+    return self.parse_line('Node-copyfrom-rev: ([0-9]+)$', required=False)
+
+  def parse_copyfrom_path(self):
+    path = self.parse_line('Node-copyfrom-path: (.+)$', required=False)
+    if not path and self.lines[self.current] == 'Node-copyfrom-path: \n':
+      self.current += 1
+      path = ''
+    return path
+
+  def parse_copy_md5(self):
+    return self.parse_line('Text-copy-source-md5: ([0-9a-z]+)$', required=False)
+
+  def parse_copy_sha1(self):
+    return self.parse_line('Text-copy-source-sha1: ([0-9a-z]+)$', required=False)
+
+  def parse_text_md5(self):
+    return self.parse_line('Text-content-md5: ([0-9a-z]+)$', required=False)
+
+  def parse_text_sha1(self):
+    return self.parse_line('Text-content-sha1: ([0-9a-z]+)$', required=False)
+
+  def parse_text_length(self):
+    return self.parse_line('Text-content-length: ([0-9]+)$', required=False)
+
+  # One day we may need to parse individual property name/values into a map
+  def get_props(self):
+    props = []
+    while not re.match('PROPS-END$', self.lines[self.current]):
+      props.append(self.lines[self.current])
+      self.current += 1
+    self.current += 1
+    # 1.6 doesn't sort props in dump file output alphabetically,
+    # but the test suite expects this.
+    return props.sort()
+
+  def get_content(self, length):
+    content = ''
+    while len(content) < length:
+      content += self.lines[self.current]
+      self.current += 1
+    if len(content) == length + 1:
+      content = content[:-1]
+    elif len(content) != length:
+      raise SVNDumpParseError("content length expected %d actual %d at line %d"
+                              % (length, len(content), self.current))
+    return content
+
+  def parse_one_node(self):
+    node = {}
+    node['kind'] = self.parse_kind()
+    action = self.parse_action()
+    node['copyfrom_rev'] = self.parse_copyfrom_rev()
+    node['copyfrom_path'] = self.parse_copyfrom_path()
+    node['copy_md5'] = self.parse_copy_md5()
+    node['copy_sha1'] = self.parse_copy_sha1()
+    node['prop_length'] = self.parse_prop_length(required=False)
+    node['text_length'] = self.parse_text_length()
+    node['text_md5'] = self.parse_text_md5()
+    node['text_sha1'] = self.parse_text_sha1()
+    node['content_length'] = self.parse_content_length(required=False)
+    self.parse_blank()
+    if node['prop_length']:
+      node['props'] = self.get_props()
+    if node['text_length']:
+      node['content'] = self.get_content(int(node['text_length']))
+    # Hard to determine how may blanks is 'correct' (a delete that is
+    # followed by an add that is a replace and a copy has one fewer
+    # than expected but that can't be predicted until seeing the add)
+    # so allow arbitrary number
+    blanks = 0
+    while self.current < len(self.lines) and self.parse_blank(required=False):
+      blanks += 1
+    node['blanks'] = blanks
+    return action, node
+
+  def parse_all_nodes(self):
+    nodes = {}
+    while True:
+      if self.current >= len(self.lines):
+        break
+      path = self.parse_path()
+      if not path and not path is '':
+        break
+      if not nodes.get(path):
+        nodes[path] = {}
+      action, node = self.parse_one_node()
+      if nodes[path].get(action):
+        raise SVNDumpParseError("duplicate action '%s' for node '%s' at line %d"
+                                % (action, path, self.current))
+      nodes[path][action] = node
+    return nodes
+
+  def parse_one_revision(self):
+    revision = {}
+    number = self.parse_revision()
+    revision['prop_length'] = self.parse_prop_length()
+    revision['content_length'] = self.parse_content_length()
+    self.parse_blank()
+    revision['props'] = self.get_props()
+    self.parse_blank()
+    revision['nodes'] = self.parse_all_nodes()
+    return number, revision
+
+  def parse_all_revisions(self):
+    while self.current < len(self.lines):
+      number, revision = self.parse_one_revision()
+      if self.parsed.get(number):
+        raise SVNDumpParseError("duplicate revision %d at line %d"
+                                % (number, self.current))
+      self.parsed[number] = revision
+
+  def parse(self):
+    self.parsed['format'] = self.parse_format()
+    self.parse_blank()
+    self.parsed['uuid'] = self.parse_uuid()
+    self.parse_blank()
+    self.parse_all_revisions()
+    return self.parsed
+
+def compare_dump_files(message, label, expected, actual):
+  """Parse two dump files EXPECTED and ACTUAL, both of which are lists
+  of lines as returned by run_and_verify_dump, and check that the same
+  revisions, nodes, properties, etc. are present in both dumps.
+  """
+
+  parsed_expected = DumpParser(expected).parse()
+  parsed_actual = DumpParser(actual).parse()
+
+  if parsed_expected != parsed_actual:
+    raise Failure('\n' + '\n'.join(ndiff(
+          pprint.pformat(parsed_expected).splitlines(),
+          pprint.pformat(parsed_actual).splitlines())))

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/switch_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/switch_tests.py Wed Sep 12 13:57:35 2012
@@ -1541,33 +1541,29 @@ def mergeinfo_switch_elision(sbox):
   beta_path     = os.path.join(wc_dir, "A", "B", "E", "beta")
 
   # Make branches A/B_COPY_1 and A/B_COPY_2
-  svntest.actions.run_and_verify_svn(
-    None,
-    ["A    " + os.path.join(wc_dir, "A", "B_COPY_1", "lambda") + "\n",
+  expected_stdout = svntest.verify.UnorderedOutput([
+     "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "lambda") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "E") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "E", "alpha") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "E", "beta") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_1", "F") + "\n",
      "Checked out revision 1.\n",
-     "A         " + B_COPY_1_path + "\n"],
-    [],
-    'copy',
-    sbox.repo_url + "/A/B",
-    B_COPY_1_path)
-
-  svntest.actions.run_and_verify_svn(
-    None,
-    ["A    " + os.path.join(wc_dir, "A", "B_COPY_2", "lambda") + "\n",
+     "A         " + B_COPY_1_path + "\n",
+    ])
+  svntest.actions.run_and_verify_svn(None, expected_stdout, [], 'copy',
+                                     sbox.repo_url + "/A/B", B_COPY_1_path)
+
+  expected_stdout = svntest.verify.UnorderedOutput([
+     "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "lambda") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "E") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "E", "alpha") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "E", "beta") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY_2", "F") + "\n",
      "Checked out revision 1.\n",
-     "A         " + B_COPY_2_path + "\n"],
-    [],
-    'copy',
-    sbox.repo_url + "/A/B",
-    B_COPY_2_path)
+     "A         " + B_COPY_2_path + "\n",
+    ])
+  svntest.actions.run_and_verify_svn(None, expected_stdout, [], 'copy',
+                                     sbox.repo_url + "/A/B", B_COPY_2_path)
 
   expected_output = svntest.wc.State(wc_dir, {
     'A/B_COPY_1' : Item(verb='Adding'),

Modified: subversion/branches/1.6.x/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x/subversion/tests/cmdline/update_tests.py?rev=1383943&r1=1383942&r2=1383943&view=diff
==============================================================================
--- subversion/branches/1.6.x/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/1.6.x/subversion/tests/cmdline/update_tests.py Wed Sep 12 13:57:35 2012
@@ -1101,6 +1101,7 @@ def another_hudson_problem(sbox):
 
   # Sigh, I can't get run_and_verify_update to work (but not because
   # of issue 919 as far as I can tell)
+  expected_output = svntest.verify.UnorderedOutput(expected_output)
   svntest.actions.run_and_verify_svn(None,
                                      ['D    '+G_path+'\n',
                                       'Updated to revision 3.\n',
@@ -2849,19 +2850,17 @@ def mergeinfo_update_elision(sbox):
   lambda_path = os.path.join(wc_dir, "A", "B", "lambda")
 
   # Make a branch A/B_COPY
-  svntest.actions.run_and_verify_svn(
-    None,
-    ["A    " + os.path.join(wc_dir, "A", "B_COPY", "lambda") + "\n",
+  expected_stdout =  svntest.verify.UnorderedOutput([
+     "A    " + os.path.join(wc_dir, "A", "B_COPY", "lambda") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "E") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "E", "alpha") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "E", "beta") + "\n",
      "A    " + os.path.join(wc_dir, "A", "B_COPY", "F") + "\n",
      "Checked out revision 1.\n",
-     "A         " + B_COPY_path + "\n"],
-    [],
-    'copy',
-    sbox.repo_url + "/A/B",
-    B_COPY_path)
+     "A         " + B_COPY_path + "\n",
+    ])
+  svntest.actions.run_and_verify_svn(None, expected_stdout, [], 'copy',
+                                     sbox.repo_url + "/A/B", B_COPY_path)
 
   expected_output = wc.State(wc_dir, {'A/B_COPY' : Item(verb='Adding')})
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)