Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/lock_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/lock_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/lock_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/lock_tests.py Fri Sep 11 15:51:30 2015 @@ -275,11 +275,11 @@ def steal_lock(sbox): # attempt (and fail) to lock file - # This should give a "iota' is already locked... error, but exits 0. - svntest.actions.run_and_verify_svn2(None, - ".*already locked", 0, - 'lock', - '-m', 'trying to break', file_path_b) + # This should give a "iota' is already locked error + svntest.actions.run_and_verify_svn(None, + ".*already locked", + 'lock', + '-m', 'trying to break', file_path_b) svntest.actions.run_and_verify_svn(".*locked by user", [], 'lock', '--force', @@ -703,11 +703,11 @@ def out_of_date(sbox): '-m', '', file_path) # --- Meanwhile, in our other working copy... --- - svntest.actions.run_and_verify_svn2(None, - ".*newer version of '/iota' exists", 0, - 'lock', - '--username', svntest.main.wc_author2, - '-m', '', file_path_b) + svntest.actions.run_and_verify_svn(None, + ".*newer version of '/iota' exists", + 'lock', + '--username', svntest.main.wc_author2, + '-m', '', file_path_b) #---------------------------------------------------------------------- # Tests reverting a svn:needs-lock file @@ -1164,10 +1164,10 @@ def unlock_already_unlocked_files(sbox): error_msg = ".*Path '/A/B/E/alpha' is already locked by user '" + \ svntest.main.wc_author2 + "'.*" - svntest.actions.run_and_verify_svn2(None, error_msg, 0, - 'lock', - '--username', svntest.main.wc_author2, - alpha_path, gamma_path) + svntest.actions.run_and_verify_svn(None, error_msg, + 'lock', + '--username', svntest.main.wc_author2, + alpha_path, gamma_path) expected_status.tweak('A/D/gamma', writelocked='K') svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1180,11 +1180,11 @@ def unlock_already_unlocked_files(sbox): error_msg = "(.*No lock on path '/A/B/lambda'.*)" + \ "|(.*'A/B/lambda' is not locked.*)" - svntest.actions.run_and_verify_svn2(None, error_msg, 0, - 'unlock', - '--username', svntest.main.wc_author2, - '--force', - iota_path, lambda_path, alpha_path) + svntest.actions.run_and_verify_svn(None, error_msg, + 'unlock', + '--username', svntest.main.wc_author2, + '--force', + iota_path, lambda_path, alpha_path) expected_status.tweak('iota', 'A/B/E/alpha', writelocked=None) @@ -1305,9 +1305,8 @@ def unlock_wrong_token(sbox): # Then, unlocking the WC path should fail. ### The error message returned is actually this, but let's worry about that ### another day... - svntest.actions.run_and_verify_svn2( - None, ".*(No lock on path)", 0, - 'unlock', file_path) + svntest.actions.run_and_verify_svn(None, ".*(No lock on path)", + 'unlock', file_path) #---------------------------------------------------------------------- # Verify that info shows lock info for locked files with URI-unsafe names @@ -1366,10 +1365,10 @@ def unlocked_lock_of_other_user(sbox): else: expected_err = "svn: warning: W160039: User '%s' is trying to use a lock owned by "\ "'%s'.*" % (svntest.main.wc_author2, svntest.main.wc_author) - svntest.actions.run_and_verify_svn2([], expected_err, 0, - 'unlock', - '--username', svntest.main.wc_author2, - pi_path) + svntest.actions.run_and_verify_svn([], expected_err, + 'unlock', + '--username', svntest.main.wc_author2, + pi_path) svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1421,9 +1420,9 @@ def lock_twice_in_one_wc(sbox): svntest.actions.run_and_verify_svn(None, [], 'lock', mu_path, '-m', 'Locked here') - # Locking in location 2 should fail ### Currently returns exitcode 0 - svntest.actions.run_and_verify_svn2(None, ".*is already locked.*", 0, - 'lock', '-m', '', mu2_path) + # Locking in location 2 should fail + svntest.actions.run_and_verify_svn(None, ".*is already locked.*", + 'lock', '-m', '', mu2_path) # Change the file anyway os.chmod(mu2_path, 0700) @@ -1469,8 +1468,8 @@ def lock_path_not_in_head(sbox): # ..\..\..\subversion\libsvn_client\ra.c:275: (apr_err=235000) # svn: In file '..\..\..\subversion\libsvn_ra_serf\util.c' line 1120: # assertion failed (ctx->status_code) - svntest.actions.run_and_verify_svn2(None, expected_lock_fail_err_re, - 0, 'lock', lambda_path) + svntest.actions.run_and_verify_svn(None, expected_lock_fail_err_re, + 'lock', lambda_path) expected_err = 'svn: E155008: The node \'.*D\' is not a file' svntest.actions.run_and_verify_svn(None, expected_err, @@ -1679,8 +1678,8 @@ def block_unlock_if_pre_unlock_hook_fail # Make sure the unlock operation fails as pre-unlock hook blocks it. expected_unlock_fail_err_re = ".*error text" - svntest.actions.run_and_verify_svn2(None, expected_unlock_fail_err_re, - 0, 'unlock', pi_path) + svntest.actions.run_and_verify_svn(None, expected_unlock_fail_err_re, + 'unlock', pi_path) svntest.actions.run_and_verify_status(wc_dir, expected_status) #---------------------------------------------------------------------- @@ -1699,10 +1698,10 @@ def lock_invalid_token(sbox): fname = 'iota' file_path = os.path.join(sbox.wc_dir, fname) - svntest.actions.run_and_verify_svn2(None, - "svn: warning: W160037: " \ - ".*scheme.*'opaquelocktoken'", 0, - 'lock', '-m', '', file_path) + svntest.actions.run_and_verify_svn(None, + "svn: warning: W160037: " \ + ".*scheme.*'opaquelocktoken'", + 'lock', '-m', '', file_path) @Issue(3105) def lock_multi_wc(sbox): @@ -1922,27 +1921,29 @@ def lock_hook_messages(sbox): svntest.actions.create_failing_hook(repo_dir, "pre-lock", error_msg) svntest.actions.create_failing_hook(repo_dir, "pre-unlock", error_msg) - _, _, actual_stderr = svntest.actions.run_and_verify_svn2( - [], svntest.verify.AnyOutput, 0, + _, _, actual_stderr = svntest.actions.run_and_verify_svn( + [], svntest.verify.AnyOutput, 'lock', mu_url) - if len(actual_stderr) > 2: - actual_stderr = actual_stderr[-2:] + if len(actual_stderr) > 4: + actual_stderr = actual_stderr[-4:-2] + actual_stderr[-1:] expected_err = [ 'svn: warning: W165001: ' + svntest.actions.hook_failure_message('pre-lock'), error_msg + "\n", + "svn: E200009: One or more locks could not be obtained\n", ] svntest.verify.compare_and_display_lines(None, 'STDERR', expected_err, actual_stderr) - _, _, actual_stderr = svntest.actions.run_and_verify_svn2( - [], svntest.verify.AnyOutput, 0, + _, _, actual_stderr = svntest.actions.run_and_verify_svn( + [], svntest.verify.AnyOutput, 'unlock', iota_url) - if len(actual_stderr) > 2: - actual_stderr = actual_stderr[-2:] + if len(actual_stderr) > 4: + actual_stderr = actual_stderr[-4:-2] + actual_stderr[-1:] expected_err = [ 'svn: warning: W165001: ' + svntest.actions.hook_failure_message('pre-unlock'), error_msg + "\n", + "svn: E200009: One or more locks could not be released\n", ] svntest.verify.compare_and_display_lines(None, 'STDERR', expected_err, actual_stderr) @@ -2036,15 +2037,15 @@ def dav_lock_timeout(sbox): expiration_date = svntest.actions.run_and_parse_info(sbox.repo_url + '/iota')[0]['Lock Expires'] # Verify that there is a lock, by trying to obtain one - svntest.actions.run_and_verify_svn2(None, ".*locked by user", 0, - 'lock', '-m', '', sbox.ospath('iota')) + svntest.actions.run_and_verify_svn(None, ".*locked by user", + 'lock', '-m', '', sbox.ospath('iota')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('iota', writelocked='O') svntest.actions.run_and_verify_status(wc_dir, expected_status) # This used to fail over serf with a parse error of the timeout. expected_err = "svn: warning: W160039:" - svntest.actions.run_and_verify_svn2(None, expected_err, 0, + svntest.actions.run_and_verify_svn(None, expected_err, 'unlock', sbox.repo_url + '/iota') # Force unlock via working copy, this also used to fail over serf. @@ -2207,27 +2208,27 @@ def many_locks_hooks(sbox): ' sys.exit(1)\n' 'sys.exit(0)\n') - svntest.actions.run_and_verify_svn2(".* locked", - "svn: warning: W165001: .*", 0, - 'lock', - sbox.ospath('iota'), - sbox.ospath('A/mu'), - sbox.ospath('A/B/E/alpha'), - sbox.ospath('A/D/G/pi'), - sbox.ospath('A/D/G/rho')) + svntest.actions.run_and_verify_svn(".* locked", + "svn: warning: W165001: .*", + 'lock', + sbox.ospath('iota'), + sbox.ospath('A/mu'), + sbox.ospath('A/B/E/alpha'), + sbox.ospath('A/D/G/pi'), + sbox.ospath('A/D/G/rho')) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('iota', 'A/mu', 'A/B/E/alpha', 'A/D/G/rho', writelocked='K') svntest.actions.run_and_verify_status(wc_dir, expected_status) - svntest.actions.run_and_verify_svn2(".* unlocked", - "svn: warning: W165001: .*", 0, - 'unlock', - sbox.ospath('iota'), - sbox.ospath('A/mu'), - sbox.ospath('A/B/E/alpha'), - sbox.ospath('A/D/G/rho')) + svntest.actions.run_and_verify_svn(".* unlocked", + "svn: warning: W165001: .*", + 'unlock', + sbox.ospath('iota'), + sbox.ospath('A/mu'), + sbox.ospath('A/B/E/alpha'), + sbox.ospath('A/D/G/rho')) expected_status.tweak('iota', 'A/B/E/alpha', 'A/D/G/rho', writelocked=None)
Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_automatic_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_automatic_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_automatic_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_automatic_tests.py Fri Sep 11 15:51:30 2015 @@ -1327,6 +1327,26 @@ def reintegrate_subtree_not_updated(sbox sbox.simple_commit() sbox.simple_update() +def merge_to_copy_and_add(sbox): + "merge peg to a copy and add" + + sbox.build() + + sbox.simple_copy('A', 'AA') + sbox.simple_append('A/mu', 'A/mu') + sbox.simple_commit('A') + + # This is the scenario the code is supposed to support; a copy + svntest.actions.run_and_verify_svn(None, [], + 'merge', '^/A', sbox.ospath('AA')) + + sbox.simple_mkdir('A3') + # And this case currently segfaults, because merge doesn't check + # if the path has a repository location + expected_err = ".*svn: E195012: Can't perform .*A3'.*added.*" + svntest.actions.run_and_verify_svn(None, expected_err, + 'merge', '^/A', sbox.ospath('A3')) + ######################################################################## # Run the tests @@ -1356,6 +1376,7 @@ test_list = [ None, auto_merge_handles_replacements_in_merge_source, effective_sync_results_in_reintegrate, reintegrate_subtree_not_updated, + merge_to_copy_and_add, ] if __name__ == '__main__': Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_tree_conflict_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_tree_conflict_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/merge_tree_conflict_tests.py Fri Sep 11 15:51:30 2015 @@ -2012,9 +2012,7 @@ def merge_conflict_details(sbox): expected_info = [ { "Path" : re.escape(sbox.ospath('B')), - - "Conflict Properties File" : - re.escape(sbox.ospath('B/dir_conflicts.prej')) + '.*', + "Conflicted Properties" : "key", "Conflict Details": re.escape( 'incoming dir edit upon merge' + ' Source left: (dir) ^/A/B@1' + @@ -2124,18 +2122,16 @@ def merge_obstruction_recording(sbox): }) expected_mergeinfo_output = wc.State(wc_dir, { '' : Item(status=' U'), - 'dir' : Item(status=' U'), # Because dir already exists }) expected_elision_output = wc.State(wc_dir, { }) expected_disk = wc.State('', { 'dir/file.txt' : Item(contents="The file on branch\n"), - 'dir' : Item(props={'svn:mergeinfo':''}), '.' : Item(props={'svn:mergeinfo':'/trunk:2-4'}), }) expected_status = wc.State(wc_dir, { '' : Item(status=' M', wc_rev='4'), - 'dir' : Item(status=' M', treeconflict='C', wc_rev='4'), + 'dir' : Item(status=' ', treeconflict='C', wc_rev='4'), 'dir/file.txt' : Item(status=' ', wc_rev='4'), }) expected_skip = wc.State('', { @@ -2172,7 +2168,7 @@ def merge_obstruction_recording(sbox): expected_output = [ '--- Recording mergeinfo for merge of r4 into \'%s\':\n' % \ sbox.ospath('dir'), - ' G %s\n' % sbox.ospath('dir'), + ' U %s\n' % sbox.ospath('dir'), ] # ### Why are r1-r3 not recorded? # ### Guess: Because dir's history only exists since r4. Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/mergeinfo_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/mergeinfo_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/mergeinfo_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/mergeinfo_tests.py Fri Sep 11 15:51:30 2015 @@ -786,6 +786,166 @@ def mergeinfo_local_move(sbox): 'mergeinfo', sbox.repo_url + '/A', sbox.ospath('A2')) +@SkipUnless(server_has_mergeinfo) +@Issue(4582) +def no_mergeinfo_on_tree_conflict_victim(sbox): + "do not record mergeinfo on tree conflict victims" + sbox.build() + + # Create a branch of A called A_copy + sbox.simple_copy('A', 'A_copy') + sbox.simple_commit() + + # Add a new directory and file on both branches + sbox.simple_mkdir('A/dir') + sbox.simple_add_text('new file', 'A/dir/f') + sbox.simple_commit() + + sbox.simple_mkdir('A_copy/dir') + sbox.simple_add_text('new file', 'A_copy/dir/f') + sbox.simple_commit() + + # Run a merge from A to A_copy + expected_output = wc.State(sbox.ospath('A_copy'), { + 'dir' : Item(status=' ', treeconflict='C'), + 'dir/f' : Item(status=' ', treeconflict='A'), + }) + expected_mergeinfo_output = wc.State(sbox.ospath('A_copy'), { + '' : Item(status=' U'), + }) + expected_elision_output = wc.State(sbox.ospath('A_copy'), { + }) + + expected_disk = svntest.wc.State('', { + 'C' : Item(), + 'B/E/beta' : Item(contents="This is the file 'beta'.\n"), + 'B/E/alpha' : Item(contents="This is the file 'alpha'.\n"), + 'B/lambda' : Item(contents="This is the file 'lambda'.\n"), + 'B/F' : Item(), + 'D/H/omega' : Item(contents="This is the file 'omega'.\n"), + 'D/H/psi' : Item(contents="This is the file 'psi'.\n"), + 'D/H/chi' : Item(contents="This is the file 'chi'.\n"), + 'D/G/tau' : Item(contents="This is the file 'tau'.\n"), + 'D/G/pi' : Item(contents="This is the file 'pi'.\n"), + 'D/G/rho' : Item(contents="This is the file 'rho'.\n"), + 'D/gamma' : Item(contents="This is the file 'gamma'.\n"), + 'dir/f' : Item(contents="new file"), + 'mu' : Item(contents="This is the file 'mu'.\n"), + }) + + # The merge will create an add vs add tree conflict on A_copy/dir + expected_status = svntest.wc.State(sbox.ospath('A_copy'), { + '' : Item(status=' M', wc_rev='4'), + 'D' : Item(status=' ', wc_rev='4'), + 'D/G' : Item(status=' ', wc_rev='4'), + 'D/G/pi' : Item(status=' ', wc_rev='4'), + 'D/G/rho' : Item(status=' ', wc_rev='4'), + 'D/G/tau' : Item(status=' ', wc_rev='4'), + 'D/H' : Item(status=' ', wc_rev='4'), + 'D/H/psi' : Item(status=' ', wc_rev='4'), + 'D/H/omega' : Item(status=' ', wc_rev='4'), + 'D/H/chi' : Item(status=' ', wc_rev='4'), + 'D/gamma' : Item(status=' ', wc_rev='4'), + 'B' : Item(status=' ', wc_rev='4'), + 'B/F' : Item(status=' ', wc_rev='4'), + 'B/E' : Item(status=' ', wc_rev='4'), + 'B/E/alpha' : Item(status=' ', wc_rev='4'), + 'B/E/beta' : Item(status=' ', wc_rev='4'), + 'B/lambda' : Item(status=' ', wc_rev='4'), + 'C' : Item(status=' ', wc_rev='4'), + 'dir' : Item(status=' ', treeconflict='C', wc_rev='4'), + 'dir/f' : Item(status=' ', wc_rev='4'), + 'mu' : Item(status=' ', wc_rev='4'), + }) + + expected_skip = wc.State('', { }) + + sbox.simple_update('A_copy') + svntest.actions.run_and_verify_merge(sbox.ospath('A_copy'), + None, None, # rev1, rev2 + '^/A', + None, # URL2 + expected_output, + expected_mergeinfo_output, + expected_elision_output, + expected_disk, + expected_status, + expected_skip) + + # Resolve the tree conflict by accepting the working copy state left + # behind by the merge. This preserves the line of history of A_copy/dir, + # which originated on the branch 'A_copy', rather than replacing it with + # Jthe line f history of A/dir which originated on branch 'A' + svntest.actions.run_and_verify_resolve([sbox.ospath('A_copy/dir')], + '--accept', 'working', + sbox.ospath('A_copy/dir')) + sbox.simple_commit('A_copy') + + # Now try to merge the 'A_copy' branch back to 'A" + expected_output = wc.State(sbox.ospath('A'), { + 'dir' : Item(status='R '), # changes line of history of A/dir + 'dir/f' : Item(status='A '), + }) + expected_mergeinfo_output = wc.State(sbox.ospath('A'), { + '' : Item(status=' U'), + }) + expected_elision_output = wc.State(sbox.ospath('A'), { + }) + + expected_disk = svntest.wc.State('', { + 'C' : Item(), + 'B/E/beta' : Item(contents="This is the file 'beta'.\n"), + 'B/E/alpha' : Item(contents="This is the file 'alpha'.\n"), + 'B/F' : Item(), + 'B/lambda' : Item(contents="This is the file 'lambda'.\n"), + 'D/H/omega' : Item(contents="This is the file 'omega'.\n"), + 'D/H/psi' : Item(contents="This is the file 'psi'.\n"), + 'D/H/chi' : Item(contents="This is the file 'chi'.\n"), + 'D/G/tau' : Item(contents="This is the file 'tau'.\n"), + 'D/G/pi' : Item(contents="This is the file 'pi'.\n"), + 'D/G/rho' : Item(contents="This is the file 'rho'.\n"), + 'D/gamma' : Item(contents="This is the file 'gamma'.\n"), + 'dir/f' : Item(contents="new file"), + 'mu' : Item(contents="This is the file 'mu'.\n"), + }) + + expected_status = svntest.wc.State(sbox.ospath('A'), { + '' : Item(status=' M', wc_rev='5'), + 'dir' : Item(status='R ', copied='+', wc_rev='-'), + 'dir/f' : Item(status=' ', copied='+', wc_rev='-'), + 'D' : Item(status=' ', wc_rev='5'), + 'D/H' : Item(status=' ', wc_rev='5'), + 'D/H/chi' : Item(status=' ', wc_rev='5'), + 'D/H/omega' : Item(status=' ', wc_rev='5'), + 'D/H/psi' : Item(status=' ', wc_rev='5'), + 'D/G' : Item(status=' ', wc_rev='5'), + 'D/G/pi' : Item(status=' ', wc_rev='5'), + 'D/G/rho' : Item(status=' ', wc_rev='5'), + 'D/G/tau' : Item(status=' ', wc_rev='5'), + 'D/gamma' : Item(status=' ', wc_rev='5'), + 'B' : Item(status=' ', wc_rev='5'), + 'B/E' : Item(status=' ', wc_rev='5'), + 'B/E/beta' : Item(status=' ', wc_rev='5'), + 'B/E/alpha' : Item(status=' ', wc_rev='5'), + 'B/lambda' : Item(status=' ', wc_rev='5'), + 'B/F' : Item(status=' ', wc_rev='5'), + 'mu' : Item(status=' ', wc_rev='5'), + 'C' : Item(status=' ', wc_rev='5'), + }) + + expected_skip = wc.State('', { }) + sbox.simple_update('A') + svntest.actions.run_and_verify_merge(sbox.ospath('A'), + None, None, # rev1, rev2 + '^/A_copy', + None, # URL2 + expected_output, + expected_mergeinfo_output, + expected_elision_output, + expected_disk, + expected_status, + expected_skip) + sbox.simple_commit('A') ######################################################################## # Run the tests @@ -806,6 +966,7 @@ test_list = [ None, natural_history_is_not_eligible_nor_merged, noninheritable_mergeinfo_not_always_eligible, mergeinfo_local_move, + no_mergeinfo_on_tree_conflict_victim, ] if __name__ == '__main__': Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py Fri Sep 11 15:51:30 2015 @@ -1619,9 +1619,7 @@ def move_conflict_details(sbox): expected_info = [ { "Path" : re.escape(sbox.ospath('B')), - - "Conflict Properties File" : - re.escape(sbox.ospath('B/dir_conflicts.prej')) + '.*', + "Conflicted Properties" : "key", "Conflict Details": re.escape( 'incoming dir edit upon update' + ' Source left: (dir) ^/A/B@1' + Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/patch_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/patch_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/patch_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/patch_tests.py Fri Sep 11 15:51:30 2015 @@ -2996,11 +2996,11 @@ def patch_git_empty_files(sbox): "Index: new\n", "===================================================================\n", "diff --git a/new b/new\n", - "new file mode 10644\n", + "new file mode 100644\n", "Index: iota\n", "===================================================================\n", "diff --git a/iota b/iota\n", - "deleted file mode 10644\n", + "deleted file mode 100644\n", ] svntest.main.file_write(patch_file_path, ''.join(unidiff_patch)) Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/prop_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/prop_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/prop_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/prop_tests.py Fri Sep 11 15:51:30 2015 @@ -2740,11 +2740,8 @@ def dir_prop_conflict_details(sbox): None, expected_status, check_props=True) - - # The conflict properties file line was shown for previous versions, but the - # conflict source urls are new since 1.8. expected_info = { - 'Conflict Properties File' : re.escape(sbox.ospath('A/dir_conflicts.prej')), + 'Conflicted Properties' : 'my-prop', 'Conflict Details': re.escape('incoming dir edit upon update' + ' Source left: (dir) ^/A@1' + ' Source right: (dir) ^/A@2') Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/revert_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/revert_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/revert_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/revert_tests.py Fri Sep 11 15:51:30 2015 @@ -1630,7 +1630,13 @@ def revert_obstructing_wc(sbox): svntest.actions.run_and_verify_svn("Skipped '.*A' -- .*obstruct.*", [], 'revert', '-R', wc_dir) +def revert_moved_dir_partial(sbox): + "partial revert moved_dir" + sbox.build(read_only = True) + + sbox.simple_move('A', 'A_') + svntest.actions.run_and_verify_svn(None, [], 'revert', sbox.ospath('A')) ######################################################################## @@ -1673,6 +1679,7 @@ test_list = [ None, revert_with_unversioned_targets, revert_nonexistent, revert_obstructing_wc, + revert_moved_dir_partial, ] if __name__ == '__main__': Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnadmin_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnadmin_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnadmin_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnadmin_tests.py Fri Sep 11 15:51:30 2015 @@ -249,6 +249,18 @@ def patch_format(repo_dir, shard_size): os.chmod(format_path, 0666) open(format_path, 'wb').write(new_contents) +def is_sharded(repo_dir): + """Return whether the FSFS repository REPO_DIR is sharded.""" + + format_path = os.path.join(repo_dir, "db", "format") + contents = open(format_path, 'rb').read() + + for line in contents.split("\n"): + if line.startswith("layout sharded"): + return True + + return False + def load_and_verify_dumpstream(sbox, expected_stdout, expected_stderr, revs, check_props, dump, *varargs): """Load the array of lines passed in DUMP into the current tests' @@ -589,8 +601,8 @@ def dump_quiet(sbox): sbox.build(create_wc = False) - exit_code, output, errput = svntest.main.run_svnadmin("dump", sbox.repo_dir, - '--quiet') + exit_code, dump, errput = svntest.main.run_svnadmin("dump", sbox.repo_dir, + '--quiet') svntest.verify.compare_and_display_lines( "Output of 'svnadmin dump --quiet' is unexpected.", 'STDERR', [], errput) @@ -1215,7 +1227,7 @@ def fsfs_recover_handle_missing_revs_or_ #---------------------------------------------------------------------- -@Skip(svntest.main.tests_use_prepacakaged_repository) +@Skip(svntest.main.tests_use_prepackaged_repository) def create_in_repo_subdir(sbox): "'svnadmin create /path/to/repo/subdir'" @@ -2000,6 +2012,14 @@ def mergeinfo_race(sbox): "concurrent mergeinfo commits invalidate pred-count" sbox.build() + # This test exercises two commit-time race condition bugs: + # + # (a) metadata corruption when concurrent commits change svn:mergeinfo (issue #4129) + # (b) false positive SVN_ERR_FS_CONFLICT error with httpv1 commits + # https://mail-archives.apache.org/mod_mbox/subversion-dev/201507.mbox/%[email protected]%3E + # + # Both bugs are timing-dependent and might not reproduce 100% of the time. + wc_dir = sbox.wc_dir wc2_dir = sbox.add_wc_path('2') @@ -2046,6 +2066,10 @@ def recover_old_empty(sbox): def verify_keep_going(sbox): "svnadmin verify --keep-going test" + # No support for modifying pack files + if svntest.main.options.fsfs_packing: + raise svntest.Skip('fsfs packing set') + sbox.build(create_wc = False) repo_url = sbox.repo_url B_url = sbox.repo_url + '/B' @@ -2070,8 +2094,6 @@ def verify_keep_going(sbox): exp_out = svntest.verify.RegexListOutput([".*Verified revision 0.", ".*Verified revision 1.", - ".*Error verifying revision 2.", - ".*Error verifying revision 3.", ".*", ".*Summary.*", ".*r2: E160004:.*", @@ -2082,8 +2104,18 @@ def verify_keep_going(sbox): if (svntest.main.fs_has_rep_sharing()): exp_out.insert(0, ".*Verifying.*metadata.*") - exp_err = svntest.verify.RegexListOutput(["svnadmin: E160004:.*", - "svnadmin: E165011:.*"], False) + exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160004:.*", + "svnadmin: E160004:.*", + ".*Error verifying revision 3.", + "svnadmin: E160004:.*", + "svnadmin: E160004:.*", + "svnadmin: E205012:.*"], False) + + if (svntest.main.is_fs_log_addressing()): + exp_err.insert(0, ".*Error verifying repository metadata.") + exp_err.insert(1, "svnadmin: E160004:.*") + if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin verify'.", output, errput, exp_out, exp_err): raise svntest.Failure @@ -2095,12 +2127,19 @@ def verify_keep_going(sbox): exp_out = svntest.verify.RegexListOutput([".*Verifying metadata at revision 0"]) else: exp_out = svntest.verify.RegexListOutput([".*Verified revision 0.", - ".*Verified revision 1.", - ".*Error verifying revision 2."]) + ".*Verified revision 1."]) if (svntest.main.fs_has_rep_sharing()): exp_out.insert(0, ".*Verifying repository metadata.*") - exp_err = svntest.verify.RegexListOutput(["svnadmin: E160004:.*"], False) + if (svntest.main.is_fs_log_addressing()): + exp_err = svntest.verify.RegexListOutput([ + ".*Error verifying repository metadata.", + "svnadmin: E160004:.*"], False) + else: + exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160004:.*", + "svnadmin: E160004:.*"], False) + if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin verify'.", output, errput, exp_out, exp_err): raise svntest.Failure @@ -2110,8 +2149,17 @@ def verify_keep_going(sbox): "--quiet", sbox.repo_dir) + if (svntest.main.is_fs_log_addressing()): + exp_err = svntest.verify.RegexListOutput([ + ".*Error verifying repository metadata.", + "svnadmin: E160004:.*"], False) + else: + exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160004:.*", + "svnadmin: E160004:.*"], False) + if svntest.verify.verify_outputs("Output of 'svnadmin verify' is unexpected.", - None, errput, None, "svnadmin: E160004:.*"): + None, errput, None, exp_err): raise svntest.Failure # Don't leave a corrupt repository @@ -2122,6 +2170,10 @@ def verify_keep_going(sbox): def verify_keep_going_quiet(sbox): "svnadmin verify --keep-going --quiet test" + # No support for modifying pack files + if svntest.main.options.fsfs_packing: + raise svntest.Skip('fsfs packing set') + sbox.build(create_wc = False) repo_url = sbox.repo_url B_url = sbox.repo_url + '/B' @@ -2152,11 +2204,12 @@ def verify_keep_going_quiet(sbox): ".*Error verifying revision 3.", "svnadmin: E160004:.*", "svnadmin: E160004:.*", - "svnadmin: E165011:.*"], False) + "svnadmin: E205012:.*"], False) # Insert another expected error from checksum verification if (svntest.main.is_fs_log_addressing()): - exp_err.insert(0, "svnadmin: E160004:.*") + exp_err.insert(0, ".*Error verifying repository metadata.") + exp_err.insert(1, "svnadmin: E160004:.*") if svntest.verify.verify_outputs( "Unexpected error while running 'svnadmin verify'.", @@ -2171,6 +2224,10 @@ def verify_keep_going_quiet(sbox): def verify_invalid_path_changes(sbox): "detect invalid changed path list entries" + # No support for modifying pack files + if svntest.main.options.fsfs_packing: + raise svntest.Skip('fsfs packing set') + sbox.build(create_wc = False) repo_url = sbox.repo_url @@ -2231,23 +2288,15 @@ def verify_invalid_path_changes(sbox): exp_out = svntest.verify.RegexListOutput([".*Verified revision 0.", ".*Verified revision 1.", - ".*Error verifying revision 2.", ".*Verified revision 3.", - ".*Error verifying revision 4.", ".*Verified revision 5.", - ".*Error verifying revision 6.", ".*Verified revision 7.", ".*Verified revision 8.", ".*Verified revision 9.", - ".*Error verifying revision 10.", ".*Verified revision 11.", - ".*Error verifying revision 12.", ".*Verified revision 13.", - ".*Error verifying revision 14.", ".*Verified revision 15.", - ".*Error verifying revision 16.", ".*Verified revision 17.", - ".*Error verifying revision 18.", ".*Verified revision 19.", ".*", ".*Summary.*", @@ -2268,12 +2317,36 @@ def verify_invalid_path_changes(sbox): ".*r18: E160013:.*"]) if (svntest.main.fs_has_rep_sharing()): exp_out.insert(0, ".*Verifying.*metadata.*") - if svntest.main.is_fs_log_addressing(): - exp_out.insert(1, ".*Verifying.*metadata.*") + if svntest.main.options.fsfs_sharding is not None: + for x in range(0, 19 / svntest.main.options.fsfs_sharding): + exp_out.insert(0, ".*Verifying.*metadata.*") + if svntest.main.is_fs_log_addressing(): + exp_out.insert(0, ".*Verifying.*metadata.*") - exp_err = svntest.verify.RegexListOutput(["svnadmin: E160020:.*", + exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160020:.*", + "svnadmin: E160020:.*", + ".*Error verifying revision 4.", + "svnadmin: E160013:.*", + ".*Error verifying revision 6.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + ".*Error verifying revision 10.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + ".*Error verifying revision 12.", + "svnadmin: E145001:.*", + "svnadmin: E145001:.*", + ".*Error verifying revision 14.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + ".*Error verifying revision 16.", "svnadmin: E145001:.*", - "svnadmin: E160013:.*"], False) + "svnadmin: E145001:.*", + ".*Error verifying revision 18.", + "svnadmin: E160013:.*", + "svnadmin: E160013:.*", + "svnadmin: E205012:.*"], False) if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin verify'.", @@ -2284,14 +2357,19 @@ def verify_invalid_path_changes(sbox): sbox.repo_dir) exp_out = svntest.verify.RegexListOutput([".*Verified revision 0.", - ".*Verified revision 1.", - ".*Error verifying revision 2."]) - exp_err = svntest.verify.RegexListOutput(["svnadmin: E160020:.*"], False) + ".*Verified revision 1."]) + exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160020:.*", + "svnadmin: E160020:.*"], False) if (svntest.main.fs_has_rep_sharing()): exp_out.insert(0, ".*Verifying.*metadata.*") - if svntest.main.is_fs_log_addressing(): - exp_out.insert(1, ".*Verifying.*metadata.*") + if svntest.main.options.fsfs_sharding is not None: + for x in range(0, 19 / svntest.main.options.fsfs_sharding): + exp_out.insert(0, ".*Verifying.*metadata.*") + if svntest.main.is_fs_log_addressing(): + exp_out.insert(0, ".*Verifying.*metadata.*") + if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin verify'.", output, errput, exp_out, exp_err): raise svntest.Failure @@ -2301,8 +2379,13 @@ def verify_invalid_path_changes(sbox): "--quiet", sbox.repo_dir) + exp_out = [] + exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.", + "svnadmin: E160020:.*", + "svnadmin: E160020:.*"], False) + if svntest.verify.verify_outputs("Output of 'svnadmin verify' is unexpected.", - None, errput, None, "svnadmin: E160020:.*"): + output, errput, exp_out, exp_err): raise svntest.Failure # Don't leave a corrupt repository @@ -2342,6 +2425,10 @@ def verify_denormalized_names(sbox): if (svntest.main.fs_has_rep_sharing()): expected_output_regex_list.insert(0, ".*Verifying repository metadata.*") + if svntest.main.options.fsfs_sharding is not None: + for x in range(0, 7 / svntest.main.options.fsfs_sharding): + expected_output_regex_list.insert(0, ".*Verifying.*metadata.*") + if svntest.main.is_fs_log_addressing(): expected_output_regex_list.insert(0, ".* Verifying metadata at revision 0.*") @@ -2656,7 +2743,10 @@ def verify_quickly(sbox): "verify quickly using metadata" sbox.build(create_wc = False) - rev_file = open(fsfs_file(sbox.repo_dir, 'revs', '1'), 'r+b') + if svntest.main.is_fs_type_fsfs(): + rev_file = open(fsfs_file(sbox.repo_dir, 'revs', '1'), 'r+b') + else: + rev_file = open(fsfs_file(sbox.repo_dir, 'revs', 'r1'), 'r+b') # set new contents rev_file.seek(8) @@ -3003,6 +3093,115 @@ def load_no_svndate_r0(sbox): 'proplist', '--revprop', '-r0', sbox.repo_dir) +# This is only supported for FSFS +# The port to FSX is still pending, BDB won't support it. +@SkipUnless(svntest.main.is_fs_type_fsfs) +def hotcopy_read_only(sbox): + "'svnadmin hotcopy' a read-only source repository" + sbox.build() + svntest.main.chmod_tree(sbox.repo_dir, 0, 0222) + + backup_dir, backup_url = sbox.add_repo_path('backup') + exit_code, output, errput = svntest.main.run_svnadmin("hotcopy", + sbox.repo_dir, + backup_dir) + + # r/o repos are hard to clean up. Make it writable again. + svntest.main.chmod_tree(sbox.repo_dir, 0222, 0222) + if errput: + logger.warn("Error: hotcopy failed") + raise SVNUnexpectedStderr(errput) + +@SkipUnless(svntest.main.is_fs_type_fsfs) +@SkipUnless(svntest.main.fs_has_pack) +def fsfs_pack_non_sharded(sbox): + "'svnadmin pack' on a non-sharded repository" + + # Configure two files per shard to trigger packing. + sbox.build(create_wc = False, + minor_version = min(svntest.main.options.server_minor_version,3)) + + # Skip for pre-cooked sharded repositories + if is_sharded(sbox.repo_dir): + raise svntest.Skip('sharded pre-cooked repository') + + svntest.actions.run_and_verify_svnadmin( + None, [], "upgrade", sbox.repo_dir) + svntest.actions.run_and_verify_svnadmin( + ['svnadmin: Warning - this repository is not sharded. Packing has no effect.\n'], + [], "pack", sbox.repo_dir) + +def load_revprops(sbox): + "svnadmin load-revprops" + + sbox.build(create_wc=False, empty=True) + + dump_path = os.path.join(os.path.dirname(sys.argv[0]), + 'svnadmin_tests_data', + 'skeleton_repos.dump') + dump_contents = open(dump_path, 'rb').readlines() + load_and_verify_dumpstream(sbox, None, [], None, False, dump_contents) + + svntest.actions.run_and_verify_svnlook(['Initial setup...\n', '\n'], + [], 'log', '-r1', sbox.repo_dir) + + # After loading the dump, amend one of the log message in the repository. + input_file = sbox.get_tempname() + svntest.main.file_write(input_file, 'Modified log message...\n') + + svntest.actions.run_and_verify_svnadmin([], [], 'setlog', '--bypass-hooks', + '-r1', sbox.repo_dir, input_file) + svntest.actions.run_and_verify_svnlook(['Modified log message...\n', '\n'], + [], 'log', '-r1', sbox.repo_dir) + + # Load the same dump, but with 'svnadmin load-revprops'. Doing so should + # restore the log message to its original state. + svntest.main.run_command_stdin(svntest.main.svnadmin_binary, None, 0, + True, dump_contents, 'load-revprops', + sbox.repo_dir) + + svntest.actions.run_and_verify_svnlook(['Initial setup...\n', '\n'], + [], 'log', '-r1', sbox.repo_dir) + +def dump_revprops(sbox): + "svnadmin dump-revprops" + + sbox.build(create_wc=False) + + # Dump revprops only. + exit_code, dump_contents, errput = \ + svntest.actions.run_and_verify_svnadmin(None, [], "dump-revprops", "-q", + sbox.repo_dir) + + # We expect the dump to contain no path changes + for line in dump_contents: + if line.find("Node-path: ") > -1: + logger.warn("Error: path change found in revprops-only dump.") + raise svntest.Failure + + # Remember the current log message for r1 + exit_code, log_msg, errput = \ + svntest.actions.run_and_verify_svnlook(None, [], 'log', '-r1', + sbox.repo_dir) + + # Now, change the log message in the repository. + input_file = sbox.get_tempname() + svntest.main.file_write(input_file, 'Modified log message...\n') + + svntest.actions.run_and_verify_svnadmin([], [], 'setlog', '--bypass-hooks', + '-r1', sbox.repo_dir, input_file) + svntest.actions.run_and_verify_svnlook(['Modified log message...\n', '\n'], + [], 'log', '-r1', sbox.repo_dir) + + # Load the same dump with 'svnadmin load-revprops'. Doing so should + # restore the log message to its original state. + svntest.main.run_command_stdin(svntest.main.svnadmin_binary, None, 0, + True, dump_contents, 'load-revprops', + sbox.repo_dir) + + svntest.actions.run_and_verify_svnlook(log_msg, [], 'log', '-r1', + sbox.repo_dir) + ######################################################################## # Run the tests @@ -3059,6 +3258,10 @@ test_list = [ None, upgrade, load_txdelta, load_no_svndate_r0, + hotcopy_read_only, + fsfs_pack_non_sharded, + load_revprops, + dump_revprops ] if __name__ == '__main__': Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnmucc_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnmucc_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnmucc_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/svnmucc_tests.py Fri Sep 11 15:51:30 2015 @@ -106,7 +106,9 @@ def basic_svnmucc(sbox): sbox.build() empty_file = sbox.ospath('empty') + file = sbox.ospath('file') svntest.main.file_append(empty_file, '') + svntest.main.file_append(file, 'file') # revision 2 test_svnmucc(sbox.repo_url, @@ -301,6 +303,14 @@ def basic_svnmucc(sbox): 'propsetf', 'testprop', empty_file, 'foo/z.c', 'propsetf', 'testprop', empty_file, 'foo/foo') + # revision 21 + test_svnmucc(sbox.repo_url, + ['M /foo/z.c', + ], #--------- + '-m', 'log msg', + 'propset', 'testprop', 'false', 'foo/z.c', + 'put', file, 'foo/z.c') + # Expected missing revision error xtest_svnmucc(sbox.repo_url, ["svnmucc: E200004: 'a' is not a revision" Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/__init__.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/__init__.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/__init__.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/__init__.py Fri Sep 11 15:51:30 2015 @@ -23,11 +23,11 @@ __all__ = [ ] import sys -if sys.hexversion < 0x2050000: - sys.stderr.write('[SKIPPED] at least Python 2.5 is required\n') +if sys.hexversion < 0x2070000: + sys.stderr.write('[SKIPPED] at least Python 2.7 is required\n') # note: exiting is a bit harsh for a library module, but we really do - # require Python 2.5. this package isn't going to work otherwise. + # require Python 2.7. this package isn't going to work otherwise. # we're skipping this test, not failing, so exit with 0 sys.exit(0) Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/actions.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/actions.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/actions.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/actions.py Fri Sep 11 15:51:30 2015 @@ -249,6 +249,28 @@ def run_and_verify_svnadmin2(expected_st return exit_code, out, err +def run_and_verify_svnfsfs(expected_stdout, + expected_stderr, *varargs): + """Like run_and_verify_svnfsfs2, but the expected exit code is + assumed to be 0 if no output is expected on stderr, and 1 otherwise.""" + + expected_exit = 0 + if expected_stderr is not None and expected_stderr != []: + expected_exit = 1 + return run_and_verify_svnfsfs2(expected_stdout, expected_stderr, + expected_exit, *varargs) + +def run_and_verify_svnfsfs2(expected_stdout, expected_stderr, + expected_exit, *varargs): + """Run svnfsfs command and check its output and exit code.""" + + exit_code, out, err = main.run_svnfsfs(*varargs) + verify.verify_outputs("Unexpected output", out, err, + expected_stdout, expected_stderr) + verify.verify_exit_code("Unexpected return code", exit_code, expected_exit) + return exit_code, out, err + + def run_and_verify_svnversion(wc_dir, trail_url, expected_stdout, expected_stderr, *varargs): """like run_and_verify_svnversion2, but the expected exit code is Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/main.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/main.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/main.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/main.py Fri Sep 11 15:51:30 2015 @@ -881,6 +881,8 @@ def youngest(repos_path): # Chmod recursively on a whole subtree def chmod_tree(path, mode, mask): + """For each node in the OS filesystem tree PATH, subtract MASK from its + permissions and add MODE to them.""" for dirpath, dirs, files in os.walk(path): for name in dirs + files: fullname = os.path.join(dirpath, name) @@ -1414,7 +1416,7 @@ def make_log_msg(): # Functions which check the test configuration # (useful for conditional XFails) -def tests_use_prepacakaged_repository(): +def tests_use_prepackaged_repository(): return options.fsfs_version is not None def tests_verify_dump_load_cross_check(): @@ -1543,6 +1545,12 @@ def is_mod_dav_url_quoting_broken(): return (options.httpd_version in __mod_dav_url_quoting_broken_versions) return None +def is_httpd_authz_provider_enabled(): + if is_ra_type_dav(): + v = options.httpd_version.split('.') + return (v[0] == '2' and int(v[1]) >= 3) or int(v[0]) > 2 + return None + ###################################################################### @@ -1877,14 +1885,48 @@ def _internal_run_tests(test_list, testn return exit_code -def create_default_options(): - """Set the global options to the defaults, as provided by the argument - parser.""" - _parse_options([]) +class AbbreviatedFormatter(logging.Formatter): + """A formatter with abbreviated loglevel indicators in the output. + + Use %(levelshort)s in the format string to get a single character + representing the loglevel.. + """ + + _level_short = { + logging.CRITICAL : 'C', + logging.ERROR : 'E', + logging.WARNING : 'W', + logging.INFO : 'I', + logging.DEBUG : 'D', + logging.NOTSET : '-', + } + def format(self, record): + record.levelshort = self._level_short[record.levelno] + return logging.Formatter.format(self, record) -def _create_parser(): +def _create_parser(usage=None): """Return a parser for our test suite.""" + + global logger + + # Initialize the LOGGER global variable so the option parsing can set + # its loglevel, as appropriate. + logger = logging.getLogger() + + # Did some chucklehead log something before we configured it? If they + # did, then a default handler/formatter would get installed. We want + # to be the one to install the first (and only) handler. + for handler in logger.handlers: + if not isinstance(handler.formatter, AbbreviatedFormatter): + raise Exception('Logging occurred before configuration. Some code' + ' path needs to be fixed. Examine the log output' + ' to find what/where logged something.') + + # Set a sane default log level + if logger.getEffectiveLevel() == logging.NOTSET: + logger.setLevel(logging.WARN) + def set_log_level(option, opt, value, parser, level=None): if level: # called from --verbose @@ -1893,9 +1935,18 @@ def _create_parser(): # called from --set-log-level logger.setLevel(getattr(logging, value, None) or int(value)) - # set up the parser + # Set up the parser. + # If you add new options, consider adding them in + # + # .../build/run_tests.py:main() + # + # and handling them in + # + # .../build/run_tests.py:TestHarness._init_py_tests() + # _default_http_library = 'serf' - usage = 'usage: %prog [options] [<test> ...]' + if usage is None: + usage = 'usage: %prog [options] [<test> ...]' parser = optparse.OptionParser(usage=usage) parser.add_option('-l', '--list', action='store_true', dest='list_tests', help='Print test doc strings instead of running them') @@ -1910,6 +1961,9 @@ def _create_parser(): parser.add_option('-p', '--parallel', action='store_const', const=default_num_threads, dest='parallel', help='Run the tests in parallel') + parser.add_option('--parallel-instances', action='store', + type='int', dest='parallel', + help='Run the given number of tests in parallel') parser.add_option('-c', action='store_true', dest='is_child_process', help='Flag if we are running this python test as a ' + 'child process') @@ -1995,31 +2049,46 @@ def _create_parser(): return parser -def _parse_options(arglist=sys.argv[1:]): +def parse_options(arglist=sys.argv[1:], usage=None): """Parse the arguments in arg_list, and set the global options object with the results""" global options - parser = _create_parser() + parser = _create_parser(usage) (options, args) = parser.parse_args(arglist) - # some sanity checking + # If there are no logging handlers registered yet, then install our + # own with our custom formatter. (anything currently installed *is* + # our handler as tested above, in _create_parser) + if not logger.handlers: + # Now that we have some options, let's get the logger configured before + # doing anything more + if options.log_with_timestamps: + formatter = AbbreviatedFormatter('%(levelshort)s:' + ' [%(asctime)s] %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + else: + formatter = AbbreviatedFormatter('%(levelshort)s: %(message)s') + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter(formatter) + logger.addHandler(handler) + + # Normalize url to have no trailing slash + if options.url: + if options.url[-1:] == '/': + options.test_area_url = options.url[:-1] + else: + options.test_area_url = options.url + + # Some sanity checking if options.fsfs_packing and not options.fsfs_sharding: parser.error("--fsfs-packing requires --fsfs-sharding") - # If you change the below condition then change - # ../../../../build/run_tests.py too. if options.server_minor_version not in range(3, SVN_VER_MINOR+1): parser.error("test harness only supports server minor versions 3-%d" % SVN_VER_MINOR) - if options.url: - if options.url[-1:] == '/': # Normalize url to have no trailing slash - options.test_area_url = options.url[:-1] - else: - options.test_area_url = options.url - # Make sure the server-minor-version matches the fsfs-version parameter. if options.fsfs_version: if options.fsfs_version == 6: @@ -2102,27 +2171,6 @@ def get_issue_details(issue_numbers): return issue_dict -class AbbreviatedFormatter(logging.Formatter): - """A formatter with abbreviated loglevel indicators in the output. - - Use %(levelshort)s in the format string to get a single character - representing the loglevel.. - """ - - _level_short = { - logging.CRITICAL : 'C', - logging.ERROR : 'E', - logging.WARNING : 'W', - logging.INFO : 'I', - logging.DEBUG : 'D', - logging.NOTSET : '-', - } - - def format(self, record): - record.levelshort = self._level_short[record.levelno] - return logging.Formatter.format(self, record) - - # Main func. This is the "entry point" that all the test scripts call # to run their list of tests. # @@ -2133,7 +2181,6 @@ def execute_tests(test_list, serial_only exiting the process. This function can be used when a caller doesn't want the process to die.""" - global logger global pristine_url global pristine_greek_repos_url global svn_binary @@ -2153,42 +2200,13 @@ def execute_tests(test_list, serial_only testnums = [] - # Initialize the LOGGER global variable so the option parsing can set - # its loglevel, as appropriate. - logger = logging.getLogger() - - # Did some chucklehead log something before we configured it? If they - # did, then a default handler/formatter would get installed. We want - # to be the one to install the first (and only) handler. - for handler in logger.handlers: - if not isinstance(handler.formatter, AbbreviatedFormatter): - raise Exception('Logging occurred before configuration. Some code' - ' path needs to be fixed. Examine the log output' - ' to find what/where logged something.') - if not options: # Override which tests to run from the commandline - (parser, args) = _parse_options() + (parser, args) = parse_options() test_selection = args else: parser = _create_parser() - # If there are no handlers registered yet, then install our own with - # our custom formatter. (anything currently installed *is* our handler - # as tested above) - if not logger.handlers: - # Now that we have some options, let's get the logger configured before - # doing anything more - if options.log_with_timestamps: - formatter = AbbreviatedFormatter('%(levelshort)s:' - ' [%(asctime)s] %(message)s', - datefmt='%Y-%m-%d %H:%M:%S') - else: - formatter = AbbreviatedFormatter('%(levelshort)s: %(message)s') - handler = logging.StreamHandler(sys.stdout) - handler.setFormatter(formatter) - logger.addHandler(handler) - # parse the positional arguments (test nums, names) for arg in test_selection: appended = False @@ -2318,25 +2336,29 @@ def execute_tests(test_list, serial_only # We are simply listing the tests so always exit with success. return 0 - # don't run tests in parallel when the tests don't support it or there - # are only a few tests to run. + # don't run tests in parallel when the tests don't support it or + # there are only a few tests to run. + options_parallel = options.parallel if serial_only or len(testnums) < 2: options.parallel = 0 - if not options.is_child_process: - # Build out the default configuration directory - create_config_dir(default_config_dir, - ssl_cert=options.ssl_cert, - ssl_url=options.test_area_url, - http_proxy=options.http_proxy, - exclusive_wc_locks=options.exclusive_wc_locks) - - # Setup the pristine repository - svntest.actions.setup_pristine_greek_repository() - - # Run the tests. - exit_code = _internal_run_tests(test_list, testnums, options.parallel, - options.srcdir, progress_func) + try: + if not options.is_child_process: + # Build out the default configuration directory + create_config_dir(default_config_dir, + ssl_cert=options.ssl_cert, + ssl_url=options.test_area_url, + http_proxy=options.http_proxy, + exclusive_wc_locks=options.exclusive_wc_locks) + + # Setup the pristine repository + svntest.actions.setup_pristine_greek_repository() + + # Run the tests. + exit_code = _internal_run_tests(test_list, testnums, options.parallel, + options.srcdir, progress_func) + finally: + options.parallel = options_parallel # Remove all scratchwork: the 'pristine' repository, greek tree, etc. # This ensures that an 'import' will happen the next time we run. Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/verify.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/verify.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/verify.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/svntest/verify.py Fri Sep 11 15:51:30 2015 @@ -853,7 +853,7 @@ def make_git_diff_header(target_path, re if add: output.extend([ "diff --git a/" + repos_relpath + " b/" + repos_relpath + "\n", - "new file mode 10644\n", + "new file mode 100644\n", ]) if text_changes: output.extend([ @@ -863,7 +863,7 @@ def make_git_diff_header(target_path, re elif delete: output.extend([ "diff --git a/" + repos_relpath + " b/" + repos_relpath + "\n", - "deleted file mode 10644\n", + "deleted file mode 100644\n", ]) if text_changes: output.extend([ Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/upgrade_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/upgrade_tests.py?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/cmdline/upgrade_tests.py (original) +++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/upgrade_tests.py Fri Sep 11 15:51:30 2015 @@ -1480,6 +1480,90 @@ def auto_analyze(sbox): if val != [(1,)]: raise svntest.Failure("analyze failed") +def upgrade_1_0_with_externals(sbox): + "test upgrading 1.0.0 working copy with externals" + + sbox.build(create_wc = False) + replace_sbox_with_tarfile(sbox, 'upgrade_1_0_with_externals.tar.bz2') + + url = sbox.repo_url + + # This is non-canonical by the rules of svn_uri_canonicalize, it gets + # written into the entries file and upgrade has to canonicalize. + non_canonical_url = url[:-1] + '%%%02x' % ord(url[-1]) + xml_entries_relocate(sbox.wc_dir, 'file:///1.0.0/repos', non_canonical_url) + + externals_propval = 'exdir_G ' + sbox.repo_url + '/A/D/G' + '\n' + adm_name = svntest.main.get_admin_name() + dir_props_file = os.path.join(sbox.wc_dir, adm_name, 'dir-props') + svntest.main.file_write(dir_props_file, + ('K 13\n' + 'svn:externals\n' + 'V %d\n' % len(externals_propval)) + + externals_propval + '\nEND\n', 'wb') + + # Attempt to use the working copy, this should give an error + expected_stderr = wc_is_too_old_regex + svntest.actions.run_and_verify_svn(None, expected_stderr, + 'info', sbox.wc_dir) + + + # Now upgrade the working copy + svntest.actions.run_and_verify_svn(None, [], + 'upgrade', sbox.wc_dir) + # And the separate working copy below COPIED or check_format() fails + svntest.actions.run_and_verify_svn(None, [], + 'upgrade', + os.path.join(sbox.wc_dir, 'COPIED', 'G')) + + # Actually check the format number of the upgraded working copy + check_format(sbox, get_current_format()) + + # Now check the contents of the working copy + # #### This working copy is not just a basic tree, + # fix with the right data once we get here + expected_status = svntest.wc.State(sbox.wc_dir, + { + '' : Item(status=' M', wc_rev=7), + 'B' : Item(status=' ', wc_rev='7'), + 'B/mu' : Item(status=' ', wc_rev='7'), + 'B/D' : Item(status=' ', wc_rev='7'), + 'B/D/H' : Item(status=' ', wc_rev='7'), + 'B/D/H/psi' : Item(status=' ', wc_rev='7'), + 'B/D/H/omega' : Item(status=' ', wc_rev='7'), + 'B/D/H/zeta' : Item(status='MM', wc_rev='7'), + 'B/D/H/chi' : Item(status=' ', wc_rev='7'), + 'B/D/gamma' : Item(status=' ', wc_rev='9'), + 'B/D/G' : Item(status=' ', wc_rev='7'), + 'B/D/G/tau' : Item(status=' ', wc_rev='7'), + 'B/D/G/rho' : Item(status=' ', wc_rev='7'), + 'B/D/G/pi' : Item(status=' ', wc_rev='7'), + 'B/B' : Item(status=' ', wc_rev='7'), + 'B/B/lambda' : Item(status=' ', wc_rev='7'), + 'MKDIR' : Item(status='A ', wc_rev='0'), + 'MKDIR/MKDIR' : Item(status='A ', wc_rev='0'), + 'A' : Item(status=' ', wc_rev='7'), + 'A/B' : Item(status=' ', wc_rev='7'), + 'A/B/lambda' : Item(status=' ', wc_rev='7'), + 'A/D' : Item(status=' ', wc_rev='7'), + 'A/D/G' : Item(status=' ', wc_rev='7'), + 'A/D/G/rho' : Item(status=' ', wc_rev='7'), + 'A/D/G/pi' : Item(status=' ', wc_rev='7'), + 'A/D/G/tau' : Item(status=' ', wc_rev='7'), + 'A/D/H' : Item(status=' ', wc_rev='7'), + 'A/D/H/psi' : Item(status=' ', wc_rev='7'), + 'A/D/H/omega' : Item(status=' ', wc_rev='7'), + 'A/D/H/zeta' : Item(status=' ', wc_rev='7'), + 'A/D/H/chi' : Item(status=' ', wc_rev='7'), + 'A/D/gamma' : Item(status=' ', wc_rev='7'), + 'A/mu' : Item(status=' ', wc_rev='7'), + 'iota' : Item(status=' ', wc_rev='7'), + 'COPIED' : Item(status=' ', wc_rev='10'), + 'DELETED' : Item(status='D ', wc_rev='10'), + 'exdir_G' : Item(status='X '), + }) + run_and_verify_status_no_server(sbox.wc_dir, expected_status) + ######################################################################## # Run the tests @@ -1537,6 +1621,7 @@ test_list = [ None, changelist_upgrade_1_6, upgrade_1_7_dir_external, auto_analyze, + upgrade_1_0_with_externals, ] Modified: subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs/fs-test.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs/fs-test.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs/fs-test.c (original) +++ subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs/fs-test.c Fri Sep 11 15:51:30 2015 @@ -5345,20 +5345,20 @@ test_fs_info_format(const svn_test_opts_ int fs_format; svn_version_t *supports_version; svn_version_t v1_5_0 = {1, 5, 0, ""}; - svn_version_t v1_9_0 = {1, 9, 0, ""}; + svn_version_t v1_10_0 = {1, 10, 0, ""}; svn_test_opts_t opts2; svn_boolean_t is_fsx = strcmp(opts->fs_type, "fsx") == 0; opts2 = *opts; - opts2.server_minor_version = is_fsx ? 9 : 5; + opts2.server_minor_version = is_fsx ? 10 : 5; SVN_ERR(svn_test__create_fs(&fs, "test-fs-format-info", &opts2, pool)); SVN_ERR(svn_fs_info_format(&fs_format, &supports_version, fs, pool, pool)); if (is_fsx) { - SVN_TEST_ASSERT(fs_format == 1); - SVN_TEST_ASSERT(svn_ver_equal(supports_version, &v1_9_0)); + SVN_TEST_ASSERT(fs_format == 2); + SVN_TEST_ASSERT(svn_ver_equal(supports_version, &v1_10_0)); } else { Modified: subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c (original) +++ subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c Fri Sep 11 15:51:30 2015 @@ -117,8 +117,9 @@ fuzzing_1_byte_1_rev(const char *repo_na svn_fs_set_warning_func(svn_repos_fs(repos), dont_filter_warnings, NULL); /* This shall detect the corruption and return an error. */ - err = svn_repos_verify_fs3(repos, revision, revision, TRUE, FALSE, FALSE, - NULL, NULL, NULL, NULL, iterpool); + err = svn_repos_verify_fs3(repos, revision, revision, FALSE, FALSE, + NULL, NULL, NULL, NULL, NULL, NULL, + iterpool); /* Case-only changes in checksum digests are not an error. * We allow upper case chars to be used in MD5 checksums in all other Modified: subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c (original) +++ subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c Fri Sep 11 15:51:30 2015 @@ -361,9 +361,10 @@ receive_index(const svn_fs_fs__p2l_entry return SVN_NO_ERROR; } +#define REPO_NAME "test-repo-load-index-test" + static svn_error_t * -load_index_test(const svn_test_opts_t *opts, apr_pool_t *pool, - const char *repo_name, svn_boolean_t keep_going) +load_index(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_repos_t *repos; svn_revnum_t rev; @@ -381,50 +382,38 @@ load_index_test(const svn_test_opts_t *o "pre-1.9 SVN doesn't have FSFS indexes"); /* Create a filesystem */ - SVN_ERR(create_greek_repo(&repos, &rev, opts, repo_name, pool, pool)); + SVN_ERR(create_greek_repo(&repos, &rev, opts, REPO_NAME, pool, pool)); /* Read the original index contents for REV in ENTRIES. */ SVN_ERR(svn_fs_fs__dump_index(svn_repos_fs(repos), rev, receive_index, entries, NULL, NULL, pool)); - /* Replace it with an empty index. - * Note that the API requires at least one entry. Give it a dummy. */ + /* Replace it with an index that declares the whole revision contents as + * "unused". */ + entry = *APR_ARRAY_IDX(entries, entries->nelts-1, svn_fs_fs__p2l_entry_t *); + entry.size += entry.offset; entry.offset = 0; - entry.size = 0; entry.type = SVN_FS_FS__ITEM_TYPE_UNUSED; entry.item.number = SVN_FS_FS__ITEM_INDEX_UNUSED; entry.item.revision = SVN_INVALID_REVNUM; APR_ARRAY_PUSH(alt_entries, svn_fs_fs__p2l_entry_t *) = &entry; SVN_ERR(svn_fs_fs__load_index(svn_repos_fs(repos), rev, alt_entries, pool)); - SVN_TEST_ASSERT_ERROR(svn_repos_verify_fs3(repos, rev, rev, - keep_going, FALSE, FALSE, - NULL, NULL, NULL, NULL, pool), - (keep_going - ? SVN_ERR_REPOS_VERIFY_FAILED - : SVN_ERR_FS_INDEX_CORRUPTION)); + SVN_TEST_ASSERT_ERROR(svn_repos_verify_fs3(repos, rev, rev, FALSE, FALSE, + NULL, NULL, NULL, NULL, NULL, + NULL, pool), + SVN_ERR_FS_INDEX_CORRUPTION); /* Restore the original index. */ SVN_ERR(svn_fs_fs__load_index(svn_repos_fs(repos), rev, entries, pool)); - SVN_ERR(svn_repos_verify_fs3(repos, rev, rev, keep_going, FALSE, FALSE, + SVN_ERR(svn_repos_verify_fs3(repos, rev, rev, FALSE, FALSE, NULL, NULL, NULL, NULL, NULL, NULL, pool)); return SVN_NO_ERROR; } -static svn_error_t * -load_index(const svn_test_opts_t *opts, - apr_pool_t *pool) -{ - return load_index_test(opts, pool, "test-repo-load-index-test", FALSE); -} +#undef REPO_NAME -static svn_error_t * -load_index_keep_going(const svn_test_opts_t *opts, - apr_pool_t *pool) -{ - return load_index_test(opts, pool, "test-repo-load-index-full-test", TRUE); -} /* The test table. */ @@ -440,8 +429,6 @@ static struct svn_test_descriptor_t test "dump the P2L index"), SVN_TEST_OPTS_PASS(load_index, "load the P2L index"), - SVN_TEST_OPTS_PASS(load_index_keep_going, - "load the P2L index (full verification)"), SVN_TEST_NULL }; Propchange: subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_x/ ('svn:mergeinfo' removed) Modified: subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_x/fs-x-pack-test.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_x/fs-x-pack-test.c?rev=1702504&r1=1702503&r2=1702504&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_x/fs-x-pack-test.c (original) +++ subversion/branches/reuse-ra-session/subversion/tests/libsvn_fs_x/fs-x-pack-test.c Fri Sep 11 15:51:30 2015 @@ -25,6 +25,7 @@ #include <apr_pools.h> #include "../svn_test.h" +#include "../../libsvn_fs_x/batch_fsync.h" #include "../../libsvn_fs_x/fs.h" #include "../../libsvn_fs_x/reps.h" @@ -657,8 +658,8 @@ recover_fully_packed(const svn_test_opts /* Now, delete the youngest revprop file, and recover again. This time we want to see an error! */ SVN_ERR(svn_io_remove_file2( - svn_dirent_join_many(pool, REPO_NAME, PATH_REVPROPS_DIR, - apr_psprintf(pool, "%ld/%ld", + svn_dirent_join_many(pool, REPO_NAME, PATH_REVS_DIR, + apr_psprintf(pool, "%ld/p%ld", after_rev / SHARD_SIZE, after_rev), SVN_VA_NULL), @@ -844,6 +845,93 @@ pack_shard_size_one(const svn_test_opts_ #undef SHARD_SIZE #undef MAX_REV /* ------------------------------------------------------------------------ */ +#define REPO_NAME "test-repo-fsx-batch-fsync" +static svn_error_t * +test_batch_fsync(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + const char *abspath; + svn_fs_x__batch_fsync_t *batch; + int i; + + /* Disable this test for non FSX backends because it has no relevance to + * them. */ + if (strcmp(opts->fs_type, "fsx") != 0) + return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, + "this will test FSX repositories only"); + + /* Create an empty working directory and let it be cleaned up by the test + * harness. */ + SVN_ERR(svn_dirent_get_absolute(&abspath, REPO_NAME, pool)); + + SVN_ERR(svn_io_remove_dir2(abspath, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_make_dir_recursively(abspath, pool)); + svn_test_add_dir_cleanup(abspath); + + /* Initialize infrastructure with a pool that lives as long as this + * application. */ + SVN_ERR(svn_fs_x__batch_fsync_init()); + + /* We use and re-use the same batch object throughout this test. */ + SVN_ERR(svn_fs_x__batch_fsync_create(&batch, pool)); + + /* The working directory is new. */ + SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, abspath, pool)); + + /* 1st run: Has to fire up worker threads etc. */ + for (i = 0; i < 10; ++i) + { + apr_file_t *file; + const char *path = svn_dirent_join(abspath, + apr_psprintf(pool, "file%i", i), + pool); + apr_size_t len = strlen(path); + + SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, path, pool)); + SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, path, pool)); + + SVN_ERR(svn_io_file_write(file, path, &len, pool)); + } + + SVN_ERR(svn_fs_x__batch_fsync_run(batch, pool)); + + /* 2nd run: Running a batch must leave the container in an empty, + * re-usable state. Hence, try to re-use it. */ + for (i = 0; i < 10; ++i) + { + apr_file_t *file; + const char *path = svn_dirent_join(abspath, + apr_psprintf(pool, "new%i", i), + pool); + apr_size_t len = strlen(path); + + SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, path, pool)); + SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, path, pool)); + + SVN_ERR(svn_io_file_write(file, path, &len, pool)); + } + + SVN_ERR(svn_fs_x__batch_fsync_run(batch, pool)); + + /* 3rd run: Schedule but don't execute. POOL cleanup shall not fail. */ + for (i = 0; i < 10; ++i) + { + apr_file_t *file; + const char *path = svn_dirent_join(abspath, + apr_psprintf(pool, "another%i", i), + pool); + apr_size_t len = strlen(path); + + SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, path, pool)); + SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, path, pool)); + + SVN_ERR(svn_io_file_write(file, path, &len, pool)); + } + + return SVN_NO_ERROR; +} +#undef REPO_NAME +/* ------------------------------------------------------------------------ */ /* The test table. */ @@ -876,6 +964,8 @@ static struct svn_test_descriptor_t test "test representations container"), SVN_TEST_OPTS_PASS(pack_shard_size_one, "test packing with shard size = 1"), + SVN_TEST_OPTS_PASS(test_batch_fsync, + "test batch fsync"), SVN_TEST_NULL };
