| #!/usr/bin/env python |
| # |
| # prop_tests.py: testing versioned properties |
| # |
| # Subversion is a tool for revision control. |
| # See http://subversion.apache.org for more information. |
| # |
| # ==================================================================== |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| ###################################################################### |
| |
| # General modules |
| import sys, re, os, stat, subprocess, logging |
| |
| logger = logging.getLogger() |
| |
| # Our testing module |
| import svntest |
| |
| from svntest.main import SVN_PROP_MERGEINFO |
| from svntest.main import SVN_PROP_INHERITABLE_IGNORES |
| from svntest import wc |
| |
| # (abbreviation) |
| Skip = svntest.testcase.Skip_deco |
| SkipUnless = svntest.testcase.SkipUnless_deco |
| XFail = svntest.testcase.XFail_deco |
| Issues = svntest.testcase.Issues_deco |
| Issue = svntest.testcase.Issue_deco |
| Wimp = svntest.testcase.Wimp_deco |
| Item = svntest.wc.StateItem |
| |
| def is_non_posix_and_non_windows_os(): |
| """lambda function to skip revprop_change test""" |
| return (not svntest.main.is_posix_os()) and sys.platform != 'win32' |
| |
| # this is global so other test files can use it |
| binary_mime_type_on_text_file_warning = \ |
| "svn: warning:.*is a binary mime-type but file.*looks like text.*" |
| |
| ###################################################################### |
| # Tests |
| |
| #---------------------------------------------------------------------- |
| |
| def make_local_props(sbox): |
| "write/read props in wc only (ps, pl, pdel, pe)" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add properties to one file and one directory |
| sbox.simple_propset('blue', 'azul', 'A/mu') |
| sbox.simple_propset('green', 'verde', 'A/mu') |
| sbox.simple_propset('editme', 'the foo fighters', 'A/mu') |
| sbox.simple_propset('red', 'rojo', 'A/D/G') |
| sbox.simple_propset('yellow', 'amarillo', 'A/D/G') |
| |
| # Make sure they show up as local mods in status |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A/mu', status=' M') |
| expected_status.tweak('A/D/G', status=' M') |
| |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Remove one property |
| sbox.simple_propdel('yellow', 'A/D/G') |
| |
| svntest.main.use_editor('foo_to_bar') |
| # Edit one property |
| svntest.main.run_svn(None, 'propedit', 'editme', |
| os.path.join(wc_dir, 'A', 'mu')) |
| |
| # What we expect the disk tree to look like: |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('A/mu', props={'blue' : 'azul', 'green' : 'verde', |
| 'editme' : 'the bar fighters'}) |
| expected_disk.tweak('A/D/G', props={'red' : 'rojo'}) |
| |
| # Read the real disk tree. Notice we are passing the (normally |
| # disabled) "load props" flag to this routine. This will run 'svn |
| # proplist' on every item in the working copy! |
| svntest.actions.verify_disk(wc_dir, expected_disk, True) |
| |
| # Edit without actually changing the property |
| svntest.main.use_editor('identity') |
| svntest.actions.run_and_verify_svn("No changes to property 'editme' on '.*'", |
| [], |
| 'propedit', 'editme', |
| os.path.join(wc_dir, 'A', 'mu')) |
| |
| |
| |
| #---------------------------------------------------------------------- |
| |
| def commit_props(sbox): |
| "commit properties" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add a property to a file and a directory |
| sbox.simple_propset('blue', 'azul', 'A/mu') |
| sbox.simple_propset('red', 'rojo', 'A/D/H') |
| |
| # Create expected output tree. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A/mu' : Item(verb='Sending'), |
| 'A/D/H' : Item(verb='Sending'), |
| }) |
| |
| # Created expected status tree. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A/mu', 'A/D/H', wc_rev=2, status=' ') |
| |
| # Commit the one file. |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, |
| expected_status) |
| |
| |
| |
| #---------------------------------------------------------------------- |
| |
| @Issue(3951) |
| def update_props(sbox): |
| "receive properties via update" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Make a backup copy of the working copy |
| wc_backup = sbox.add_wc_path('backup') |
| svntest.actions.duplicate_dir(wc_dir, wc_backup) |
| |
| # Add a property to a file and a directory |
| sbox.simple_propset('blue', 'azul', 'A/mu') |
| sbox.simple_propset('red', 'rojo', 'A/D/H') |
| |
| # Create expected output tree. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A/mu' : Item(verb='Sending'), |
| 'A/D/H' : Item(verb='Sending'), |
| }) |
| |
| # Created expected status tree. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A/mu', 'A/D/H', wc_rev=2, status=' ') |
| |
| # Commit property mods |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Add more properties |
| sbox.simple_propset('blue2', 'azul2', 'A/mu') |
| sbox.simple_propset('red2', 'rojo2', 'A/D/H') |
| expected_status.tweak('A/mu', 'A/D/H', wc_rev=3, status=' ') |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Create expected output tree for an update of the wc_backup. |
| expected_output = svntest.wc.State(wc_backup, { |
| 'A/mu' : Item(status=' U'), |
| 'A/D/H' : Item(status=' U'), |
| }) |
| |
| # Create expected disk tree for the update. |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('A/mu', props={'blue' : 'azul'}) |
| expected_disk.tweak('A/D/H', props={'red' : 'rojo'}) |
| |
| # Create expected status tree for the update. |
| expected_status = svntest.actions.get_virginal_state(wc_backup, 2) |
| expected_status.tweak('A/mu', 'A/D/H', status=' ') |
| |
| # Do the update and check the results in three ways... INCLUDING PROPS |
| # This adds properties to nodes that have none |
| svntest.actions.run_and_verify_update(wc_backup, |
| expected_output, |
| expected_disk, |
| expected_status, |
| [], 1, |
| '-r', '2', wc_backup) |
| |
| # This adds properties to nodes that have properties |
| expected_status.tweak(wc_rev=3) |
| expected_disk.tweak('A/mu', props={'blue' : 'azul', |
| 'blue2' : 'azul2'}) |
| expected_disk.tweak('A/D/H', props={'red' : 'rojo', |
| 'red2' : 'rojo2'}) |
| svntest.actions.run_and_verify_update(wc_backup, |
| expected_output, |
| expected_disk, |
| expected_status, |
| [], 1, |
| '-r', '3', wc_backup) |
| |
| |
| #---------------------------------------------------------------------- |
| |
| def downdate_props(sbox): |
| "receive property changes as part of a downdate" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| mu_path = sbox.ospath('A/mu') |
| |
| # Add a property to a file |
| sbox.simple_propset('cash-sound', 'cha-ching!', 'iota') |
| |
| # Create expected output tree. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'iota' : Item(verb='Sending'), |
| }) |
| |
| # Created expected status tree. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('iota', wc_rev=2, status=' ') |
| |
| # Commit the one file. |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Make some mod (something to commit) |
| svntest.main.file_append(mu_path, "some mod") |
| |
| # Create expected output tree. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A/mu' : Item(verb='Sending'), |
| }) |
| |
| # Created expected status tree. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('iota', wc_rev=2, status=' ') |
| expected_status.tweak('A/mu', wc_rev=3, status=' ') |
| |
| # Commit the one file. |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Create expected output tree for an update. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'iota' : Item(status=' U'), |
| 'A/mu' : Item(status='U '), |
| }) |
| |
| # Create expected disk tree for the update. |
| expected_disk = svntest.main.greek_state |
| |
| # Create expected status tree for the update. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| |
| # Do the update and check the results in three ways... INCLUDING PROPS |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| expected_disk, |
| expected_status, |
| [], 1, |
| '-r', '1', wc_dir) |
| |
| #---------------------------------------------------------------------- |
| |
| def remove_props(sbox): |
| "commit the removal of props" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add a property to a file |
| sbox.simple_propset('cash-sound', 'cha-ching!', 'iota') |
| |
| # Commit the file |
| sbox.simple_commit('iota') |
| |
| # Now, remove the property |
| sbox.simple_propdel('cash-sound', 'iota') |
| |
| # Create expected output tree. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'iota' : Item(verb='Sending'), |
| }) |
| |
| # Created expected status tree. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('iota', wc_rev=3, status=' ') |
| |
| # Commit the one file. |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| #---------------------------------------------------------------------- |
| |
| def update_conflict_props(sbox): |
| "update with conflicting props" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add a property to a file and a directory |
| mu_path = sbox.ospath('A/mu') |
| sbox.simple_propset('cash-sound', 'cha-ching!', 'A/mu') |
| A_path = sbox.ospath('A') |
| sbox.simple_propset('foo', 'bar', 'A') |
| |
| # Commit the file and directory |
| sbox.simple_commit() |
| |
| # Update to rev 1 |
| svntest.main.run_svn(None, 'up', '-r', '1', wc_dir) |
| |
| # Add conflicting properties |
| sbox.simple_propset('cash-sound', 'beep!', 'A/mu') |
| sbox.simple_propset('foo', 'baz', 'A') |
| |
| # Create expected output tree for an update of the wc_backup. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A/mu' : Item(status=' C'), |
| 'A' : Item(status=' C'), |
| }) |
| |
| # Create expected disk tree for the update. |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('A/mu', props={'cash-sound' : 'beep!'}) |
| expected_disk.tweak('A', props={'foo' : 'baz'}) |
| |
| # Create expected status tree for the update. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 2) |
| expected_status.tweak('A/mu', 'A', status=' C') |
| |
| extra_files = ['mu.*\.prej', 'dir_conflicts.*\.prej'] |
| # Do the update and check the results in three ways... INCLUDING PROPS |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| expected_disk, |
| expected_status, |
| check_props=True, |
| extra_files=extra_files) |
| |
| # Resolve the conflicts |
| svntest.actions.run_and_verify_resolved([mu_path, A_path]) |
| |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 2) |
| expected_status.tweak('A/mu', 'A', status=' M') |
| |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| #---------------------------------------------------------------------- |
| @Issue(2608) |
| def commit_conflict_dirprops(sbox): |
| "commit with conflicting dirprops" |
| |
| # Issue #2608: failure to see conflicting dirprops on root of |
| # repository. |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| sbox.simple_propset('foo', 'bar', '') |
| |
| # Commit the file and directory |
| sbox.simple_commit() |
| |
| # Update to rev 1 |
| svntest.main.run_svn(None, |
| 'up', '-r', '1', wc_dir) |
| |
| # Add conflicting properties |
| sbox.simple_propset('foo', 'eek', '') |
| |
| svntest.actions.run_and_verify_commit(wc_dir, None, None, |
| ".*[oO]ut[- ]of[- ]date.*") |
| |
| #---------------------------------------------------------------------- |
| |
| # Issue #742: we used to screw up when committing a file replacement |
| # that also had properties. It was fixed by teaching |
| # svn_wc_props_modified_p and svn_wc_transmit_prop_deltas to *ignore* |
| # leftover base-props when a file is scheduled for replacement. (When |
| # we svn_wc_add a file, it starts life with no working props.) |
| @Issue(742) |
| def commit_replacement_props(sbox): |
| "props work when committing a replacement" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add a property to two files |
| iota_path = sbox.ospath('iota') |
| lambda_path = sbox.ospath('A/B/lambda') |
| sbox.simple_propset('cash-sound', 'cha-ching!', 'iota') |
| sbox.simple_propset('boson', 'W', 'A/B/lambda') |
| |
| # Commit (### someday use run_and_verify_commit for better coverage) |
| sbox.simple_commit() |
| |
| # Schedule both files for deletion |
| sbox.simple_rm('iota', 'A/B/lambda') |
| |
| # Now recreate the files, and schedule them for addition. |
| # Poof, the 'new' files don't have any properties at birth. |
| svntest.main.file_append(iota_path, 'iota TNG') |
| svntest.main.file_append(lambda_path, 'lambda TNG') |
| sbox.simple_add('iota', 'A/B/lambda') |
| |
| # Sanity check: the two files should be scheduled for (R)eplacement. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('iota', wc_rev=2, status='R ') |
| expected_status.tweak('A/B/lambda', wc_rev=2, status='R ') |
| |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Now add a property to lambda. Iota still doesn't have any. |
| sbox.simple_propset('capacitor', 'flux', 'A/B/lambda') |
| |
| # Commit, with careful output checking. We're actually going to |
| # scan the working copy for props after the commit. |
| |
| expected_output = svntest.wc.State(wc_dir, { |
| 'iota' : Item(verb='Replacing'), |
| 'A/B/lambda' : Item(verb='Replacing'), |
| }) |
| |
| # Expected status tree: lambda has one prop, iota doesn't. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('iota', wc_rev=3) |
| expected_status.tweak('A/B/lambda', wc_rev=3, status=' ') |
| |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| #---------------------------------------------------------------------- |
| |
| def revert_replacement_props(sbox): |
| "props work when reverting a replacement" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add a property to two files |
| iota_path = sbox.ospath('iota') |
| lambda_path = sbox.ospath('A/B/lambda') |
| sbox.simple_propset('cash-sound', 'cha-ching!', 'iota') |
| sbox.simple_propset('boson', 'W', 'A/B/lambda') |
| |
| # Commit rev 2. (### someday use run_and_verify_commit for better coverage) |
| sbox.simple_commit() |
| |
| # Schedule both files for deletion |
| sbox.simple_rm('iota', 'A/B/lambda') |
| |
| # Now recreate the files, and schedule them for addition. |
| # Poof, the 'new' files don't have any properties at birth. |
| svntest.main.file_append(iota_path, 'iota TNG') |
| svntest.main.file_append(lambda_path, 'lambda TNG') |
| sbox.simple_add('iota', 'A/B/lambda') |
| |
| # Sanity check: the two files should be scheduled for (R)eplacement. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('iota', wc_rev=2, status='R ') |
| expected_status.tweak('A/B/lambda', wc_rev=2, status='R ') |
| |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Now add a property to lambda. Iota still doesn't have any. |
| sbox.simple_propset('capacitor', 'flux', 'A/B/lambda') |
| |
| # Now revert both files. |
| sbox.simple_revert('iota', 'A/B/lambda') |
| |
| # Do an update; even though the update is really a no-op, |
| # run_and_verify_update has the nice feature of scanning disk as |
| # well as running status. We want to verify that we truly have a |
| # *pristine* revision 2 tree, with the original rev 2 props, and no |
| # local mods at all. |
| |
| expected_output = svntest.wc.State(wc_dir, { |
| }) |
| |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 2) |
| expected_status.tweak('iota', status=' ') |
| expected_status.tweak('A/B/lambda', status=' ') |
| |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('iota', props={'cash-sound' : 'cha-ching!'}) |
| expected_disk.tweak('A/B/lambda', props={'boson' : 'W'}) |
| |
| # scan disk for props too. |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| expected_disk, |
| expected_status, |
| check_props=True) |
| |
| #---------------------------------------------------------------------- |
| @Issues(920,2065) |
| def inappropriate_props(sbox): |
| "try to set inappropriate props" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| A_path = sbox.ospath('A') |
| E_path = sbox.ospath('A/B/E') |
| iota_path = sbox.ospath('iota') |
| |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # These should produce an error |
| svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, |
| 'propset', 'svn:executable', 'on', A_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:keywords', 'LastChangedDate', |
| A_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:eol-style', 'native', A_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:eol-style', 'invalid value', |
| os.path.join(A_path, 'mu')) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:mime-type', 'image/png', A_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:ignore', '*.o', iota_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:externals', |
| 'foo http://host.com/repos', iota_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:author', 'socrates', iota_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:log', 'log message', iota_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:date', 'Tue Jan 19 04:14:07 2038', |
| iota_path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, 'propset', |
| 'svn:original-date', |
| 'Thu Jan 1 01:00:00 1970', iota_path) |
| |
| # Status unchanged |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Recursive setting of inappropriate dir prop should work on files |
| svntest.actions.run_and_verify_svn(None, [], 'propset', '-R', |
| 'svn:executable', 'on', E_path) |
| |
| expected_status.tweak('A/B/E/alpha', 'A/B/E/beta', status=' M') |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Issue #920. Don't allow setting of svn:eol-style on binary files or files |
| # with inconsistent eol types. |
| |
| path = sbox.ospath('binary') |
| svntest.main.file_append(path, "binary") |
| sbox.simple_add('binary') |
| |
| svntest.main.run_svn(binary_mime_type_on_text_file_warning, |
| 'propset', 'svn:mime-type', 'application/octet-stream', |
| sbox.ospath('binary')) |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, |
| 'propset', 'svn:eol-style', |
| 'CRLF', path) |
| |
| path = sbox.ospath('multi-eol') |
| svntest.main.file_append(path, "line1\rline2\n") |
| sbox.simple_add('multi-eol') |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, |
| 'propset', 'svn:eol-style', |
| 'LF', path) |
| |
| path = sbox.ospath('backwards-eol') |
| svntest.main.file_append(path, "line1\n\r") |
| sbox.simple_add('backwards-eol') |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, |
| 'propset', 'svn:eol-style', |
| 'native', path) |
| |
| path = sbox.ospath('incomplete-eol') |
| svntest.main.file_append(path, "line1\r\n\r") |
| sbox.simple_add('incomplete-eol') |
| |
| svntest.actions.run_and_verify_svn(None, |
| svntest.verify.AnyOutput, |
| 'propset', 'svn:eol-style', |
| 'CR', path) |
| |
| # Issue #2065. Do allow setting of svn:eol-style on binary files or files |
| # with inconsistent eol types if --force is passed. |
| |
| path = sbox.ospath('binary') |
| svntest.main.file_append(path, "binary") |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--force', |
| 'svn:eol-style', 'CRLF', |
| path) |
| |
| path = sbox.ospath('multi-eol') |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--force', |
| 'svn:eol-style', 'LF', |
| path) |
| |
| path = sbox.ospath('backwards-eol') |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--force', |
| 'svn:eol-style', 'native', |
| path) |
| |
| path = sbox.ospath('incomplete-eol') |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--force', |
| 'svn:eol-style', 'CR', |
| path) |
| |
| # Prevent setting of svn:mergeinfo prop values that are... |
| path = sbox.ospath('A/D') |
| |
| # ...grammatically incorrect |
| svntest.actions.run_and_verify_svn(None, |
| "svn: E200020: Pathname not terminated by ':'\n", |
| 'propset', SVN_PROP_MERGEINFO, '/trunk', |
| path) |
| svntest.actions.run_and_verify_svn(None, |
| "svn: E200022: Invalid revision number found " |
| "parsing 'one'\n", |
| 'propset', SVN_PROP_MERGEINFO, |
| '/trunk:one', path) |
| |
| # ...contain overlapping revision ranges of differing inheritability. |
| svntest.actions.run_and_verify_svn(None, |
| "svn: E200020: Unable to parse overlapping " |
| "revision ranges '9-20\\*' and " |
| "'18-22' with different " |
| "inheritance types\n", |
| 'propset', SVN_PROP_MERGEINFO, |
| '/branch:5-7,9-20*,18-22', path) |
| |
| svntest.actions.run_and_verify_svn(None, |
| "svn: E200020: Unable to parse overlapping " |
| "revision ranges " |
| "(('3' and '3\\*')|('3\\*' and '3')) " |
| "with different " |
| "inheritance types\n", |
| 'propset', SVN_PROP_MERGEINFO, |
| '/branch:3,3*', path) |
| |
| # ...contain revision ranges with start revisions greater than or |
| # equal to end revisions. |
| svntest.actions.run_and_verify_svn(None, |
| "svn: E200020: Unable to parse reversed " |
| "revision range '20-5'\n", |
| 'propset', SVN_PROP_MERGEINFO, |
| '/featureX:4,20-5', path) |
| |
| # ...contain paths mapped to empty revision ranges |
| svntest.actions.run_and_verify_svn(None, |
| "svn: E200020: Mergeinfo for '/trunk' maps to " |
| "an empty revision range\n", |
| 'propset', SVN_PROP_MERGEINFO, |
| '/trunk:', path) |
| |
| # ...contain non-inheritable ranges when the target is a file. |
| svntest.actions.run_and_verify_svn(None, |
| "svn: E200020: Cannot set non-inheritable " |
| "mergeinfo on a non-directory*", |
| 'propset', SVN_PROP_MERGEINFO, |
| '/A/D/H/psi:1*', iota_path) |
| |
| #---------------------------------------------------------------------- |
| |
| # Issue #976. When copying a file, do not determine svn:executable |
| # and svn:mime-type values as though the file is brand new, instead |
| # use the copied file's property values. |
| @Issue(976) |
| def copy_inherits_special_props(sbox): |
| "file copies inherit (not re-derive) special props" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| orig_mime_type = 'image/fake_image' |
| |
| # Create two paths |
| new_path1 = sbox.ospath('new_file1.bin') |
| new_path2 = sbox.ospath('new_file2.bin') |
| |
| # Create the first path as a binary file. To have svn treat the |
| # file as binary, have a 0x00 in the file. |
| svntest.main.file_append(new_path1, "binary file\000") |
| sbox.simple_add('new_file1.bin') |
| |
| # Add initial svn:mime-type to the file |
| sbox.simple_propset('svn:mime-type', orig_mime_type, 'new_file1.bin') |
| |
| # Set the svn:executable property on the file if this is a system |
| # that can handle chmod, in which case svn will turn on the |
| # executable bits on the file. Then remove the executable bits |
| # manually on the file and see the value of svn:executable in the |
| # copied file. |
| if os.name == 'posix': |
| sbox.simple_propset('svn:executable', 'on', 'new_file1.bin') |
| os.chmod(new_path1, svntest.main.S_ALL_READ | stat.S_IWUSR) |
| |
| # Commit the file |
| sbox.simple_commit() |
| |
| # Copy the file |
| svntest.main.run_svn(None, 'cp', new_path1, new_path2) |
| |
| # Check the svn:mime-type |
| actual_exit, actual_stdout, actual_stderr = svntest.main.run_svn( |
| None, 'pg', 'svn:mime-type', new_path2) |
| |
| expected_stdout = [orig_mime_type + '\n'] |
| if actual_stdout != expected_stdout: |
| logger.warn("svn pg svn:mime-type output does not match expected.") |
| logger.warn("Expected standard output: %s\n", expected_stdout) |
| logger.warn("Actual standard output: %s\n", actual_stdout) |
| raise svntest.verify.SVNUnexpectedOutput |
| |
| # Check the svn:executable value. |
| # The value of the svn:executable property is now always forced to '*' |
| if os.name == 'posix': |
| actual_exit, actual_stdout, actual_stderr = svntest.main.run_svn( |
| None, 'pg', 'svn:executable', new_path2) |
| |
| expected_stdout = ['*\n'] |
| if actual_stdout != expected_stdout: |
| logger.warn("svn pg svn:executable output does not match expected.") |
| logger.warn("Expected standard output: %s\n", expected_stdout) |
| logger.warn("Actual standard output: %s\n", actual_stdout) |
| raise svntest.verify.SVNUnexpectedOutput |
| |
| #---------------------------------------------------------------------- |
| # Test for issue #3086 'mod-dav-svn ignores pre-revprop-change failure |
| # on revprop delete' |
| # |
| # If we learn how to write a pre-revprop-change hook for |
| # non-Posix platforms, we won't have to skip here: |
| @Skip(is_non_posix_and_non_windows_os) |
| @Issue(3086) |
| def revprop_change(sbox): |
| "set, get, and delete a revprop change" |
| |
| sbox.build() |
| |
| # First test the error when no revprop-change hook exists. |
| svntest.actions.run_and_verify_svn(None, '.*pre-revprop-change', |
| 'propset', '--revprop', '-r', '0', |
| 'cash-sound', 'cha-ching!', sbox.wc_dir) |
| |
| # Now test error output from revprop-change hook. |
| svntest.actions.disable_revprop_changes(sbox.repo_dir) |
| svntest.actions.run_and_verify_svn(None, '.*pre-revprop-change.* 0 jrandom cash-sound A', |
| 'propset', '--revprop', '-r', '0', |
| 'cash-sound', 'cha-ching!', sbox.wc_dir) |
| |
| # Create the revprop-change hook for this test |
| svntest.actions.enable_revprop_changes(sbox.repo_dir) |
| |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--revprop', '-r', '0', |
| 'cash-sound', 'cha-ching!', sbox.wc_dir) |
| |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propget', '--revprop', '-r', '0', |
| 'cash-sound', sbox.wc_dir) |
| |
| # Now test that blocking the revprop delete. |
| svntest.actions.disable_revprop_changes(sbox.repo_dir) |
| svntest.actions.run_and_verify_svn(None, '.*pre-revprop-change.* 0 jrandom cash-sound D', |
| 'propdel', '--revprop', '-r', '0', |
| 'cash-sound', sbox.wc_dir) |
| |
| # Now test actually deleting the revprop. |
| svntest.actions.enable_revprop_changes(sbox.repo_dir) |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propdel', '--revprop', '-r', '0', |
| 'cash-sound', sbox.wc_dir) |
| |
| # The property should have been deleted. |
| svntest.actions.run_and_verify_svn(None, |
| '.*(E195011|E200017).*cash-sound.*', |
| 'propget', '--revprop', '-r', '0', 'cash-sound', sbox.wc_dir) |
| |
| |
| #---------------------------------------------------------------------- |
| |
| def prop_value_conversions(sbox): |
| "some svn: properties should be converted" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| A_path = sbox.ospath('A') |
| B_path = sbox.ospath('A/B') |
| iota_path = sbox.ospath('iota') |
| lambda_path = sbox.ospath('A/B/lambda') |
| mu_path = sbox.ospath('A/mu') |
| |
| # Leading and trailing whitespace should be stripped |
| svntest.actions.set_prop('svn:mime-type', ' text/html\n\n', iota_path) |
| svntest.actions.set_prop('svn:mime-type', 'text/html', mu_path) |
| |
| # Leading and trailing whitespace should be stripped |
| svntest.actions.set_prop('svn:eol-style', '\nnative\n', iota_path) |
| svntest.actions.set_prop('svn:eol-style', 'native', mu_path) |
| |
| # A trailing newline should be added |
| svntest.actions.set_prop('svn:ignore', '*.o\nfoo.c', A_path) |
| svntest.actions.set_prop('svn:ignore', '*.o\nfoo.c\n', B_path) |
| |
| # A trailing newline should be added |
| svntest.actions.set_prop('svn:externals', 'foo http://foo.com/repos', A_path) |
| svntest.actions.set_prop('svn:externals', 'foo http://foo.com/repos\n', B_path) |
| |
| # Leading and trailing whitespace should be stripped, but not internal |
| # whitespace |
| svntest.actions.set_prop('svn:keywords', ' Rev Date \n', iota_path) |
| svntest.actions.set_prop('svn:keywords', 'Rev Date', mu_path) |
| |
| # svn:executable value should be forced to a '*' |
| svntest.actions.set_prop('svn:executable', 'foo', iota_path) |
| svntest.actions.set_prop('svn:executable', '*', lambda_path) |
| for pval in (' ', '', 'no', 'off', 'false'): |
| svntest.actions.set_prop('svn:executable', pval, mu_path, |
| "svn: warning: W125005.*use 'svn propdel'") |
| |
| # Anything else should be untouched |
| svntest.actions.set_prop('svn:some-prop', 'bar', lambda_path, force=True) |
| svntest.actions.set_prop('svn:some-prop', ' bar baz', mu_path, force=True) |
| svntest.actions.set_prop('svn:some-prop', 'bar\n', iota_path, force=True) |
| svntest.actions.set_prop('some-prop', 'bar', lambda_path) |
| svntest.actions.set_prop('some-prop', ' bar baz', mu_path) |
| svntest.actions.set_prop('some-prop', 'bar\n', iota_path) |
| |
| # NOTE: When writing out multi-line prop values in svn:* props, the |
| # client converts to local encoding and local eol style. |
| # Therefore, the expected output must contain the right kind of eoln |
| # strings. That's why we use os.linesep in the tests below, not just |
| # plain '\n'. The _last_ \n is also from the client, but it's not |
| # part of the prop value and it doesn't get converted in the pipe. |
| |
| # Check svn:mime-type |
| svntest.actions.check_prop('svn:mime-type', iota_path, [b'text/html']) |
| svntest.actions.check_prop('svn:mime-type', mu_path, [b'text/html']) |
| |
| # Check svn:eol-style |
| svntest.actions.check_prop('svn:eol-style', iota_path, [b'native']) |
| svntest.actions.check_prop('svn:eol-style', mu_path, [b'native']) |
| |
| # Check svn:ignore |
| linesep = os.linesep.encode() |
| svntest.actions.check_prop('svn:ignore', A_path, |
| [b'*.o'+linesep, b'foo.c'+linesep]) |
| svntest.actions.check_prop('svn:ignore', B_path, |
| [b'*.o'+linesep, b'foo.c'+linesep]) |
| |
| # Check svn:externals |
| svntest.actions.check_prop('svn:externals', A_path, |
| [b'foo http://foo.com/repos'+linesep]) |
| svntest.actions.check_prop('svn:externals', B_path, |
| [b'foo http://foo.com/repos'+linesep]) |
| |
| # Check svn:keywords |
| svntest.actions.check_prop('svn:keywords', iota_path, [b'Rev Date']) |
| svntest.actions.check_prop('svn:keywords', mu_path, [b'Rev Date']) |
| |
| # Check svn:executable |
| svntest.actions.check_prop('svn:executable', iota_path, [b'*']) |
| svntest.actions.check_prop('svn:executable', lambda_path, [b'*']) |
| svntest.actions.check_prop('svn:executable', mu_path, [b'*']) |
| |
| # Check other props |
| svntest.actions.check_prop('svn:some-prop', lambda_path, [b'bar']) |
| svntest.actions.check_prop('svn:some-prop', mu_path, [b' bar baz']) |
| svntest.actions.check_prop('svn:some-prop', iota_path, [b'bar'+linesep]) |
| svntest.actions.check_prop('some-prop', lambda_path, [b'bar']) |
| svntest.actions.check_prop('some-prop', mu_path,[b' bar baz']) |
| svntest.actions.check_prop('some-prop', iota_path, [b'bar\n']) |
| |
| |
| #---------------------------------------------------------------------- |
| |
| def binary_props(sbox): |
| "test binary property support" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Make a backup copy of the working copy |
| wc_backup = sbox.add_wc_path('backup') |
| svntest.actions.duplicate_dir(wc_dir, wc_backup) |
| |
| # Some path convenience vars. |
| A_path = sbox.ospath('A') |
| B_path = sbox.ospath('A/B') |
| iota_path = sbox.ospath('iota') |
| lambda_path = sbox.ospath('A/B/lambda') |
| mu_path = sbox.ospath('A/mu') |
| |
| A_path_bak = sbox.ospath('A', wc_dir=wc_backup) |
| B_path_bak = sbox.ospath('A/B', wc_dir=wc_backup) |
| iota_path_bak = sbox.ospath('iota', wc_dir=wc_backup) |
| lambda_path_bak = sbox.ospath('A/B/lambda', wc_dir=wc_backup) |
| mu_path_bak = sbox.ospath('A/mu', wc_dir=wc_backup) |
| |
| # Property value convenience vars. |
| prop_zb = b"This property has a zer\000 byte." |
| prop_ff = b"This property has a form\014feed." |
| prop_xml = b"This property has an <xml> tag." |
| prop_binx = b"This property has an <xml> tag and a zer\000 byte." |
| |
| # Set some binary properties. |
| svntest.actions.set_prop('prop_zb', prop_zb, B_path, ) |
| svntest.actions.set_prop('prop_ff', prop_ff, iota_path) |
| svntest.actions.set_prop('prop_xml', prop_xml, lambda_path) |
| svntest.actions.set_prop('prop_binx', prop_binx, mu_path) |
| svntest.actions.set_prop('prop_binx', prop_binx, A_path) |
| |
| # Create expected output and status trees. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A' : Item(verb='Sending'), |
| 'A/B' : Item(verb='Sending'), |
| 'iota' : Item(verb='Sending'), |
| 'A/B/lambda' : Item(verb='Sending'), |
| 'A/mu' : Item(verb='Sending'), |
| }) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A', 'A/B', 'iota', 'A/B/lambda', 'A/mu', |
| wc_rev=2, status=' ') |
| |
| # Commit the propsets. |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, |
| expected_status) |
| |
| # Create expected output, disk, and status trees for an update of |
| # the wc_backup. |
| expected_output = svntest.wc.State(wc_backup, { |
| 'A' : Item(status=' U'), |
| 'A/B' : Item(status=' U'), |
| 'iota' : Item(status=' U'), |
| 'A/B/lambda' : Item(status=' U'), |
| 'A/mu' : Item(status=' U'), |
| }) |
| expected_disk = svntest.main.greek_state.copy() |
| expected_status = svntest.actions.get_virginal_state(wc_backup, 2) |
| |
| # Do the update and check the results. |
| svntest.actions.run_and_verify_update(wc_backup, |
| expected_output, |
| expected_disk, |
| expected_status) |
| |
| # Now, check those properties. |
| svntest.actions.check_prop('prop_zb', B_path_bak, [prop_zb]) |
| svntest.actions.check_prop('prop_ff', iota_path_bak, [prop_ff]) |
| svntest.actions.check_prop('prop_xml', lambda_path_bak, [prop_xml]) |
| svntest.actions.check_prop('prop_binx', mu_path_bak, [prop_binx]) |
| svntest.actions.check_prop('prop_binx', A_path_bak, [prop_binx]) |
| |
| #---------------------------------------------------------------------- |
| |
| # Ensure that each line of output contains the corresponding string of |
| # expected_out, and that errput is empty. |
| def verify_output(expected_out, output, errput): |
| if errput != []: |
| logger.warn('Error: stderr:') |
| logger.warn(errput) |
| raise svntest.Failure |
| output.sort() |
| ln = 0 |
| for line in output: |
| if line.startswith('DBG:'): |
| continue |
| if ((line.find(expected_out[ln]) == -1) or |
| (line != '' and expected_out[ln] == '')): |
| logger.warn('Error: expected keywords: %s', expected_out) |
| logger.warn(' actual full output: %s', output) |
| raise svntest.Failure |
| ln = ln + 1 |
| if ln != len(expected_out): |
| raise svntest.Failure |
| |
| @Issue(1794) |
| def recursive_base_wc_ops(sbox): |
| "recursive property operations in BASE and WC" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Files with which to test, in alphabetical order |
| fp_add = sbox.ospath('A/added') |
| fp_del = sbox.ospath('A/mu') |
| #fp_keep= sbox.ospath('iota') |
| |
| # Set up properties |
| sbox.simple_propset('p', 'old-del', 'A/mu') |
| sbox.simple_propset('p', 'old-keep', 'iota') |
| sbox.simple_commit() |
| |
| svntest.main.file_append(fp_add, 'blah') |
| sbox.simple_add('A/added') |
| sbox.simple_propset('p', 'new-add', 'A/added') |
| sbox.simple_propset('p', 'new-del', 'A/mu') |
| sbox.simple_propset('p', 'new-keep', 'iota') |
| svntest.main.run_svn(None, 'del', '--force', fp_del) |
| |
| # Test recursive proplist |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', '-R', |
| '-v', wc_dir, '-rBASE') |
| verify_output([ 'old-del', 'old-keep', 'p', 'p', |
| 'Properties on ', 'Properties on ' ], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', '-R', |
| '-v', wc_dir) |
| verify_output([ 'new-add', 'new-keep', 'p', 'p', |
| 'Properties on ', 'Properties on ' ], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test recursive propget |
| exit_code, output, errput = svntest.main.run_svn(None, 'propget', '-R', |
| 'p', wc_dir, '-rBASE') |
| verify_output([ 'old-del', 'old-keep' ], output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| exit_code, output, errput = svntest.main.run_svn(None, 'propget', '-R', |
| 'p', wc_dir) |
| verify_output([ 'new-add', 'new-keep' ], output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test recursive propset (issue 1794) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A/mu', status='D ', wc_rev=2) |
| expected_status.tweak('iota', status=' M', wc_rev=2) |
| expected_status.add({ |
| 'A/added' : Item(status='A ', wc_rev=0), |
| }) |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '-R', 'svn:keywords', 'Date', |
| os.path.join(wc_dir, 'A', 'B')) |
| expected_status.tweak('A/B/lambda', 'A/B/E/alpha', 'A/B/E/beta', status=' M') |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| #---------------------------------------------------------------------- |
| |
| def url_props_ops(sbox): |
| "property operations on a URL" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| prop1 = 'prop1' |
| propval1 = 'propval1 is foo' |
| prop2 = 'prop2' |
| propval2 = 'propval2' |
| |
| iota_url = sbox.repo_url + '/iota' |
| A_url = sbox.repo_url + '/A' |
| |
| # Add a couple of properties |
| sbox.simple_propset(prop1, propval1, 'iota') |
| sbox.simple_propset(prop1, propval1, 'A') |
| |
| # Commit |
| sbox.simple_commit() |
| |
| # Add a few more properties |
| sbox.simple_propset(prop2, propval2, 'iota') |
| sbox.simple_propset(prop2, propval2, 'A') |
| |
| # Commit again |
| sbox.simple_commit() |
| |
| # Test propget |
| svntest.actions.run_and_verify_svn([ propval1 + '\n' ], [], |
| 'propget', prop1, iota_url) |
| svntest.actions.run_and_verify_svn([ propval1 + '\n' ], [], |
| 'propget', prop1, A_url) |
| |
| # Test normal proplist |
| exit_code, output, errput = svntest.main.run_svn(None, |
| 'proplist', iota_url) |
| verify_output([ prop1, prop2, 'Properties on ' ], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| exit_code, output, errput = svntest.main.run_svn(None, |
| 'proplist', A_url) |
| verify_output([ prop1, prop2, 'Properties on ' ], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test verbose proplist |
| exit_code, output, errput = svntest.main.run_svn(None, |
| 'proplist', '-v', iota_url) |
| verify_output([ propval1, propval2, prop1, prop2, |
| 'Properties on ' ], output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| exit_code, output, errput = svntest.main.run_svn(None, |
| 'proplist', '-v', A_url) |
| verify_output([ propval1, propval2, prop1, prop2, |
| 'Properties on ' ], output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test propedit |
| svntest.main.use_editor('foo_to_bar') |
| propval1 = propval1.replace('foo', 'bar') |
| svntest.main.run_svn(None, |
| 'propedit', prop1, '-m', 'editlog', iota_url) |
| svntest.main.run_svn(None, |
| 'propedit', prop1, '-m', 'editlog', A_url) |
| svntest.actions.run_and_verify_svn([ propval1 + '\n' ], [], |
| 'propget', prop1, iota_url) |
| svntest.actions.run_and_verify_svn([ propval1 + '\n' ], [], |
| 'propget', prop1, A_url) |
| |
| # Edit without actually changing the property |
| svntest.main.use_editor('identity') |
| svntest.actions.run_and_verify_svn("No changes to property '%s' on '.*'" |
| % prop1, |
| [], |
| 'propedit', prop1, '-m', 'nocommit', |
| iota_url) |
| |
| |
| |
| #---------------------------------------------------------------------- |
| def removal_schedule_added_props(sbox): |
| "removal of schedule added file with properties" |
| |
| sbox.build() |
| |
| wc_dir = sbox.wc_dir |
| newfile_path = sbox.ospath('newfile') |
| file_add_output = ["A " + newfile_path + "\n"] |
| propset_output = ["property 'newprop' set on '" + newfile_path + "'\n"] |
| file_rm_output = ["D " + newfile_path + "\n"] |
| propls_output = [ |
| "Properties on '" + newfile_path + "':\n", |
| " newprop\n", |
| " newvalue\n", |
| ] |
| |
| # create new fs file |
| open(newfile_path, 'w').close() |
| # Add it and set a property |
| svntest.actions.run_and_verify_svn(file_add_output, [], 'add', newfile_path) |
| svntest.actions.run_and_verify_svn(propset_output, [], 'propset', |
| 'newprop', 'newvalue', newfile_path) |
| svntest.actions.run_and_verify_svn(propls_output, [], |
| 'proplist', '-v', newfile_path) |
| # remove the file |
| svntest.actions.run_and_verify_svn(file_rm_output, [], |
| 'rm', '--force', newfile_path) |
| # recreate the file and add it again |
| open(newfile_path, 'w').close() |
| svntest.actions.run_and_verify_svn(file_add_output, [], 'add', newfile_path) |
| |
| # Now there should be NO properties leftover... |
| svntest.actions.run_and_verify_svn([], [], |
| 'proplist', '-v', newfile_path) |
| |
| #---------------------------------------------------------------------- |
| |
| def update_props_on_wc_root(sbox): |
| "receive properties on the wc root via update" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Make a backup copy of the working copy |
| wc_backup = sbox.add_wc_path('backup') |
| svntest.actions.duplicate_dir(wc_dir, wc_backup) |
| |
| # Add a property to the root folder |
| sbox.simple_propset('red', 'rojo', '') |
| |
| # Create expected output tree. |
| expected_output = svntest.wc.State(wc_dir, { |
| '' : Item(verb='Sending') |
| }) |
| |
| # Created expected status tree. |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('', wc_rev=2, status=' ') |
| |
| # Commit the working copy |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Create expected output tree for an update of the wc_backup. |
| expected_output = svntest.wc.State(wc_backup, { |
| '' : Item(status=' U'), |
| }) |
| # Create expected disk tree for the update. |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.add({ |
| '' : Item(props = {'red' : 'rojo'}), |
| }) |
| # Create expected status tree for the update. |
| expected_status = svntest.actions.get_virginal_state(wc_backup, 2) |
| expected_status.tweak('', status=' ') |
| |
| # Do the update and check the results in three ways... INCLUDING PROPS |
| svntest.actions.run_and_verify_update(wc_backup, |
| expected_output, |
| expected_disk, |
| expected_status, |
| check_props=True) |
| |
| # test for issue 2743 |
| @Issue(2743) |
| def props_on_replaced_file(sbox): |
| """test properties on replaced files""" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add some properties to iota |
| iota_path = sbox.ospath("iota") |
| sbox.simple_propset('red', 'rojo', 'iota') |
| sbox.simple_propset('blue', 'lagoon', 'iota') |
| sbox.simple_commit() |
| |
| # replace iota_path |
| sbox.simple_rm('iota') |
| svntest.main.file_append(iota_path, "some mod") |
| sbox.simple_add('iota') |
| |
| # check that the replaced file has no properties |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('iota', contents="some mod") |
| svntest.actions.verify_disk(wc_dir, expected_disk.old_tree(), True) |
| |
| # now add a new property to iota |
| sbox.simple_propset('red', 'mojo', 'iota') |
| sbox.simple_propset('groovy', 'baby', 'iota') |
| |
| # What we expect the disk tree to look like: |
| expected_disk.tweak('iota', props={'red' : 'mojo', 'groovy' : 'baby'}) |
| svntest.actions.verify_disk(wc_dir, expected_disk.old_tree(), True) |
| |
| #---------------------------------------------------------------------- |
| |
| def depthy_wc_proplist(sbox): |
| """test proplist at various depths on a wc""" |
| # Bootstrap. |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Set up properties. |
| sbox.simple_propset('p', 'prop1', '') |
| sbox.simple_propset('p', 'prop2', 'iota') |
| sbox.simple_propset('p', 'prop3', 'A') |
| sbox.simple_propset('p', 'prop4', 'A/mu') |
| |
| # Commit. |
| sbox.simple_commit() |
| |
| # Test depth-empty proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', |
| '--depth', 'empty', |
| '-v', wc_dir) |
| verify_output([ 'prop1', 'p', 'Properties on ' ], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test depth-files proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', |
| '--depth', 'files', |
| '-v', wc_dir) |
| verify_output([ 'prop1', 'prop2', 'p', 'p', |
| 'Properties on ', 'Properties on ' ], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test depth-immediates proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', '--depth', |
| 'immediates', '-v', wc_dir) |
| verify_output([ 'prop1', 'prop2', 'prop3' ] + |
| ['p'] * 3 + ['Properties on '] * 3, |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test depth-infinity proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', '--depth', |
| 'infinity', '-v', wc_dir) |
| verify_output([ 'prop1', 'prop2', 'prop3', 'prop4' ] + |
| ['p'] * 4 + ['Properties on '] * 4, |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| #---------------------------------------------------------------------- |
| |
| def depthy_url_proplist(sbox): |
| """test proplist at various depths on a url""" |
| # Bootstrap. |
| sbox.build() |
| repo_url = sbox.repo_url |
| wc_dir = sbox.wc_dir |
| |
| # Set up properties. |
| sbox.simple_propset('p', 'prop1', '') |
| sbox.simple_propset('p', 'prop2', 'iota') |
| sbox.simple_propset('p', 'prop3', 'A') |
| sbox.simple_propset('p', 'prop4', 'A/mu') |
| sbox.simple_commit() |
| |
| # Test depth-empty proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', |
| '--depth', 'empty', |
| '-v', repo_url) |
| verify_output([ 'prop1', 'p', 'Properties on '], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test depth-files proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', |
| '--depth', 'files', |
| '-v', repo_url) |
| verify_output([ 'prop1', 'prop2', 'p', 'p', |
| 'Properties on ', 'Properties on ' ], |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test depth-immediates proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, 'proplist', |
| '--depth', 'immediates', |
| '-v', repo_url) |
| |
| verify_output([ 'prop1', 'prop2', 'prop3' ] + ['p'] * 3 + |
| ['Properties on '] * 3, |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| # Test depth-infinity proplist. |
| exit_code, output, errput = svntest.main.run_svn(None, |
| 'proplist', '--depth', |
| 'infinity', '-v', repo_url) |
| verify_output([ 'prop1', 'prop2', 'prop3', 'prop4' ] + ['p'] * 4 + |
| ['Properties on '] * 4, |
| output, errput) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| #---------------------------------------------------------------------- |
| |
| def invalid_propnames(sbox): |
| """test prop* handle invalid property names""" |
| # Bootstrap. |
| sbox.build() |
| repo_url = sbox.repo_url |
| wc_dir = sbox.wc_dir |
| cwd = os.getcwd() |
| os.chdir(wc_dir) |
| |
| propname = chr(8) |
| propval = 'foo' |
| |
| expected_stdout = (".*Attempting to delete nonexistent property " |
| "'%s'.*" % (propname,)) |
| svntest.actions.run_and_verify_svn(expected_stdout, [], |
| 'propdel', propname) |
| expected_stderr = (".*'%s' is not a valid Subversion" |
| ' property name' % (propname,)) |
| svntest.actions.run_and_verify_svn(None, expected_stderr, |
| 'propedit', propname) |
| svntest.actions.run_and_verify_svn(None, expected_stderr, |
| 'propget', propname) |
| svntest.actions.run_and_verify_svn(None, expected_stderr, |
| 'propset', propname, propval) |
| |
| svntest.actions.run_and_verify_svn(None, expected_stderr, |
| 'commit', '--with-revprop', |
| '='.join([propname, propval])) |
| # Now swap them: --with-revprop should accept propname as a property |
| # value; no concept of validity there. |
| svntest.actions.run_and_verify_svn([], [], |
| 'commit', '--with-revprop', |
| '='.join([propval, propname])) |
| |
| os.chdir(cwd) |
| |
| @SkipUnless(svntest.main.is_posix_os) |
| @Issue(2581) |
| def perms_on_symlink(sbox): |
| "propset shouldn't touch symlink perms" |
| sbox.build() |
| # We can't just run commands on absolute paths in the usual way |
| # (e.g., os.path.join(sbox.wc_dir, 'newdir')), because for some |
| # reason, if the symlink points to newdir as an absolute path, the |
| # bug doesn't reproduce. I have no idea why. Since it does have to |
| # point to newdir, the only other choice is to have it point to it |
| # in the same directory, so we have to run the test from inside the |
| # working copy. |
| saved_cwd = os.getcwd() |
| os.chdir(sbox.wc_dir) |
| try: |
| svntest.actions.run_and_verify_svn(None, [], 'mkdir', 'newdir') |
| os.symlink('newdir', 'symlink') |
| svntest.actions.run_and_verify_svn(None, [], 'add', 'symlink') |
| old_mode = os.stat('newdir')[stat.ST_MODE] |
| # The only property on 'symlink' is svn:special, so attempting to remove |
| # 'svn:executable' should result in an error |
| expected_stdout = (".*Attempting to delete nonexistent property " |
| "'svn:executable'.*") |
| svntest.actions.run_and_verify_svn(expected_stdout, [], 'propdel', |
| 'svn:executable', 'symlink') |
| new_mode = os.stat('newdir')[stat.ST_MODE] |
| if not old_mode == new_mode: |
| # Chmod newdir back, so the test suite can remove this working |
| # copy when cleaning up later. |
| os.chmod('newdir', stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) |
| raise svntest.Failure |
| finally: |
| os.chdir(saved_cwd) |
| |
| # Use a property with a custom namespace, ie 'ns:prop' or 'mycompany:prop'. |
| def remove_custom_ns_props(sbox): |
| "remove a property with a custom namespace" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add a property to a file |
| sbox.simple_propset('ns:cash-sound', 'cha-ching!', 'iota') |
| |
| # Commit the file |
| sbox.simple_commit('iota') |
| |
| # Now, make a backup copy of the working copy |
| wc_backup = sbox.add_wc_path('backup') |
| svntest.actions.duplicate_dir(wc_dir, wc_backup) |
| |
| # Remove the property |
| sbox.simple_propdel('ns:cash-sound', 'iota') |
| |
| # Create expected trees. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'iota' : Item(verb='Sending'), |
| }) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('iota', wc_rev=3, status=' ') |
| |
| # Commit the one file. |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Create expected trees for the update. |
| expected_output = svntest.wc.State(wc_backup, { |
| 'iota' : Item(status=' U'), |
| }) |
| expected_disk = svntest.main.greek_state.copy() |
| expected_status = svntest.actions.get_virginal_state(wc_backup, 3) |
| expected_status.tweak('iota', wc_rev=3, status=' ') |
| |
| # Do the update and check the results in three ways... INCLUDING PROPS |
| svntest.actions.run_and_verify_update(wc_backup, |
| expected_output, |
| expected_disk, |
| expected_status, |
| check_props=True) |
| |
| def props_over_time(sbox): |
| "property retrieval with peg and operative revs" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Convenience variables |
| iota_path = sbox.ospath('iota') |
| iota_url = sbox.repo_url + '/iota' |
| |
| # Add/tweak a property 'revision' with value revision-committed to a |
| # file, commit, and then repeat this a few times. |
| for rev in range(2, 4): |
| sbox.simple_propset('revision', str(rev), 'iota') |
| sbox.simple_commit('iota') |
| |
| # Backdate to r2 so the defaults for URL- vs. WC-style queries are |
| # different. |
| svntest.main.run_svn(None, 'up', '-r2', wc_dir) |
| |
| # Now, test propget of the property across many combinations of |
| # pegrevs, operative revs, and wc-path vs. url style input specs. |
| # NOTE: We're using 0 in these loops to mean "unspecified". |
| for path in iota_path, iota_url: |
| for peg_rev in range(0, 4): |
| for op_rev in range(0, 4): |
| # Calculate the expected property value. If there is an |
| # operative rev, we expect the output to match revisions |
| # there. Else, we'll be looking at the peg-rev value. And if |
| # neither are supplied, it depends on the path vs. URL |
| # question. |
| if op_rev > 1: |
| expected = str(op_rev) |
| elif op_rev == 1: |
| expected = None |
| else: |
| if peg_rev > 1: |
| expected = str(peg_rev) |
| elif peg_rev == 1: |
| expected = None |
| else: |
| if path == iota_url: |
| expected = "3" # HEAD |
| else: |
| expected = "2" # BASE |
| |
| peg_path = path + (peg_rev != 0 and '@' + str(peg_rev) or "") |
| |
| ### Test 'svn propget' |
| pget_expected = expected |
| if pget_expected: |
| pget_expected = [ pget_expected + "\n" ] |
| expected_err = [] if expected else '.*W200017: Property.*not found.*' |
| if op_rev != 0: |
| svntest.actions.run_and_verify_svn(pget_expected, expected_err, |
| 'propget', 'revision', peg_path, |
| '-r', str(op_rev)) |
| else: |
| svntest.actions.run_and_verify_svn(pget_expected, expected_err, |
| 'propget', 'revision', peg_path) |
| |
| ### Test 'svn proplist -v' |
| if op_rev != 0 or peg_rev != 0: # a revision-ful query output URLs |
| path = iota_url |
| plist_expected = expected |
| if plist_expected: |
| plist_expected = [ "Properties on '" + path + "':\n", |
| " revision\n", |
| " " + expected + "\n" ] |
| |
| if op_rev != 0: |
| svntest.actions.run_and_verify_svn(plist_expected, [], |
| 'proplist', '-v', peg_path, |
| '-r', str(op_rev)) |
| else: |
| svntest.actions.run_and_verify_svn(plist_expected, [], |
| 'proplist', '-v', peg_path) |
| |
| |
| # XFail the same reason revprop_change() is. |
| @SkipUnless(svntest.main.server_enforces_date_syntax) |
| @Issue(3086) |
| def invalid_propvalues(sbox): |
| "test handling invalid svn:* property values" |
| |
| sbox.build(create_wc = False) |
| repo_dir = sbox.repo_dir |
| repo_url = sbox.repo_url |
| |
| svntest.actions.enable_revprop_changes(repo_dir) |
| |
| expected_stderr = '.*unexpected property value.*|.*Bogus date.*' |
| svntest.actions.run_and_verify_svn([], expected_stderr, |
| 'propset', '--revprop', '-r', '0', |
| 'svn:date', 'Sat May 10 12:12:31 2008', |
| repo_url) |
| |
| @Issue(3282) |
| def same_replacement_props(sbox): |
| "commit replacement props when same as old props" |
| # issue #3282 |
| sbox.build() |
| |
| foo_path = sbox.ospath('foo') |
| |
| open(foo_path, 'w').close() |
| sbox.simple_add('foo') |
| sbox.simple_propset('someprop', 'someval', 'foo') |
| sbox.simple_commit('foo') |
| sbox.simple_rm('foo') |
| |
| # Now replace 'foo'. |
| open(foo_path, 'w').close() |
| sbox.simple_add('foo') |
| |
| # Set the same property again, with the same value. |
| sbox.simple_propset('someprop', 'someval', 'foo') |
| sbox.simple_commit('foo') |
| |
| # Check if the property made it into the repository. |
| foo_url = sbox.repo_url + '/foo' |
| expected_out = [ "Properties on '" + foo_url + "':\n", |
| " someprop\n", |
| " someval\n" ] |
| svntest.actions.run_and_verify_svn(expected_out, [], |
| 'proplist', '-v', foo_url) |
| |
| def added_moved_file(sbox): |
| "'svn mv added_file' preserves props" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # create it |
| foo_path = sbox.ospath('foo') |
| foo2_path = sbox.ospath('foo2') |
| foo2_url = sbox.repo_url + '/foo2' |
| |
| open(foo_path, 'w').close() |
| |
| # add it |
| sbox.simple_add('foo') |
| sbox.simple_propset('someprop', 'someval', 'foo') |
| |
| # move it |
| svntest.main.run_svn(None, 'mv', foo_path, foo2_path) |
| |
| # should still have the property |
| svntest.actions.check_prop('someprop', foo2_path, [b'someval']) |
| |
| # the property should get committed, too |
| sbox.simple_commit() |
| svntest.actions.check_prop('someprop', foo2_url, [b'someval']) |
| |
| |
| # Issue 2220, deleting a non-existent property should error |
| @Issue(2220) |
| def delete_nonexistent_property(sbox): |
| "remove a property which doesn't exist" |
| |
| # Bootstrap |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Remove one property |
| expected_stdout = ".*Attempting to delete nonexistent property 'yellow'.*" |
| svntest.actions.run_and_verify_svn(expected_stdout, [], |
| 'propdel', 'yellow', |
| os.path.join(wc_dir, 'A', 'D', 'G')) |
| |
| #---------------------------------------------------------------------- |
| @Issue(3553) |
| def post_revprop_change_hook(sbox): |
| "post-revprop-change hook" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| repo_dir = sbox.repo_dir |
| |
| # Include a non-XML-safe message to regression-test issue #3553. |
| error_msg = 'Text with <angle brackets> & ampersand' |
| |
| svntest.actions.enable_revprop_changes(repo_dir) |
| svntest.actions.create_failing_hook(repo_dir, 'post-revprop-change', |
| error_msg) |
| |
| # serf/mod_dav_svn give SVN_ERR_RA_DAV_PROPPATCH_FAILED |
| # file/svn give SVN_ERR_REPOS_HOOK_FAILURE |
| expected_error = 'svn: (E175008|E165001).*post-revprop-change hook failed' |
| |
| svntest.actions.run_and_verify_svn([], expected_error, |
| 'ps', '--revprop', '-r0', 'p', 'v', |
| wc_dir) |
| |
| # Verify change has stuck -- at one time mod_dav_svn would rollback |
| # revprop changes on post-revprop-change hook errors |
| svntest.actions.run_and_verify_svn('v', [], |
| 'pg', '--revprop', '-r0', 'p', |
| wc_dir) |
| |
| def rm_of_replaced_file(sbox): |
| """properties after a removal of a replaced file""" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add some properties to iota and mu |
| iota_path = sbox.ospath('iota') |
| sbox.simple_propset('red', 'rojo', 'iota') |
| sbox.simple_propset('blue', 'lagoon', 'iota') |
| |
| mu_path = sbox.ospath('A/mu') |
| sbox.simple_propset('yellow', 'submarine', 'A/mu') |
| sbox.simple_propset('orange', 'toothpick', 'A/mu') |
| |
| sbox.simple_commit() |
| |
| # Copy iota over the top of mu |
| sbox.simple_rm('A/mu') |
| svntest.main.run_svn(None, 'cp', iota_path, mu_path) |
| |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('iota', props={'red': 'rojo', 'blue': 'lagoon'}) |
| expected_disk.tweak('A/mu', props={'red': 'rojo', 'blue': 'lagoon'}, |
| contents="This is the file 'iota'.\n") |
| svntest.actions.verify_disk(wc_dir, expected_disk.old_tree(), True) |
| |
| # Remove the copy. This should leave the original locally-deleted mu, |
| # which should have no properties. |
| svntest.main.run_svn(None, 'rm', '--force', mu_path) |
| |
| svntest.actions.run_and_verify_svn( |
| [], |
| 'svn: E200009.*some targets are not versioned.*', |
| 'proplist', '-v', mu_path) |
| |
| # Run it again, but ask for the pristine properties, which should |
| # be mu's original props. |
| exit_code, output, errput = svntest.main.run_svn(None, |
| 'proplist', '-v', |
| mu_path + '@base') |
| expected_output = svntest.verify.UnorderedRegexListOutput([ |
| 'Properties on.*', |
| ' yellow', |
| ' submarine', |
| ' orange', |
| ' toothpick', |
| ]) |
| svntest.verify.compare_and_display_lines('message', 'label', |
| expected_output, output) |
| svntest.verify.verify_exit_code(None, exit_code, 0) |
| |
| |
| def prop_reject_grind(sbox): |
| """grind through all variants of prop rejects""" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| mu_path = sbox.ospath('A/mu') |
| mu_prej_path = sbox.ospath('A/mu.prej') |
| |
| # Create r2 with all the properties we intend to use as incoming-change, |
| # and as incoming-delete. Also set up our local-edit and local-delete |
| # properties. We also need some properties that are simply different |
| # from the incoming properties |
| sbox.simple_propset('edit.diff', 'repos', 'iota') |
| sbox.simple_propset('edit.edit', 'repos', 'iota') |
| sbox.simple_propset('edit.del', 'repos', 'iota') |
| sbox.simple_propset('edit.add', 'repos', 'iota') |
| sbox.simple_propset('edit.none', 'repos', 'iota') |
| sbox.simple_propset('del.edit', 'repos', 'iota') |
| sbox.simple_propset('del.edit2', 'repos', 'iota') |
| sbox.simple_propset('del.diff', 'repos', 'iota') |
| sbox.simple_propset('del.del', 'repos', 'iota') |
| sbox.simple_propset('del.add', 'repos', 'iota') |
| |
| sbox.simple_propset('edit.edit', 'local', 'A/mu') |
| sbox.simple_propset('add.edit', 'local', 'A/mu') |
| sbox.simple_propset('del.edit', 'local', 'A/mu') |
| sbox.simple_propset('del.edit2', 'repos', 'A/mu') |
| sbox.simple_propset('add.del', 'local', 'A/mu') |
| sbox.simple_propset('edit.del', 'local', 'A/mu') |
| sbox.simple_propset('del.del', 'local', 'A/mu') |
| sbox.simple_propset('edit.diff', 'local', 'A/mu') |
| sbox.simple_propset('add.diff', 'local', 'A/mu') |
| sbox.simple_propset('del.diff', 'local', 'A/mu') |
| |
| sbox.simple_commit() |
| |
| # Create r3 with all the properties that we intend to use as incoming-add, |
| # and then perform the incoming-edits and incoming-deletes. |
| sbox.simple_propset('add.add', 'repos', 'iota') |
| sbox.simple_propset('add.edit', 'repos', 'iota') |
| sbox.simple_propset('add.del', 'repos', 'iota') |
| sbox.simple_propset('add.diff', 'repos', 'iota') |
| sbox.simple_propset('edit.diff', 'repos.changed', 'iota') |
| sbox.simple_propset('edit.edit', 'repos.changed', 'iota') |
| sbox.simple_propset('edit.del', 'repos.changed', 'iota') |
| sbox.simple_propset('edit.add', 'repos.changed', 'iota') |
| sbox.simple_propset('edit.none', 'repos.changed', 'iota') |
| sbox.simple_propdel('del.edit', 'iota') |
| sbox.simple_propdel('del.edit2', 'iota') |
| sbox.simple_propdel('del.diff', 'iota') |
| sbox.simple_propdel('del.del', 'iota') |
| sbox.simple_propdel('del.add', 'iota') |
| sbox.simple_commit() |
| |
| # Set up our victim for all the right rejects: local-adds, local-edits, |
| # and local-deletes. |
| sbox.simple_propset('edit.add', 'local', 'A/mu') |
| sbox.simple_propset('add.add', 'local', 'A/mu') |
| sbox.simple_propset('del.add', 'local', 'A/mu') |
| sbox.simple_propset('edit.edit', 'local.changed', 'A/mu') |
| sbox.simple_propset('add.edit', 'local.changed', 'A/mu') |
| sbox.simple_propset('del.edit', 'local.changed', 'A/mu') |
| sbox.simple_propset('del.edit2', 'repos.changed', 'A/mu') |
| sbox.simple_propdel('add.del', 'A/mu') |
| sbox.simple_propdel('edit.del', 'A/mu') |
| sbox.simple_propdel('del.del', 'A/mu') |
| |
| # Now merge r2:3 into the victim to create all variants |
| svntest.main.run_svn(False, 'merge', '-r2:3', sbox.repo_url + '/iota', |
| mu_path) |
| |
| # Check that A/mu.prej reports the expected conflicts: |
| expected_prej = [ |
| "Trying to change property 'edit.none'\n" |
| "but the property does not exist locally.\n" |
| "<<<<<<< (local property value)\n" |
| "||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| "repos.changed>>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to delete property 'del.del'\n" |
| "but the property has been locally deleted and had a different value.\n", |
| |
| "Trying to delete property 'del.edit'\n" |
| "but the local property value is different.\n" |
| "<<<<<<< (local property value)\n" |
| "local.changed||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| ">>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to change property 'edit.del'\n" |
| "but the property has been locally deleted.\n" |
| "<<<<<<< (local property value)\n" |
| "||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| "repos.changed>>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to change property 'edit.edit'\n" |
| "but the property has already been locally changed to a different value.\n" |
| "<<<<<<< (local property value)\n" |
| "local.changed||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| "repos.changed>>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to delete property 'del.edit2'\n" |
| "but the property has been locally modified.\n" |
| "<<<<<<< (local property value)\n" |
| "repos.changed||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| ">>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to delete property 'del.add'\n" |
| "but the property has been locally added.\n" |
| "<<<<<<< (local property value)\n" |
| "local||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| ">>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to delete property 'del.diff'\n" |
| "but the local property value is different.\n" |
| "<<<<<<< (local property value)\n" |
| "local||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| ">>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to change property 'edit.add'\n" |
| "but the property has been locally added with a different value.\n" |
| "<<<<<<< (local property value)\n" |
| "local||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| "repos.changed>>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to change property 'edit.diff'\n" |
| "but the local property value conflicts with the incoming change.\n" |
| "<<<<<<< (local property value)\n" |
| "local||||||| (incoming 'changed from' value)\n" |
| "repos=======\n" |
| "repos.changed>>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to add new property 'add.add'\n" |
| "but the property already exists.\n" |
| "<<<<<<< (local property value)\n" |
| "local||||||| (incoming 'changed from' value)\n" |
| "=======\n" |
| "repos>>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to add new property 'add.diff'\n" |
| "but the property already exists.\n" |
| "<<<<<<< (local property value)\n" |
| "local||||||| (incoming 'changed from' value)\n" |
| "=======\n" |
| "repos>>>>>>> (incoming 'changed to' value)\n", |
| |
| "Trying to add new property 'add.del'\n" |
| "but the property has been locally deleted.\n" |
| "Incoming property value:\n" |
| "repos\n", |
| |
| "Trying to add new property 'add.edit'\n" |
| "but the property already exists.\n" |
| "<<<<<<< (local property value)\n" |
| "local.changed||||||| (incoming 'changed from' value)\n" |
| "=======\n" |
| "repos>>>>>>> (incoming 'changed to' value)\n", |
| ] |
| |
| # Get the contents of mu.prej. The error messages are in the prej file |
| # but there is no guarantee as to order. So try to locate each message |
| # in the file individually. |
| prej_file = open(mu_prej_path, 'r') |
| n = 0 |
| for message in expected_prej: |
| prej_file.seek(0) |
| match = False |
| i = 0 |
| j = 0 |
| msg_lines = message.split('\n') |
| for file_line in prej_file: |
| line = msg_lines[i] + '\n' |
| match = (line == file_line) |
| if match: |
| # The last line in the list is always an empty string. |
| if msg_lines[i + 1] == "": |
| #logger.info("found message %i in file at line %i" % (n, j)) |
| break |
| i += 1 |
| else: |
| i = 0 |
| j += 1 |
| n += 1 |
| if not match: |
| raise svntest.main.SVNUnmatchedError( |
| "Expected mu.prej doesn't match actual mu.prej") |
| |
| def obstructed_subdirs(sbox): |
| """test properties of obstructed subdirectories""" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # at one point during development, obstructed subdirectories threw |
| # errors trying to fetch property information during 'svn status'. |
| # this test ensures we won't run into that problem again. |
| |
| C_path = sbox.ospath('A/C') |
| sbox.simple_propset('red', 'blue', 'A/C') |
| |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('A/C', props={'red': 'blue'}) |
| svntest.actions.verify_disk(wc_dir, expected_disk.old_tree(), True) |
| |
| # Remove the subdir from disk, and validate the status |
| svntest.main.safe_rmtree(C_path) |
| |
| expected_disk.remove('A/C') |
| svntest.actions.verify_disk(wc_dir, expected_disk.old_tree(), True) |
| |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A/C', status='!M', wc_rev='1') |
| |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Drop an empty file there to obstruct the now-deleted subdir |
| open(C_path, 'w') |
| |
| expected_disk.add({'A/C': Item(contents='', props={'red': 'blue'})}) |
| expected_status.tweak('A/C', status='~M', wc_rev='1') |
| |
| svntest.actions.verify_disk(wc_dir, expected_disk.old_tree(), True) |
| |
| |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| |
| def atomic_over_ra(sbox): |
| "test revprop atomicity guarantees of libsvn_ra" |
| |
| sbox.build(create_wc=False) |
| repo_url = sbox.repo_url |
| |
| # From this point on, similar to ../libsvn_fs/fs-test.c:revision_props(). |
| s1 = "violet" |
| s2 = "wrong value" |
| |
| # But test "" explicitly, since the RA layers have to marshal "" and <unset> |
| # differently. |
| s3 = "" |
| |
| # Initial state. |
| svntest.actions.enable_revprop_changes(sbox.repo_dir) |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--revprop', '-r', '0', |
| 'flower', s1, repo_url) |
| |
| # Helpers. |
| |
| def expect_old_server_fail(old_value, proposed_value): |
| # We are setting a (possibly "not present") expectation for the old value, |
| # so we should fail. |
| expected_stderr = ".*doesn't advertise.*ATOMIC_REVPROP" |
| svntest.actions.run_and_verify_atomic_ra_revprop_change( |
| None, expected_stderr, 1, repo_url, 0, 'flower', |
| old_value, proposed_value, True) |
| |
| # The original value is still there. |
| svntest.actions.check_prop('flower', repo_url, [s1], 0) |
| |
| def FAILS_WITH_BPV(not_the_old_value, proposed_value): |
| if svntest.main.server_has_atomic_revprop(): |
| svntest.actions.run_and_verify_atomic_ra_revprop_change( |
| None, [], 0, repo_url, 0, 'flower', |
| not_the_old_value, proposed_value, True) |
| else: |
| expect_old_server_fail(not_the_old_value, proposed_value) |
| |
| def PASSES_WITHOUT_BPV(yes_the_old_value, proposed_value): |
| if svntest.main.server_has_atomic_revprop(): |
| svntest.actions.run_and_verify_atomic_ra_revprop_change( |
| None, [], 0, repo_url, 0, 'flower', |
| yes_the_old_value, proposed_value, False) |
| else: |
| expect_old_server_fail(yes_the_old_value, proposed_value) |
| |
| # Value of "flower" is 's1'. |
| FAILS_WITH_BPV(s2, s1) |
| FAILS_WITH_BPV(s3, s1) |
| PASSES_WITHOUT_BPV(s1, s2) |
| |
| # Value of "flower" is 's2'. |
| PASSES_WITHOUT_BPV(s2, s3) |
| |
| # Value of "flower" is 's3'. |
| FAILS_WITH_BPV(None, s3) |
| FAILS_WITH_BPV(s1, s3) |
| PASSES_WITHOUT_BPV(s3, s2) |
| |
| # Value of "flower" is 's2'. |
| FAILS_WITH_BPV(None, None) |
| FAILS_WITH_BPV(s1, None) |
| FAILS_WITH_BPV(s3, None) |
| PASSES_WITHOUT_BPV(s2, None) |
| |
| # Value of "flower" is <not set>. |
| FAILS_WITH_BPV(s2, s1) |
| FAILS_WITH_BPV(s3, s1) |
| PASSES_WITHOUT_BPV(None, s1) |
| |
| # Value of "flower" is 's1'. |
| svntest.actions.check_prop('flower', repo_url, [s1.encode()], 0) |
| |
| # Test for issue #3721 'redirection of svn propget output corrupted with |
| # large property values' |
| @Issue(3721) |
| def propget_redirection(sbox): |
| """pg of large text properties redirects properly""" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Some paths we'll care about |
| B_path = os.path.join(wc_dir, "A", "B") |
| C_path = os.path.join(wc_dir, "A", "C") |
| D_path = os.path.join(wc_dir, "A", "D") |
| |
| prop_val_file = os.path.join(wc_dir, "prop_val") |
| redirect_file = os.path.join(wc_dir, "pg.vR.out") |
| |
| # A 'big' mergeinfo property. Yes, it is bogus in the sense that |
| # it refers to non-existent path-revs, but that is not relevant to |
| # this test. What matters is that it is a realistic 'big' mergeinfo |
| # value (it is from Subversion's own 1.6.x branch in fact). |
| # Also, the syntax is wrong: every path should start with '/'; |
| # Subversion currently silently corrects this. |
| big_prop_val = "subversion/branches/1.5.x:872364-874936\n" + \ |
| "subversion/branches/1.5.x-34184:874657-874741\n" + \ |
| "subversion/branches/1.5.x-34432:874744-874798\n" + \ |
| "subversion/branches/1.5.x-issue3067:872184-872314\n" + \ |
| "subversion/branches/1.5.x-issue3157:872165-872175\n" + \ |
| "subversion/branches/1.5.x-issue3174:872178-872348\n" + \ |
| "subversion/branches/1.5.x-r30215:870310,870312,870319,870362\n" + \ |
| "subversion/branches/1.5.x-r30756:874853-874870\n" + \ |
| "subversion/branches/1.5.x-r30868:870951-870970\n" + \ |
| "subversion/branches/1.5.x-r31314:874476-874605\n" + \ |
| "subversion/branches/1.5.x-r31516:871592-871649\n" + \ |
| "subversion/branches/1.5.x-r32470:872546-872676\n" + \ |
| "subversion/branches/1.5.x-r32968:873773-873872\n" + \ |
| "subversion/branches/1.5.x-r33447:873527-873547\n" + \ |
| "subversion/branches/1.5.x-r33465:873541-873549\n" + \ |
| "subversion/branches/1.5.x-r33641:873880-873883\n" + \ |
| "subversion/branches/1.5.x-r34050-followups:874639-874686\n" + \ |
| "subversion/branches/1.5.x-r34487:874562-874581\n" + \ |
| "subversion/branches/1.5.x-ra_serf-backports:872354-872626\n" + \ |
| "subversion/branches/1.5.x-rb-test-fix:874916-874919\n" + \ |
| "subversion/branches/1.5.x-reintegrate-improvements:874586-874922\n" + \ |
| "subversion/branches/1.5.x-tests-pass:870925-870973\n" + \ |
| "subversion/branches/dont-save-plaintext-passwords-by-default:" + \ |
| "870728-871118\n" + \ |
| "subversion/branches/gnome-keyring:870558-871410\n" + \ |
| "subversion/branches/issue-3220-dev:872210-872226\n" + \ |
| "subversion/branches/kwallet:870785-871314\n" + \ |
| "subversion/branches/log-g-performance:870941-871032\n" + \ |
| "subversion/branches/r30963-1.5.x:871056-871076\n" + \ |
| "subversion/branches/reintegrate-improvements:873853-874164\n" + \ |
| "subversion/branches/svn-mergeinfo-enhancements:870196\n" + \ |
| "subversion/branches/svnpatch-diff:871905\n" + \ |
| "subversion/trunk:869159-869165,869168-869181,869185,869188,869191," + \ |
| "869200-869201,869203-869207,869209-869224,869227-869238,869240-" + \ |
| "869244,869248,869250-869260,869262-869263,869265,869267-869268," + \ |
| "869272-869280,869282-869325,869328-869330,869335,869341-869347," + \ |
| "869351,869354-869355,869358,869361-869377,869379-869381,869383-" + \ |
| "869417,869419-869422,869432-869453,869455-869466,869471-869473," + \ |
| "869475,869483,869486,869488-869489,869491-869497,869499-869500," + \ |
| "869503,869506-869508,869510-869521,869523-869540,869542-869552," + \ |
| "869556,869558,869560-869561,869563,869565,869567,869570,869572," + \ |
| "869582,869601-869602,869605,869607,869613-869614,869616,869618," + \ |
| "869620,869625,869627,869630,869633,869639,869641-869643,869645-" + \ |
| "869652,869655,869657,869665,869668,869674,869677,869681,869685," + \ |
| "869687-869688,869693,869697,869699-869700,869704-869708,869716," + \ |
| "869719,869722,869724,869730,869733-869734,869737-869740,869745-" + \ |
| "869746,869751-869754,869766,869812-869813,869815-869818,869820," + \ |
| "869825,869837,869841,869843-869844,869858,869860-869861,869871," + \ |
| "869875,869889,869895,869898,869902,869907,869909,869926,869928-" + \ |
| "869929,869931-869933,869942-869943,869950,869952,869957-869958," + \ |
| "869969,869972,869974,869988,869994,869996,869999,870004,870013-" + \ |
| "870014,870016,870024,870032,870036,870039,870041-870043,870054," + \ |
| "870060,870068-870071,870078,870083,870094,870104,870124,870127-" + \ |
| "870128,870133,870135-870136,870141,870144,870148,870160,870172," + \ |
| "870175,870191,870198,870203-870204,870211,870219,870225,870233," + \ |
| "870235-870236,870254-870255,870259,870307,870311,870313,870320," + \ |
| "870323,870330-870331,870352-870353,870355,870359-870360,870371," + \ |
| "870373,870378,870393-870395,870402,870409-870410,870414,870416," + \ |
| "870421,870436,870442,870447,870449,870452,870454,870466,870476," + \ |
| "870481-870483,870486,870500,870502,870505,870513-870518,870522-" + \ |
| "870523,870527,870529,870534,870536-870538,870540-870541,870543-" + \ |
| "870548,870554,870556,870561,870563,870584,870590-870592,870594-" + \ |
| "870595,870597,870618,870620,870622,870625-870626,870641,870647," + \ |
| "870657,870665,870671,870681,870702-870703,870706-870708,870717-" + \ |
| "870718,870727,870730,870737,870740,870742,870752,870758,870800," + \ |
| "870809,870815,870817,870820-870825,870830,870834-870836,870850-" + \ |
| "870851,870853,870859,870861,870886,870894,870916-870918,870942," + \ |
| "870945,870957,870962,870970,870979,870981,870989,870996,871003," + \ |
| "871005,871009,871011,871023,871033,871035-871038,871041,871060," + \ |
| "871078,871080,871092,871097,871099,871105,871107,871120,871123-" + \ |
| "871127,871130,871133-871135,871140,871149,871155-871156,871160," + \ |
| "871162,871164,871181,871191,871199-871200,871205,871211-871212," + \ |
| "871215,871219,871225,871227,871229,871231,871236,871270,871273," + \ |
| "871277,871283,871297,871302,871306,871308,871315-871320,871323-" + \ |
| "871325,871333-871335,871345,871347-871350,871354,871357,871361," + \ |
| "871363-871366,871374-871375,871377,871382,871385-871388,871391," + \ |
| "871408,871411,871422,871435,871441,871443-871444,871465,871470," + \ |
| "871472-871476,871481,871489,871499,871501-871502,871505,871508," + \ |
| "871520,871523,871525-871527,871538,871542,871544,871547-871549," + \ |
| "871556,871559,871562-871563,871578,871581,871587,871589-871597," + \ |
| "871608,871613,871616-871617,871620,871624,871649,871668,871675," + \ |
| "871677,871693-871694,871696,871704,871732-871733,871744,871747," + \ |
| "871759,871762,871766,871769,871793,871796,871799,871801,871811," + \ |
| "871813,871821-871826,871831,871843,871860,871880,871891,871894," + \ |
| "871899,871907,871911,871926,871928,871933,871935,871941-871942," + \ |
| "871947-871949,871958,871974,872000-872001,872003,872005,872018," + \ |
| "872022,872038,872065,872068,872086,872091,872093,872097,872103," + \ |
| "872112,872130,872154,872157,872206,872216,872218-872219,872227," + \ |
| "872234,872238,872243,872253,872255,872259,872261,872278-872279," + \ |
| "872281,872310-872311,872362,872404,872416-872417,872429,872431," + \ |
| "872434,872439,872450-872453,872468,872470,872477-872478,872483," + \ |
| "872490-872491,872495,872515-872516,872518-872519,872537,872541," + \ |
| "872544,872565,872568,872571-872573,872584,872596-872597,872612," + \ |
| "872619,872624,872632,872656,872670,872706,872710,872713,872717," + \ |
| "872746-872748,872777,872780-872782,872791,872804,872813,872845," + \ |
| "872864,872870,872872,872947-872948,872961,872974,872981,872985-" + \ |
| "872987,873004,873042,873049,873051,873076,873087,873090,873096," + \ |
| "873098,873100,873183,873186,873192,873195,873210-873211,873247," + \ |
| "873252,873256,873259,873275,873286,873288,873343,873379-873381," + \ |
| "873443,873521,873538-873539,873714-873715,873718,873733,873745," + \ |
| "873751,873767,873778,873781,873849,873856,873862,873914,873940," + \ |
| "873947-873948,873975-873976,873987,873998,874026-874027,874075," + \ |
| "874077-874078,874124-874125,874127,874156,874159,874161,874165," + \ |
| "874168,874170,874184,874189,874204,874223-874224,874245,874258," + \ |
| "874262,874270,874292-874297,874300-874301,874303,874305,874316-" + \ |
| "874318,874330,874363,874380,874405,874421,874441,874459,874467," + \ |
| "874473,874497,874506,874545-874546,874561,874566,874568,874580," + \ |
| "874619,874621,874634,874636,874659,874673,874681,874727,874730," + \ |
| "874743,874765-874767,874806,874816,874848,874868,874888,874896," + \ |
| "874909,874912,874996,875051,875069,875129,875132,875134,875137," + \ |
| "875151-875153,875186-875188,875190,875235-875237,875242-875243," + \ |
| "875249,875388,875393,875406,875411\n" |
| |
| # Set the 'big' mergeinfo prop on A/B, A/C, and A/D. |
| svntest.main.file_write(prop_val_file, big_prop_val) |
| |
| svntest.actions.run_and_verify_svn(None, [], 'propset', |
| SVN_PROP_MERGEINFO, '-F', prop_val_file, |
| B_path) |
| svntest.actions.run_and_verify_svn(None, [], 'propset', |
| SVN_PROP_MERGEINFO, '-F', prop_val_file, |
| C_path) |
| svntest.actions.run_and_verify_svn(None, [], 'propset', |
| SVN_PROP_MERGEINFO, '-F', prop_val_file, |
| D_path) |
| svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', |
| 'ps some large svn:mergeinfos', wc_dir) |
| |
| # Run propget -vR svn:mergeinfo, redirecting the stdout to a file. |
| arglist = [svntest.main.svn_binary, 'propget', SVN_PROP_MERGEINFO, '-vR', |
| '--config-dir', svntest.main.default_config_dir, wc_dir] |
| redir_file = open(redirect_file, 'wb') |
| pg_proc = subprocess.Popen(arglist, stdout=redir_file) |
| pg_proc.wait() |
| redir_file.close() |
| pg_stdout_redir = open(redirect_file, 'r').readlines() |
| |
| # Check if the redirected output of svn pg -vR on the root of the WC |
| # is what we expect. |
| expected_mergeinfo_displayed = [ |
| ' /' + line for line in big_prop_val.splitlines(True) ] |
| expected_output = [ |
| "Properties on '" + B_path + "':\n", # Should ocur only once! |
| " svn:mergeinfo\n", |
| ] + expected_mergeinfo_displayed + [ |
| "Properties on '" + C_path + "':\n", # Should ocur only once! |
| " svn:mergeinfo\n", |
| ] + expected_mergeinfo_displayed + [ |
| "Properties on '" + D_path + "':\n", # Should ocur only once! |
| " svn:mergeinfo\n", |
| ] + expected_mergeinfo_displayed |
| svntest.verify.verify_outputs( |
| "Redirected pg -vR doesn't match pg -vR stdout", |
| pg_stdout_redir, None, |
| svntest.verify.UnorderedOutput(expected_output), None) |
| # (We want this check to fail if the redirected pg output contains |
| # unexpected duplicate lines, although this hasn't been observed as |
| # part of issue #3721. We used to check separately here because the old |
| # UnorderedOutput class ignored duplicates but now it detects them.) |
| |
| @Issue(3852) |
| def file_matching_dir_prop_reject(sbox): |
| "prop conflict for file matching dir prop reject" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Add file with awkward name |
| svntest.main.file_append(sbox.ospath('A/dir_conflicts'), "some content\n") |
| svntest.actions.run_and_verify_svn(None, [], |
| 'add', sbox.ospath('A/dir_conflicts')) |
| sbox.simple_propset('prop', 'val1', 'A/dir_conflicts') |
| sbox.simple_propset('prop', 'val1', 'A') |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A' : Item(verb='Sending'), |
| 'A/dir_conflicts' : Item(verb='Adding'), |
| }) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A', wc_rev=2) |
| expected_status.add({ |
| 'A/dir_conflicts' : Item(status=' ', wc_rev=2), |
| }) |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Modify/commit property change |
| sbox.simple_propset('prop', 'val2', 'A/dir_conflicts') |
| sbox.simple_propset('prop', 'val2', 'A') |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A' : Item(verb='Sending'), |
| 'A/dir_conflicts' : Item(verb='Sending'), |
| }) |
| expected_status.tweak('A', 'A/dir_conflicts', wc_rev=3) |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| expected_status) |
| |
| # Local property mod |
| sbox.simple_propset('prop', 'val3', 'A/dir_conflicts') |
| sbox.simple_propset('prop', 'val3', 'A') |
| |
| # Update to trigger property conflicts |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.add({ |
| 'A/dir_conflicts' : Item('some content\n', props = {'prop' : 'val3'}), |
| }) |
| expected_disk.tweak('A', props={'prop' : 'val3'}) |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A' : Item(status=' C'), |
| 'A/dir_conflicts' : Item(status=' C'), |
| }) |
| expected_status.tweak(wc_rev=2) |
| expected_status.tweak('A', 'A/dir_conflicts', status=' C') |
| |
| # Conflict: BASE=val2 WORKING=val3 INCOMING_OLD=val2 INCOMING_NEW=val1 |
| extra_files = ['dir_conflicts.prej', 'dir_conflicts.2.prej'] |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| expected_disk, |
| expected_status, |
| [], True, |
| '-r', '2', wc_dir, |
| extra_files=extra_files) |
| |
| # Revert and update to check that conflict files are removed |
| svntest.actions.run_and_verify_svn(None, [], 'revert', '-R', wc_dir) |
| expected_status.tweak('A', 'A/dir_conflicts', status=' ') |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A' : Item(status=' U'), |
| 'A/dir_conflicts' : Item(status=' U'), |
| }) |
| expected_disk.tweak('A', 'A/dir_conflicts', props={'prop' : 'val2'}) |
| expected_status.tweak(wc_rev=3) |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| expected_disk, |
| expected_status, |
| check_props=True) |
| |
| def pristine_props_listed(sbox): |
| "check if pristine properties are visible" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| sbox.simple_propset('prop', 'val', 'A') |
| sbox.simple_commit() |
| |
| expected_output = ["Properties on '" + sbox.ospath('A') + "':\n", " prop\n"] |
| |
| # Now we see the pristine properties |
| svntest.actions.run_and_verify_svn(expected_output, [], |
| 'proplist', '-R', wc_dir, '-r', 'BASE') |
| |
| sbox.simple_propset('prop', 'needs-fix', 'A') |
| |
| # And now we see no property at all |
| svntest.actions.run_and_verify_svn(expected_output, [], |
| 'proplist', '-R', wc_dir, '-r', 'BASE') |
| |
| def create_inherited_ignores_config(sbox): |
| "create config stuffs for inherited ignores tests" |
| |
| # contents of the file 'config' |
| config_contents = '''\ |
| [miscellany] |
| global-ignores = *.boo *.goo |
| ''' |
| |
| return sbox.create_config_dir(config_contents) |
| |
| def inheritable_ignores(sbox): |
| "inheritable ignores with svn:ignores and config" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| config_dir = create_inherited_ignores_config(sbox) |
| |
| sbox.simple_propset(SVN_PROP_INHERITABLE_IGNORES, '*.doo', 'A/B') |
| sbox.simple_propset(SVN_PROP_INHERITABLE_IGNORES, '*.moo', 'A/D') |
| sbox.simple_propset('svn:ignore', '*.foo', 'A/B/E') |
| sbox.simple_commit() |
| |
| # Some directories and files that should always be added because they |
| # don't match any applicable ignore patterns. |
| X_dir_path = sbox.ospath('ADD-ME-DIR-X') |
| Y_dir_path = sbox.ospath('A/ADD-ME-DIR-Y.doo') |
| Z_dir_path = sbox.ospath('A/D/G/ADD-ME-DIR-Z.doo') |
| os.mkdir(X_dir_path) |
| os.mkdir(Y_dir_path) |
| os.mkdir(Z_dir_path) |
| |
| # Some directories and files that should be ignored when adding |
| # because they match an ignore pattern (unless of course they are |
| # the direct target of an add, which we always add). |
| boo_dir_path = sbox.ospath('IGNORE-ME-DIR.boo') |
| goo_dir_path = sbox.ospath('IGNORE-ME-DIR.boo/IGNORE-ME-DIR.goo') |
| doo_dir_path = sbox.ospath('A/B/IGNORE-ME-DIR.doo') |
| moo_dir_path = sbox.ospath('A/D/IGNORE-ME-DIR.moo') |
| foo_dir_path = sbox.ospath('A/B/E/IGNORE-ME-DIR.foo') |
| os.mkdir(boo_dir_path) |
| os.mkdir(goo_dir_path) |
| os.mkdir(doo_dir_path) |
| os.mkdir(moo_dir_path) |
| os.mkdir(foo_dir_path) |
| boo_file_path = sbox.ospath('ADD-ME-DIR-X/ignore-me-file.boo') |
| goo_file_path = sbox.ospath('A/D/G/ignore-me-file.goo') |
| doo_file_path = sbox.ospath('A/B/IGNORE-ME-DIR.doo/ignore-me-file.doo') |
| doo_file2_path = sbox.ospath('A/B/E/ignore-me-file.doo') |
| moo_file_path = sbox.ospath('A/D/ignore-me-file.moo') |
| foo_file_path = sbox.ospath('A/B/E/ignore-me-file.foo') |
| svntest.main.file_write(boo_file_path, 'I should not be versioned!\n') |
| svntest.main.file_write(goo_file_path, 'I should not be versioned!\n') |
| svntest.main.file_write(doo_file_path, 'I should not be versioned!\n') |
| svntest.main.file_write(doo_file2_path, 'I should not be versioned!\n') |
| svntest.main.file_write(moo_file_path, 'I should not be versioned!\n') |
| svntest.main.file_write(foo_file_path, 'I should not be versioned!\n') |
| |
| # Some directories and files that don't match any ignore pattern |
| # but are located within a subtree that does match and so shouldn't |
| # be added. |
| roo_file_path = sbox.ospath('A/B/IGNORE-ME-DIR.doo/ignore-me-file.roo') |
| svntest.main.file_write(roo_file_path, 'I should not be versioned!\n') |
| |
| # Check (non-verbose) status with the custom config. We should only see |
| # the three unversioned directories which don't match any of the ignore |
| # patterns and aren't proper subtrees of an unversioned or ignored |
| # subtree. |
| expected_output = svntest.verify.UnorderedOutput( |
| ['? ' + X_dir_path + '\n', |
| '? ' + Y_dir_path + '\n', |
| '? ' + Z_dir_path + '\n',]) |
| svntest.actions.run_and_verify_svn(expected_output, [], 'st', |
| '--config-dir', config_dir, wc_dir) |
| |
| # Check status without the custom config. |
| # Should be the same as above except the *.boo and *.goo paths |
| # now show up as unversioned '?'. |
| expected_output = svntest.verify.UnorderedOutput( |
| ['? ' + X_dir_path + '\n', |
| '? ' + Y_dir_path + '\n', |
| '? ' + Z_dir_path + '\n', |
| '? ' + boo_dir_path + '\n', |
| '? ' + goo_file_path + '\n',]) |
| svntest.actions.run_and_verify_svn(expected_output, [], 'st', wc_dir) |
| |
| # Check status with the custom config and --no-ignore. |
| expected_output = svntest.verify.UnorderedOutput( |
| ['? ' + X_dir_path + '\n', |
| '? ' + Y_dir_path + '\n', |
| '? ' + Z_dir_path + '\n', |
| 'I ' + boo_dir_path + '\n', |
| 'I ' + doo_dir_path + '\n', |
| 'I ' + doo_file2_path + '\n', |
| 'I ' + moo_dir_path + '\n', |
| 'I ' + foo_dir_path + '\n', |
| 'I ' + goo_file_path + '\n', |
| 'I ' + moo_file_path + '\n', |
| 'I ' + foo_file_path + '\n',]) |
| svntest.actions.run_and_verify_svn(expected_output, [], 'st', |
| '--config-dir', config_dir, |
| '--no-ignore', wc_dir) |
| |
| # Check status without the custom config and --no-ignore. |
| # Should be the same as above except the *.boo and *.goo paths |
| # are reported as unversioned '?' rather than ignored 'I'. |
| expected_output = svntest.verify.UnorderedOutput( |
| ['? ' + X_dir_path + '\n', |
| '? ' + Y_dir_path + '\n', |
| '? ' + Z_dir_path + '\n', |
| '? ' + boo_dir_path + '\n', |
| 'I ' + doo_dir_path + '\n', |
| 'I ' + doo_file2_path + '\n', |
| 'I ' + moo_dir_path + '\n', |
| 'I ' + foo_dir_path + '\n', |
| '? ' + goo_file_path + '\n', |
| 'I ' + moo_file_path + '\n', |
| 'I ' + foo_file_path + '\n',]) |
| svntest.actions.run_and_verify_svn(expected_output, [], 'st', |
| '--no-ignore', wc_dir) |
| |
| # Perform the add with the --force flag, targeting the root of the WC. |
| ### Note: You have to be inside the working copy or else Subversion |
| ### will think you're trying to add the working copy to its parent |
| ### directory, and will (possibly, if the parent directory isn't |
| ### versioned) fail -- see also schedule_tests.py 11 "'svn add' |
| ### should traverse already-versioned dirs" |
| saved_wd = os.getcwd() |
| os.chdir(sbox.wc_dir) |
| expected = svntest.verify.UnorderedOutput( |
| ['A ' + 'ADD-ME-DIR-X\n', |
| 'A ' + os.path.join('A', 'ADD-ME-DIR-Y.doo') + '\n', |
| 'A ' + os.path.join('A', 'D', 'G', 'ADD-ME-DIR-Z.doo') + '\n']) |
| svntest.actions.run_and_verify_svn(expected, |
| [], 'add', '.', '--force', |
| '--config-dir', config_dir) |
| os.chdir(saved_wd) |
| |
| # Now revert and try the add with the --no-ignore flag, nothing should |
| # be ignored. |
| svntest.actions.run_and_verify_svn(None, [], 'revert', wc_dir, '-R') |
| saved_wd = os.getcwd() |
| os.chdir(sbox.wc_dir) |
| expected = svntest.verify.UnorderedOutput( |
| ['A ' + 'ADD-ME-DIR-X\n', |
| 'A ' + os.path.join('A', 'ADD-ME-DIR-Y.doo') + '\n', |
| 'A ' + os.path.join('A', 'D', 'G', 'ADD-ME-DIR-Z.doo') + '\n', |
| 'A ' + os.path.join('ADD-ME-DIR-X', 'ignore-me-file.boo') + '\n', |
| 'A ' + 'IGNORE-ME-DIR.boo' + '\n', |
| 'A ' + os.path.join('IGNORE-ME-DIR.boo', |
| 'IGNORE-ME-DIR.goo') + '\n', |
| 'A ' + os.path.join('A', 'B', 'E', 'IGNORE-ME-DIR.foo') + '\n', |
| 'A ' + os.path.join('A', 'B', 'E', 'ignore-me-file.foo') + '\n', |
| 'A ' + os.path.join('A', 'D', 'G', 'ignore-me-file.goo') + '\n', |
| |
| 'A ' + os.path.join('A', 'B', 'E', 'ignore-me-file.doo') + '\n', |
| 'A ' + os.path.join('A', 'B', 'IGNORE-ME-DIR.doo') + '\n', |
| 'A ' + os.path.join('A', 'B', 'IGNORE-ME-DIR.doo', |
| 'ignore-me-file.doo') + '\n', |
| 'A ' + os.path.join('A', 'B', 'IGNORE-ME-DIR.doo', |
| 'ignore-me-file.roo') + '\n', |
| 'A ' + os.path.join('A', 'D', 'IGNORE-ME-DIR.moo') + '\n', |
| 'A ' + os.path.join('A', 'D', 'ignore-me-file.moo') + '\n']) |
| svntest.actions.run_and_verify_svn(expected, [], 'add', '.', '--force', |
| '--no-ignore', '--config-dir', |
| config_dir) |
| |
| def almost_known_prop_names(sbox): |
| "propset with svn: prefix but unknown name" |
| |
| sbox.build(read_only=True) |
| wc_dir = sbox.wc_dir |
| iota_path = sbox.ospath('iota') |
| |
| # Same prefix, different prop name |
| svntest.actions.set_prop('svn:exemutable', 'x', iota_path, |
| "svn: E195011: 'svn:exemutable' " |
| "is not a valid svn: property name") |
| svntest.actions.set_prop('svn:exemutable', 'x', iota_path, force=True) |
| |
| # Similar prefix, different prop name |
| svntest.actions.set_prop('svm:exemutable', 'x', iota_path) |
| |
| # Similar prefix, same prop name |
| svntest.actions.set_prop('svm:executable', 'x', iota_path, |
| "svn: E195011: 'svm:executable' " |
| "is not a valid svn: property name") |
| svntest.actions.set_prop('svm:executable', 'x', iota_path, force=True) |
| |
| # Different prefix, same prop name |
| svntest.actions.set_prop('tsvn:executable', 'x', iota_path) |
| |
| # Property name is too different to matter |
| svntest.actions.set_prop('svn:foobar', 'x', iota_path, |
| "svn: E195011: 'svn:foobar'" |
| " is not a valid svn: property name;" |
| " use '--force' to set it") |
| |
| @Issue(3231) |
| def peg_rev_base_working(sbox): |
| """peg rev @BASE, peg rev @WORKING""" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # set up a local prop mod |
| svntest.actions.set_prop('ordinal', 'ninth\n', sbox.ospath('iota')) |
| sbox.simple_commit(message='r2') |
| svntest.actions.set_prop('cardinal', 'nine\n', sbox.ospath('iota')) |
| svntest.actions.run_and_verify_svn(['ninth\n'], [], |
| 'propget', '--no-newline', 'ordinal', |
| sbox.ospath('iota') + '@BASE') |
| |
| @Issue(4415) |
| def xml_unsafe_author(sbox): |
| "svn:author with XML unsafe chars" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| svntest.actions.enable_revprop_changes(sbox.repo_dir) |
| |
| # client sends svn:author (via PROPPATCH for DAV) |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--revprop', '-r', '1', |
| 'svn:author', 'foo\bbar', wc_dir) |
| |
| # mod_dav_svn sends svn:author (via REPORT for DAV) |
| sbox.simple_update(revision=0) |
| sbox.simple_update(revision=1) |
| expected_info = [{ |
| 'Path' : re.escape(wc_dir), |
| 'Repository Root' : sbox.repo_url, |
| 'Repository UUID' : svntest.actions.get_wc_uuid(wc_dir), |
| 'Last Changed Author' : 'foo\bbar', |
| }] |
| svntest.actions.run_and_verify_info(expected_info, wc_dir) |
| |
| # mod_dav_svn sends svn:author (via PROPFIND for DAV) |
| # Since r1553367 this works correctly on ra_serf, since we now request |
| # a single property value which skips creating the creator-displayname property |
| svntest.actions.run_and_verify_svn(['foo\bbar'], [], |
| 'propget', '--revprop', '-r', '1', |
| 'svn:author', '--no-newline', wc_dir) |
| |
| # Ensure a stable date |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--revprop', '-r', '1', |
| 'svn:date', '2015-01-01T00:00:00.0Z', wc_dir) |
| |
| # But a proplist of this property value still fails via DAV. |
| expected_output = svntest.verify.UnorderedOutput([ |
| 'Unversioned properties on revision 1:\n', |
| ' svn:author\n', |
| ' foo\bbar\n', |
| ' svn:date\n', |
| ' 2015-01-01T00:00:00.0Z\n', |
| ' svn:log\n', |
| ' Log message for revision 1.\n' |
| ]) |
| svntest.actions.run_and_verify_svn(expected_output, [], |
| 'proplist', '--revprop', '-r', '1', '-v', |
| wc_dir) |
| |
| @Issue(4415) |
| def xml_unsafe_author2(sbox): |
| "svn:author with XML unsafe chars 2" |
| |
| sbox.build(create_wc = False) |
| repo_url = sbox.repo_url |
| |
| svntest.actions.enable_revprop_changes(sbox.repo_dir) |
| |
| # client sends svn:author (via PROPPATCH for DAV) |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--revprop', '-r', '1', |
| 'svn:author', 'foo\bbar', repo_url) |
| |
| # Ensure a stable date |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--revprop', '-r', '1', |
| 'svn:date', '2000-01-01T12:00:00.0Z', |
| repo_url) |
| |
| if svntest.main.is_ra_type_dav(): |
| # This receives the filtered author (but that is better than an Xml fail) |
| expected_author = 'foobar' |
| else: |
| expected_author = 'foo\bbar' |
| |
| # Use svn ls in --xml mode to test locale independent output. |
| expected_output = [ |
| '<?xml version="1.0" encoding="UTF-8"?>\n', |
| '<lists>\n', |
| '<list\n', |
| ' path="%s">\n' % sbox.repo_url, |
| '<entry\n', |
| ' kind="dir">\n', |
| '<name>A</name>\n', |
| '<commit\n', |
| ' revision="1">\n', |
| '<author>%s</author>\n' % expected_author, |
| '<date>2000-01-01T12:00:00.000000Z</date>\n', |
| '</commit>\n', |
| '</entry>\n', |
| '<entry\n', |
| ' kind="file">\n', |
| '<name>iota</name>\n', |
| '<size>25</size>\n', |
| '<commit\n', |
| ' revision="1">\n', |
| '<author>%s</author>\n' % expected_author, |
| '<date>2000-01-01T12:00:00.000000Z</date>\n', |
| '</commit>\n', |
| '</entry>\n', |
| '</list>\n', |
| '</lists>\n' |
| ] |
| |
| svntest.actions.run_and_verify_svn(expected_output, [], |
| 'ls', '--xml', repo_url) |
| |
| expected_info = [{ |
| 'Repository Root' : sbox.repo_url, |
| 'Last Changed Author' : expected_author, |
| }] |
| svntest.actions.run_and_verify_info(expected_info, repo_url) |
| |
| def dir_prop_conflict_details(sbox): |
| "verify dir property conflict details" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Apply some changes |
| sbox.simple_propset('svn:mergeinfo', '/B:1', 'A') |
| sbox.simple_propset('my-prop', 'my-val', 'A') |
| sbox.simple_commit() |
| |
| # Revert to r1 |
| sbox.simple_update('', revision=1) |
| |
| # Apply some incompatible changes |
| sbox.simple_propset('svn:mergeinfo', '/C:1', 'A') |
| sbox.simple_propset('my-prop', 'other-val', 'A') |
| |
| # This should report out of date because there are incompatible property |
| # changes that can't be merged on the server |
| svntest.actions.run_and_verify_commit(wc_dir, |
| None, |
| None, |
| '.*[Oo]ut of date.*') |
| |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A' : Item(status=' C'), |
| }) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 2) |
| expected_status.tweak('A', status=' C') |
| |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| None, |
| expected_status, |
| check_props=True) |
| expected_info = { |
| 'Conflicted Properties' : 'my-prop', |
| 'Conflict Details': re.escape('incoming dir edit upon update' |
| + ' Source left: (dir) ^/A@1' |
| + ' Source right: (dir) ^/A@2') |
| } |
| svntest.actions.run_and_verify_info([expected_info], sbox.path('A')) |
| |
| |
| def iprops_list_abspath(sbox): |
| "test listing iprops via abspath" |
| |
| sbox.build() |
| |
| sbox.simple_propset('im', 'root', '') |
| sbox.simple_commit() |
| |
| svntest.actions.run_and_verify_svn(None, [], |
| 'switch', '^/A/D', sbox.ospath(''), |
| '--ignore-ancestry') |
| |
| sbox.simple_propset('im', 'GammA', 'gamma') |
| |
| expected_output = [ |
| 'Inherited properties on \'%s\',\n' % sbox.ospath(''), |
| 'from \'%s\':\n' % sbox.repo_url, |
| ' im\n', |
| ' root\n', |
| 'Properties on \'%s\':\n' % sbox.ospath('gamma'), |
| ' im\n', |
| ' GammA\n' |
| ] |
| svntest.actions.run_and_verify_svn(expected_output, [], |
| 'pl', '-R', |
| '--show-inherited-props', '-v', |
| sbox.ospath('')) |
| |
| expected_output = [ |
| 'Inherited properties on \'%s\',\n' % os.path.abspath(sbox.ospath('')), |
| 'from \'%s\':\n' % sbox.repo_url, |
| ' im\n', |
| ' root\n', |
| 'Properties on \'%s\':\n' % os.path.abspath(sbox.ospath('gamma')), |
| ' im\n', |
| ' GammA\n' |
| ] |
| svntest.actions.run_and_verify_svn(expected_output, [], |
| 'pl', '-R', |
| '--show-inherited-props', '-v', |
| os.path.abspath(sbox.ospath(''))) |
| |
| def wc_propop_on_url(sbox): |
| "perform wc specific operations on url" |
| |
| sbox.build(create_wc = False) |
| |
| svntest.actions.run_and_verify_svn(None, '.*E195000:.*path', |
| 'pl', '-r', 'PREV', |
| sbox.repo_url) |
| |
| svntest.actions.run_and_verify_svn(None, '.*E195000:.*path', |
| 'pg', 'my:Q', '-r', 'PREV', |
| sbox.repo_url) |
| |
| def prop_conflict_root(sbox): |
| """property conflict on wc root""" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| sbox.simple_propset('propname', 'propval1', '') |
| sbox.simple_commit() |
| sbox.simple_propset('propname', 'propval2', '') |
| sbox.simple_commit() |
| sbox.simple_update(revision=2) |
| sbox.simple_propset('propname', 'propvalconflict', '') |
| |
| expected_output = svntest.wc.State(wc_dir, { |
| '' : Item(status=' C'), |
| }) |
| expected_disk = svntest.main.greek_state.copy() |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 3) |
| expected_status.tweak('', status=' C') |
| extra_files = ['dir_conflicts.prej'] |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| expected_disk, |
| expected_status, |
| extra_files=extra_files) |
| |
| |
| # Test that editing a regular property creates a temporary file named |
| # "svn-prop.tmp" whereas editing a revprop results in a temporary file |
| # named "svn-revprop-rN.tmp" (where "N" is the number of the revision |
| # whose revprop would be edited). |
| def tmpfile_name_matches_prop_type(sbox): |
| "propedit tmpfile name matches property type" |
| |
| sbox.build(read_only=True) |
| |
| # We want the editor invocation to fail -- all we care about is the |
| # name of the tmpfile left over after that failure. I'm guessing |
| # you don't have a editor named this on your system: |
| non_editor = 'af968da2ce9' |
| |
| svntest.actions.run_and_verify_svn( |
| None, |
| '.*' + re.escape(non_editor) + r'.*svn-revprop-r1\.tmp.*', |
| 'propedit', '--revprop', |
| '--editor-cmd', non_editor, |
| '-r1', 'svn:log', |
| sbox.repo_url) |
| |
| svntest.actions.run_and_verify_svn( |
| None, |
| '.*' + re.escape(non_editor) + r'.*svn-prop\.tmp.*', |
| 'propedit', |
| '--editor-cmd', non_editor, |
| 'ignored-propname', |
| sbox.ospath('A/mu')) |
| |
| |
| ######################################################################## |
| # Run the tests |
| |
| # list all tests here, starting with None: |
| test_list = [ None, |
| make_local_props, |
| commit_props, |
| update_props, |
| downdate_props, |
| remove_props, |
| update_conflict_props, |
| commit_conflict_dirprops, |
| commit_replacement_props, |
| revert_replacement_props, |
| inappropriate_props, |
| copy_inherits_special_props, |
| revprop_change, |
| prop_value_conversions, |
| binary_props, |
| recursive_base_wc_ops, |
| url_props_ops, |
| removal_schedule_added_props, |
| update_props_on_wc_root, |
| props_on_replaced_file, |
| depthy_wc_proplist, |
| depthy_url_proplist, |
| invalid_propnames, |
| perms_on_symlink, |
| remove_custom_ns_props, |
| props_over_time, |
| invalid_propvalues, |
| same_replacement_props, |
| added_moved_file, |
| delete_nonexistent_property, |
| post_revprop_change_hook, |
| rm_of_replaced_file, |
| prop_reject_grind, |
| obstructed_subdirs, |
| atomic_over_ra, |
| propget_redirection, |
| file_matching_dir_prop_reject, |
| pristine_props_listed, |
| inheritable_ignores, |
| almost_known_prop_names, |
| peg_rev_base_working, |
| xml_unsafe_author, |
| xml_unsafe_author2, |
| dir_prop_conflict_details, |
| iprops_list_abspath, |
| wc_propop_on_url, |
| prop_conflict_root, |
| tmpfile_name_matches_prop_type, |
| ] |
| |
| if __name__ == '__main__': |
| svntest.main.run_tests(test_list) |
| # NOTREACHED |
| |
| |
| ### End of file. |