blob: e755c687ca5ec008f8fe22d0834b5fcf90a67bf7 [file] [log] [blame]
#!/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.