blob: 7f7591eb2363bd83b326c2edda6fb562f0cc3629 [file] [log] [blame]
#!/usr/bin/env python
#
# commit_tests.py: testing fancy commit cases.
#
# 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, os, re
# Our testing module
import svntest
from svntest import wc
from prop_tests import binary_mime_type_on_text_file_warning
# (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
from svntest.main import server_has_revprop_commit, \
server_gets_client_capabilities
from svntest.actions import inject_conflict_into_wc
######################################################################
# Utilities
#
def is_non_posix_os_or_cygwin_platform():
return (not svntest.main.is_posix_os()) or sys.platform == 'cygwin'
def get_standard_state(wc_dir):
"""Return a status list reflecting the local mods made by
make_standard_slew_of_changes()."""
state = svntest.actions.get_virginal_state(wc_dir, 1)
state.tweak('', 'A/D', 'A/D/G/pi', status=' M')
state.tweak('A/B/lambda', status='M ')
state.tweak('A/B/E', 'A/D/H/chi', status='R ')
state.tweak('A/B/E/alpha', 'A/B/E/beta', 'A/C', 'A/D/gamma',
'A/D/G/rho', status='D ')
state.tweak('A/D/H/omega', status='MM')
# New things
state.add({
'Q' : Item(status='A ', wc_rev=0),
'Q/floo' : Item(status='A ', wc_rev=0),
'A/D/H/gloo' : Item(status='A ', wc_rev=0),
'A/B/E/bloo' : Item(status='A ', wc_rev=0),
})
return state
def make_standard_slew_of_changes(wc_dir):
"""Make a specific set of local mods to WC_DIR. These will be used
by every commit-test. Verify the 'svn status' output, and return the
(pre-commit) status tree."""
# Cache current working directory, move into wc_dir
was_cwd = os.getcwd()
os.chdir(wc_dir)
# Add a directory
os.mkdir('Q')
svntest.main.run_svn(None, 'add', 'Q')
# Remove two directories
A_B_E = os.path.join('A', 'B', 'E')
svntest.main.run_svn(None, 'rm', A_B_E)
svntest.main.run_svn(None, 'rm', os.path.join('A', 'C'))
# Replace one of the removed directories
# But first recreate if it doesn't exist (single-db)
if not os.path.exists(A_B_E):
os.mkdir(A_B_E)
svntest.main.run_svn(None, 'add', A_B_E)
# Make property mods to two directories
svntest.main.run_svn(None, 'propset', 'foo', 'bar', os.curdir)
svntest.main.run_svn(None, 'propset', 'foo2', 'bar2', os.path.join('A', 'D'))
# Add three files
svntest.main.file_append(os.path.join('A', 'B', 'E', 'bloo'), "hi")
svntest.main.file_append(os.path.join('A', 'D', 'H', 'gloo'), "hello")
svntest.main.file_append(os.path.join('Q', 'floo'), "yo")
svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'E', 'bloo'))
svntest.main.run_svn(None, 'add', os.path.join('A', 'D', 'H', 'gloo'))
svntest.main.run_svn(None, 'add', os.path.join('Q', 'floo'))
# Remove three files
svntest.main.run_svn(None, 'rm', os.path.join('A', 'D', 'G', 'rho'))
svntest.main.run_svn(None, 'rm', os.path.join('A', 'D', 'H', 'chi'))
svntest.main.run_svn(None, 'rm', os.path.join('A', 'D', 'gamma'))
# Replace one of the removed files
svntest.main.file_append(os.path.join('A', 'D', 'H', 'chi'), "chi")
svntest.main.run_svn(None, 'add', os.path.join('A', 'D', 'H', 'chi'))
# Make textual mods to two files
svntest.main.file_append(os.path.join('A', 'B', 'lambda'), "new ltext")
svntest.main.file_append(os.path.join('A', 'D', 'H', 'omega'), "new otext")
# Make property mods to three files
svntest.main.run_svn(None, 'propset', 'blue', 'azul',
os.path.join('A', 'D', 'H', 'omega'))
svntest.main.run_svn(None, 'propset', 'green', 'verde',
os.path.join('Q', 'floo'))
svntest.main.run_svn(None, 'propset', 'red', 'rojo',
os.path.join('A', 'D', 'G', 'pi'))
# Restore the CWD.
os.chdir(was_cwd)
# Build an expected status tree.
expected_status = get_standard_state(wc_dir)
# Verify status -- all local mods should be present.
svntest.actions.run_and_verify_status(wc_dir, expected_status)
return expected_status
######################################################################
# Tests
#
# Each test must return on success or raise on failure.
#----------------------------------------------------------------------
def commit_one_file(sbox):
"commit one file"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
omega_path = sbox.ospath('A/D/H/omega')
# Create expected state.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/omega' : Item(verb='Sending'),
})
expected_status.tweak('A/D/H/omega', wc_rev=2, status=' ')
# Commit the one file.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
omega_path)
#----------------------------------------------------------------------
def commit_one_new_file(sbox):
"commit one newly added file"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
gloo_path = sbox.ospath('A/D/H/gloo')
# Create expected state.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/gloo' : Item(verb='Adding'),
})
expected_status.tweak('A/D/H/gloo', wc_rev=2, status=' ')
# Commit the one file.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
gloo_path)
#----------------------------------------------------------------------
def commit_one_new_binary_file(sbox):
"commit one newly added binary file"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
gloo_path = sbox.ospath('A/D/H/gloo')
svntest.main.run_svn(binary_mime_type_on_text_file_warning,
'propset', 'svn:mime-type',
'application/octet-stream', gloo_path)
# Create expected state.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/gloo' : Item(verb='Adding (bin)'),
})
expected_status.tweak('A/D/H/gloo', wc_rev=2, status=' ')
# Commit the one file.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
gloo_path)
#----------------------------------------------------------------------
def commit_multiple_targets(sbox):
"commit multiple targets"
sbox.build()
wc_dir = sbox.wc_dir
# This test will commit three targets: psi, B, and pi. In that order.
# Make local mods to many files.
AB_path = sbox.ospath('A/B')
lambda_path = sbox.ospath('A/B/lambda')
rho_path = sbox.ospath('A/D/G/rho')
pi_path = sbox.ospath('A/D/G/pi')
omega_path = sbox.ospath('A/D/H/omega')
psi_path = sbox.ospath('A/D/H/psi')
svntest.main.file_append(lambda_path, 'new appended text for lambda')
svntest.main.file_append(rho_path, 'new appended text for rho')
svntest.main.file_append(pi_path, 'new appended text for pi')
svntest.main.file_append(omega_path, 'new appended text for omega')
svntest.main.file_append(psi_path, 'new appended text for psi')
# Just for kicks, add a property to A/D/G as well. We'll make sure
# that it *doesn't* get committed.
ADG_path = sbox.ospath('A/D/G')
svntest.main.run_svn(None, 'propset', 'foo', 'bar', ADG_path)
# Create expected output tree for 'svn ci'. We should see changes
# only on these three targets, no others.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/psi' : Item(verb='Sending'),
'A/B/lambda' : Item(verb='Sending'),
'A/D/G/pi' : Item(verb='Sending'),
})
# Create expected status tree; all local revisions should be at 1,
# but our three targets should be at 2.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/H/psi', 'A/B/lambda', 'A/D/G/pi', wc_rev=2)
# rho and omega should still display as locally modified:
expected_status.tweak('A/D/G/rho', 'A/D/H/omega', status='M ')
# A/D/G should still have a local property set, too.
expected_status.tweak('A/D/G', status=' M')
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
psi_path, AB_path, pi_path)
#----------------------------------------------------------------------
def commit_multiple_targets_2(sbox):
"commit multiple targets, 2nd variation"
sbox.build()
wc_dir = sbox.wc_dir
# This test will commit four targets: psi, B, omega and pi. In that order.
# Make local mods to many files.
AB_path = sbox.ospath('A/B')
lambda_path = sbox.ospath('A/B/lambda')
rho_path = sbox.ospath('A/D/G/rho')
pi_path = sbox.ospath('A/D/G/pi')
omega_path = sbox.ospath('A/D/H/omega')
psi_path = sbox.ospath('A/D/H/psi')
svntest.main.file_append(lambda_path, 'new appended text for lambda')
svntest.main.file_append(rho_path, 'new appended text for rho')
svntest.main.file_append(pi_path, 'new appended text for pi')
svntest.main.file_append(omega_path, 'new appended text for omega')
svntest.main.file_append(psi_path, 'new appended text for psi')
# Just for kicks, add a property to A/D/G as well. We'll make sure
# that it *doesn't* get committed.
ADG_path = sbox.ospath('A/D/G')
svntest.main.run_svn(None, 'propset', 'foo', 'bar', ADG_path)
# Created expected output tree for 'svn ci'. We should see changes
# only on these three targets, no others.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/psi' : Item(verb='Sending'),
'A/B/lambda' : Item(verb='Sending'),
'A/D/H/omega' : Item(verb='Sending'),
'A/D/G/pi' : Item(verb='Sending'),
})
# Create expected status tree; all local revisions should be at 1,
# but our four targets should be at 2.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/H/psi', 'A/B/lambda', 'A/D/G/pi', 'A/D/H/omega',
wc_rev=2)
# rho should still display as locally modified:
expected_status.tweak('A/D/G/rho', status='M ')
# A/D/G should still have a local property set, too.
expected_status.tweak('A/D/G', status=' M')
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
psi_path, AB_path,
omega_path, pi_path)
#----------------------------------------------------------------------
def commit_inclusive_dir(sbox):
"commit wc_dir/A/D -- includes D. (anchor=A, tgt=D)"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
D_path = sbox.ospath('A/D')
# Create expected state.
expected_output = svntest.wc.State(wc_dir, {
'A/D' : Item(verb='Sending'),
'A/D/G/pi' : Item(verb='Sending'),
'A/D/G/rho' : Item(verb='Deleting'),
'A/D/H/gloo' : Item(verb='Adding'),
'A/D/H/chi' : Item(verb='Replacing'),
'A/D/H/omega' : Item(verb='Sending'),
'A/D/gamma' : Item(verb='Deleting'),
})
expected_status.remove('A/D/G/rho', 'A/D/gamma')
expected_status.tweak('A/D', 'A/D/G/pi', 'A/D/H/omega',
wc_rev=2, status=' ')
expected_status.tweak('A/D/H/chi', 'A/D/H/gloo', wc_rev=2, status=' ')
# Commit the one file.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
D_path)
#----------------------------------------------------------------------
def commit_top_dir(sbox):
"commit wc_dir -- (anchor=wc_dir, tgt={})"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
# Create expected state.
expected_output = svntest.wc.State(wc_dir, {
'' : Item(verb='Sending'),
'Q' : Item(verb='Adding'),
'Q/floo' : Item(verb='Adding'),
'A/B/E' : Item(verb='Replacing'),
'A/B/E/bloo' : Item(verb='Adding'),
'A/B/lambda' : Item(verb='Sending'),
'A/C' : Item(verb='Deleting'),
'A/D' : Item(verb='Sending'),
'A/D/G/pi' : Item(verb='Sending'),
'A/D/G/rho' : Item(verb='Deleting'),
'A/D/H/gloo' : Item(verb='Adding'),
'A/D/H/chi' : Item(verb='Replacing'),
'A/D/H/omega' : Item(verb='Sending'),
'A/D/gamma' : Item(verb='Deleting'),
})
expected_status.remove('A/D/G/rho', 'A/D/gamma', 'A/C',
'A/B/E/alpha', 'A/B/E/beta')
expected_status.tweak('A/D', 'A/D/G/pi', 'A/D/H/omega', 'Q/floo', '',
wc_rev=2, status=' ')
expected_status.tweak('A/D/H/chi', 'Q', 'A/B/E', 'A/B/E/bloo', 'A/B/lambda',
'A/D/H/gloo', wc_rev=2, status=' ')
# Commit the one file.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
wc_dir)
#----------------------------------------------------------------------
# Regression test for bug reported by Jon Trowbridge:
#
# From: Jon Trowbridge <trow@ximian.com>
# Subject: svn segfaults if you commit a file that hasn't been added
# To: dev@subversion.tigris.org
# Date: 17 Jul 2001 03:20:55 -0500
# Message-Id: <995358055.16975.5.camel@morimoto>
#
# The problem is that report_single_mod in libsvn_wc/adm_crawler.c is
# called with its entry parameter as NULL, but the code doesn't
# check that entry is non-NULL before trying to dereference it.
#
# This bug never had an issue number.
#
def commit_unversioned_thing(sbox):
"committing unversioned object produces error"
sbox.build()
wc_dir = sbox.wc_dir
# Create an unversioned file in the wc.
svntest.main.file_append(sbox.ospath('blorg'), "nothing to see")
# Commit a non-existent file and *expect* failure:
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
".*is not under version control.*",
os.path.join(wc_dir,'blorg'))
#----------------------------------------------------------------------
# regression test for bug #391
def nested_dir_replacements(sbox):
"replace two nested dirs, verify empty contents"
sbox.build()
wc_dir = sbox.wc_dir
A_D = sbox.ospath('A/D')
# Delete and re-add A/D (a replacement), and A/D/H (another replace).
svntest.main.run_svn(None, 'rm', A_D)
# Recreate directories for single-db
if not os.path.exists(A_D):
os.mkdir(A_D)
os.mkdir(os.path.join(A_D, 'H'))
svntest.main.run_svn(None, 'add', '--depth=empty', A_D)
svntest.main.run_svn(None, 'add', '--depth=empty', os.path.join(A_D, 'H'))
# For kicks, add new file A/D/bloo.
svntest.main.file_append(os.path.join(A_D, 'bloo'), "hi")
svntest.main.run_svn(None, 'add', os.path.join(A_D, 'bloo'))
# Verify pre-commit status:
#
# - A/D should both be scheduled as addition, A/D as "R" at rev 1
# (rev 1 because they both existed before at rev 1)
#
# - A/D/H should be a local addition "A"
# (and exists as shadowed node in BASE)
#
# - A/D/bloo scheduled as "A" at rev 0
# (rev 0 because it did not exist before)
#
# - ALL other children of A/D scheduled as "D" at rev 1
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D', status='R ', wc_rev=1)
# In the entries world we couldn't represent H properly, so it shows
# A/D/H as a replacement against BASE
expected_status.tweak('A/D/H', status='A ', wc_rev='-',
entry_status='R ', entry_rev='1')
expected_status.add({
'A/D/bloo' : Item(status='A ', wc_rev=0),
})
expected_status.tweak('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', 'A/D/gamma',
status='D ')
svntest.actions.run_and_verify_status(wc_dir, expected_status)
# Build expected post-commit trees:
# Create expected output tree.
expected_output = svntest.wc.State(wc_dir, {
'A/D' : Item(verb='Replacing'),
'A/D/H' : Item(verb='Adding'),
'A/D/bloo' : Item(verb='Adding'),
})
# Created expected status tree.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D', 'A/D/H', wc_rev=2)
expected_status.add({
'A/D/bloo' : Item(status=' ', wc_rev=2),
})
expected_status.remove('A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi', 'A/D/gamma')
# Commit from the top of the working copy and verify output & status.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
#----------------------------------------------------------------------
# Testing part 1 of the "Greg Hudson" problem -- specifically, that
# our use of the "existence=deleted" flag is working properly in cases
# where the parent directory's revision lags behind a deleted child's
# revision.
def hudson_part_1(sbox):
"hudson prob 1.0: delete file, commit, update"
sbox.build()
wc_dir = sbox.wc_dir
# Remove gamma from the working copy.
gamma_path = sbox.ospath('A/D/gamma')
svntest.main.run_svn(None, 'rm', gamma_path)
# Create expected commit output.
expected_output = svntest.wc.State(wc_dir, {
'A/D/gamma' : Item(verb='Deleting'),
})
# After committing, status should show no sign of gamma.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('A/D/gamma')
# Commit the deletion of gamma and verify.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# Now gamma should be marked as `deleted' under the hood. When we
# update, we should no output, and a perfect, virginal status list
# at revision 2. (The `deleted' entry should be removed.)
# Expected output of update: nothing.
expected_output = svntest.wc.State(wc_dir, {})
# Expected disk tree: everything but gamma
expected_disk = svntest.main.greek_state.copy()
expected_disk.remove('A/D/gamma')
# Expected status after update: totally clean revision 2, minus gamma.
expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
expected_status.remove('A/D/gamma')
svntest.actions.run_and_verify_update(wc_dir,
expected_output,
expected_disk,
expected_status)
#----------------------------------------------------------------------
# Testing part 1 of the "Greg Hudson" problem -- variation on previous
# test, removing a directory instead of a file this time.
def hudson_part_1_variation_1(sbox):
"hudson prob 1.1: delete dir, commit, update"
sbox.build()
wc_dir = sbox.wc_dir
# Remove H from the working copy.
H_path = sbox.ospath('A/D/H')
svntest.main.run_svn(None, 'rm', H_path)
# Create expected commit output.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H' : Item(verb='Deleting'),
})
# After committing, status should show no sign of H or its contents
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
# Commit the deletion of H and verify.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# Now H should be marked as `deleted' under the hood. When we
# update, we should no see output, and a perfect, virginal status
# list at revision 2. (The `deleted' entry should be removed.)
# Expected output of update: H gets a no-op deletion.
expected_output = svntest.wc.State(wc_dir, {})
# Expected disk tree: everything except files in H
expected_disk = svntest.main.greek_state.copy()
expected_disk.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
# Expected status after update: totally clean revision 2, minus H.
expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
expected_status.remove('A/D/H', 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
svntest.actions.run_and_verify_update(wc_dir,
expected_output,
expected_disk,
expected_status)
#----------------------------------------------------------------------
# Testing part 1 of the "Greg Hudson" problem -- variation 2. In this
# test, we make sure that a file that is BOTH `deleted' and scheduled
# for addition can be correctly committed & merged.
def hudson_part_1_variation_2(sbox):
"hudson prob 1.2: delete, commit, re-add, commit"
sbox.build()
wc_dir = sbox.wc_dir
# Remove gamma from the working copy.
gamma_path = sbox.ospath('A/D/gamma')
svntest.main.run_svn(None, 'rm', gamma_path)
# Create expected commit output.
expected_output = svntest.wc.State(wc_dir, {
'A/D/gamma' : Item(verb='Deleting'),
})
# After committing, status should show no sign of gamma.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('A/D/gamma')
# Commit the deletion of gamma and verify.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# Now gamma should be marked as `deleted' under the hood.
# Go ahead and re-add gamma, so that is *also* scheduled for addition.
svntest.main.file_append(gamma_path, "added gamma")
svntest.main.run_svn(None, 'add', gamma_path)
# For sanity, examine status: it should show a revision 2 tree with
# gamma scheduled for addition.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/gamma', wc_rev=0, status='A ')
svntest.actions.run_and_verify_status(wc_dir, expected_status)
# Create expected commit output.
expected_output = svntest.wc.State(wc_dir, {
'A/D/gamma' : Item(verb='Adding'),
})
# After committing, status should show only gamma at revision 3.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/gamma', wc_rev=3)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
#----------------------------------------------------------------------
# Testing part 2 of the "Greg Hudson" problem.
#
# In this test, we make sure that we're UNABLE to commit a propchange
# on an out-of-date directory.
def hudson_part_2(sbox):
"hudson prob 2.0: prop commit on old dir fails"
sbox.build()
wc_dir = sbox.wc_dir
# Remove gamma from the working copy.
D_path = sbox.ospath('A/D')
gamma_path = sbox.ospath('A/D/gamma')
svntest.main.run_svn(None, 'rm', gamma_path)
# Create expected commit output.
expected_output = svntest.wc.State(wc_dir, {
'A/D/gamma' : Item(verb='Deleting'),
})
# After committing, status should show no sign of gamma.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('A/D/gamma')
# Commit the deletion of gamma and verify.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# Now gamma should be marked as `deleted' under the hood, at
# revision 2. Meanwhile, A/D is still lagging at revision 1.
# Make a propchange on A/D
svntest.main.run_svn(None, 'ps', 'foo', 'bar', D_path)
# Commit and *expect* a repository Merge failure:
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
".*[Oo]ut of date.*")
#----------------------------------------------------------------------
# Test a possible regression in our 'deleted' post-commit handling.
#
# This test moves files from one subdir to another, commits, then
# updates the empty directory. Nothing should be printed, assuming
# all the moved files are properly marked as 'deleted' and reported to
# the server.
def hudson_part_2_1(sbox):
"hudson prob 2.1: move files, update empty dir"
sbox.build()
wc_dir = sbox.wc_dir
# Move all the files in H to G
H_path = sbox.ospath('A/D/H')
G_path = sbox.ospath('A/D/G')
chi_path = os.path.join(H_path, 'chi')
psi_path = os.path.join(H_path, 'psi')
omega_path = os.path.join(H_path, 'omega')
svntest.main.run_svn(None, 'mv', chi_path, G_path)
svntest.main.run_svn(None, 'mv', psi_path, G_path)
svntest.main.run_svn(None, 'mv', omega_path, G_path)
# Create expected commit output.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/chi' : Item(verb='Deleting'),
'A/D/H/omega' : Item(verb='Deleting'),
'A/D/H/psi' : Item(verb='Deleting'),
'A/D/G/chi' : Item(verb='Adding'),
'A/D/G/omega' : Item(verb='Adding'),
'A/D/G/psi' : Item(verb='Adding'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('A/D/H/chi')
expected_status.remove('A/D/H/omega')
expected_status.remove('A/D/H/psi')
expected_status.add({ 'A/D/G/chi' :
Item(wc_rev=2, status=' ') })
expected_status.add({ 'A/D/G/omega' :
Item(wc_rev=2, status=' ') })
expected_status.add({ 'A/D/G/psi' :
Item(wc_rev=2, status=' ') })
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# Now, assuming all three files in H are marked as 'deleted', an
# update of H should print absolutely nothing.
expected_output = svntest.wc.State(wc_dir, { })
# Reuse expected_status
expected_status.tweak(wc_rev=2)
expected_disk = svntest.main.greek_state.copy()
expected_disk.remove('A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi')
expected_disk.add({
'A/D/G/chi' : Item("This is the file 'chi'.\n"),
})
expected_disk.add({
'A/D/G/omega' : Item("This is the file 'omega'.\n"),
})
expected_disk.add({
'A/D/G/psi' : Item("This is the file 'psi'.\n"),
})
svntest.actions.run_and_verify_update(wc_dir,
expected_output,
expected_disk,
expected_status)
#----------------------------------------------------------------------
def hook_test(sbox):
"hook testing"
sbox.build()
# Get paths to the working copy and repository
wc_dir = sbox.wc_dir
repo_dir = sbox.repo_dir
# Create a hook that appends its name to a log file.
hook_format = """import sys
fp = open(sys.argv[1] + '/hooks.log', 'a')
fp.write("%s\\n")
fp.close()"""
# Setup the hook configs to log data to a file
start_commit_hook = svntest.main.get_start_commit_hook_path(repo_dir)
svntest.main.create_python_hook_script(start_commit_hook,
hook_format % "start_commit_hook")
pre_commit_hook = svntest.main.get_pre_commit_hook_path(repo_dir)
svntest.main.create_python_hook_script(pre_commit_hook,
hook_format % "pre_commit_hook")
post_commit_hook = svntest.main.get_post_commit_hook_path(repo_dir)
svntest.main.create_python_hook_script(post_commit_hook,
hook_format % "post_commit_hook")
# Modify iota just so there is something to commit.
iota_path = sbox.ospath('iota')
svntest.main.file_append(iota_path, "More stuff in iota")
# Commit, no output expected.
svntest.actions.run_and_verify_svn([], [],
'ci', '--quiet',
'-m', 'log msg', wc_dir)
# Now check the logfile
expected_data = [ 'start_commit_hook\n', 'pre_commit_hook\n', 'post_commit_hook\n' ]
logfilename = os.path.join(repo_dir, "hooks.log")
if os.path.exists(logfilename):
fp = open(logfilename)
else:
raise svntest.verify.SVNUnexpectedOutput("hook logfile %s not found")\
% logfilename
actual_data = fp.readlines()
fp.close()
os.unlink(logfilename)
svntest.verify.compare_and_display_lines('wrong hook logfile content',
'STDERR',
expected_data, actual_data)
#----------------------------------------------------------------------
# Regression test for bug #469, whereby merge() was once reporting
# erroneous conflicts due to Ancestor < Target < Source, in terms of
# node-rev-id parentage.
def merge_mixed_revisions(sbox):
"commit mixed-rev wc (no erroneous merge error)"
sbox.build()
wc_dir = sbox.wc_dir
# Make some convenient paths.
iota_path = sbox.ospath('iota')
H_path = sbox.ospath('A/D/H')
chi_path = sbox.ospath('A/D/H/chi')
omega_path = sbox.ospath('A/D/H/omega')
# Here's the reproduction formula, in 5 parts.
# Hoo, what a buildup of state!
# 1. echo "moo" >> iota; echo "moo" >> A/D/H/chi; svn ci
svntest.main.file_append(iota_path, "moo")
svntest.main.file_append(chi_path, "moo")
expected_output = svntest.wc.State(wc_dir, {
'iota' : Item(verb='Sending'),
'A/D/H/chi' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('iota', 'A/D/H/chi', wc_rev=2)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# 2. svn up A/D/H
expected_status = svntest.wc.State(wc_dir, {
'A/D/H' : Item(status=' ', wc_rev=2),
'A/D/H/chi' : Item(status=' ', wc_rev=2),
'A/D/H/omega' : Item(status=' ', wc_rev=2),
'A/D/H/psi' : Item(status=' ', wc_rev=2),
})
expected_disk = svntest.wc.State('', {
'omega' : Item("This is the file 'omega'.\n"),
'chi' : Item("This is the file 'chi'.\nmoo"),
'psi' : Item("This is the file 'psi'.\n"),
})
expected_output = svntest.wc.State(wc_dir, { })
svntest.actions.run_and_verify_update(H_path,
expected_output,
expected_disk,
expected_status)
# 3. echo "moo" >> iota; svn ci iota
svntest.main.file_append(iota_path, "moo2")
expected_output = svntest.wc.State(wc_dir, {
'iota' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/H', 'A/D/H/omega', 'A/D/H/chi', 'A/D/H/psi',
wc_rev=2)
expected_status.tweak('iota', wc_rev=3)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# 4. echo "moo" >> A/D/H/chi; svn ci A/D/H/chi
svntest.main.file_append(chi_path, "moo3")
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/chi' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/H/chi', wc_rev=4)
expected_status.tweak('A/D/H', 'A/D/H/omega', 'A/D/H/psi', wc_rev=2)
expected_status.tweak('iota', wc_rev=3)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# 5. echo "moo" >> iota; svn ci iota
svntest.main.file_append(iota_path, "moomoo")
expected_output = svntest.wc.State(wc_dir, {
'iota' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/H', 'A/D/H/omega', 'A/D/H/psi', wc_rev=2)
expected_status.tweak('A/D/H/chi', wc_rev=4)
expected_status.tweak('iota', wc_rev=5)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# At this point, here is what our tree should look like:
# _ 1 ( 5) working_copies/commit_tests-10
# _ 1 ( 5) working_copies/commit_tests-10/A
# _ 1 ( 5) working_copies/commit_tests-10/A/B
# _ 1 ( 5) working_copies/commit_tests-10/A/B/E
# _ 1 ( 5) working_copies/commit_tests-10/A/B/E/alpha
# _ 1 ( 5) working_copies/commit_tests-10/A/B/E/beta
# _ 1 ( 5) working_copies/commit_tests-10/A/B/F
# _ 1 ( 5) working_copies/commit_tests-10/A/B/lambda
# _ 1 ( 5) working_copies/commit_tests-10/A/C
# _ 1 ( 5) working_copies/commit_tests-10/A/D
# _ 1 ( 5) working_copies/commit_tests-10/A/D/G
# _ 1 ( 5) working_copies/commit_tests-10/A/D/G/pi
# _ 1 ( 5) working_copies/commit_tests-10/A/D/G/rho
# _ 1 ( 5) working_copies/commit_tests-10/A/D/G/tau
# _ 2 ( 5) working_copies/commit_tests-10/A/D/H
# _ 4 ( 5) working_copies/commit_tests-10/A/D/H/chi
# _ 2 ( 5) working_copies/commit_tests-10/A/D/H/omega
# _ 2 ( 5) working_copies/commit_tests-10/A/D/H/psi
# _ 1 ( 5) working_copies/commit_tests-10/A/D/gamma
# _ 1 ( 5) working_copies/commit_tests-10/A/mu
# _ 5 ( 5) working_copies/commit_tests-10/iota
# At this point, we're ready to modify omega and iota, and commit
# from the top. We should *not* get a conflict!
svntest.main.file_append(iota_path, "finalmoo")
svntest.main.file_append(omega_path, "finalmoo")
expected_output = svntest.wc.State(wc_dir, {
'iota' : Item(verb='Sending'),
'A/D/H/omega' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('iota', 'A/D/H/omega', wc_rev=6)
expected_status.tweak('A/D/H', 'A/D/H/psi', wc_rev=2)
expected_status.tweak('A/D/H/chi', wc_rev=4)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
#----------------------------------------------------------------------
def commit_uri_unsafe(sbox):
"commit files and dirs with URI-unsafe characters"
sbox.build()
wc_dir = sbox.wc_dir
# Note: on Windows, files can't have angle brackets in them, so we
# don't tests that case.
if svntest.main.windows or sys.platform == 'cygwin':
angle_name = '_angle_'
nasty_name = '#![]{}()__%'
else:
angle_name = '<angle>'
nasty_name = '#![]{}()<>%'
# Make some convenient paths.
hash_dir = sbox.ospath('#hash#')
nasty_dir = os.path.join(wc_dir, nasty_name)
space_path = sbox.ospath('A/D/space path')
bang_path = sbox.ospath('A/D/H/bang!')
bracket_path = sbox.ospath('A/D/H/bra[ket')
brace_path = sbox.ospath('A/D/H/bra{e')
angle_path = os.path.join(wc_dir, 'A', 'D', 'H', angle_name)
paren_path = sbox.ospath('A/D/pare)(theses')
percent_path = sbox.ospath('#hash#/percen%')
nasty_path = os.path.join(wc_dir, 'A', nasty_name)
os.mkdir(hash_dir)
os.mkdir(nasty_dir)
svntest.main.file_append(space_path, "This path has a space in it.")
svntest.main.file_append(bang_path, "This path has a bang in it.")
svntest.main.file_append(bracket_path, "This path has a bracket in it.")
svntest.main.file_append(brace_path, "This path has a brace in it.")
svntest.main.file_append(angle_path, "This path has angle brackets in it.")
svntest.main.file_append(paren_path, "This path has parentheses in it.")
svntest.main.file_append(percent_path, "This path has a percent in it.")
svntest.main.file_append(nasty_path, "This path has all sorts of ick in it.")
add_list = [hash_dir,
nasty_dir, # not xml-safe
space_path,
bang_path,
bracket_path,
brace_path,
angle_path, # not xml-safe
paren_path,
percent_path,
nasty_path, # not xml-safe
]
for item in add_list:
svntest.main.run_svn(None, 'add', '--depth=empty', item)
expected_output = svntest.wc.State(wc_dir, {
'#hash#' : Item(verb='Adding'),
nasty_name : Item(verb='Adding'),
'A/D/space path' : Item(verb='Adding'),
'A/D/H/bang!' : Item(verb='Adding'),
'A/D/H/bra[ket' : Item(verb='Adding'),
'A/D/H/bra{e' : Item(verb='Adding'),
'A/D/H/' + angle_name : Item(verb='Adding'),
'A/D/pare)(theses' : Item(verb='Adding'),
'#hash#/percen%' : Item(verb='Adding'),
'A/' + nasty_name : Item(verb='Adding'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
# Items in our add list will be at rev 2
for item in expected_output.desc.keys():
expected_status.add({ item : Item(wc_rev=2, status=' ') })
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
#----------------------------------------------------------------------
def commit_deleted_edited(sbox):
"commit deleted yet edited files"
sbox.build()
wc_dir = sbox.wc_dir
# Make some convenient paths.
iota_path = sbox.ospath('iota')
mu_path = sbox.ospath('A/mu')
# Edit the files.
svntest.main.file_append(iota_path, "This file has been edited.")
svntest.main.file_append(mu_path, "This file has been edited.")
# Schedule the files for removal.
svntest.main.run_svn(None, 'remove', '--force', iota_path)
svntest.main.run_svn(None, 'remove', '--force', mu_path)
# Make our output list
expected_output = svntest.wc.State(wc_dir, {
'iota' : Item(verb='Deleting'),
'A/mu' : Item(verb='Deleting'),
})
# Items in the status list are all at rev 1, except the two things
# we changed...but then, they don't exist at all.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('iota', 'A/mu')
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
#----------------------------------------------------------------------
def commit_in_dir_scheduled_for_addition(sbox):
"commit a file inside dir scheduled for addition"
sbox.build()
wc_dir = sbox.wc_dir
A_path = sbox.ospath('A')
Z_path = sbox.ospath('Z')
Z_abspath = os.path.abspath(Z_path)
mu_path = sbox.ospath('Z/mu')
svntest.main.run_svn(None, 'move', A_path, Z_path)
# Make sure mu is a committable
svntest.main.file_write(mu_path, "xxxx")
# Commit a copied thing inside an added-with-history directory,
# expecting a specific error to occur!
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
"svn: E200009: '" +
re.escape(Z_abspath) +
"' is not known to exist in the",
mu_path)
Q_path = sbox.ospath('Q')
Q_abspath = os.path.abspath(Q_path)
bloo_path = os.path.join(Q_path, 'bloo')
os.mkdir(Q_path)
svntest.main.file_append(bloo_path, "New contents.")
svntest.main.run_svn(None, 'add', Q_path)
# Commit a regular added thing inside an added directory,
# expecting a specific error to occur!
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
"svn: E200009: '" +
re.escape(Q_abspath) +
"' is not known to exist in the",
bloo_path)
R_path = sbox.ospath('Z/B/R')
sbox.simple_mkdir('Z/B/R')
# Commit a d added thing inside an added directory,
# expecting a specific error to occur!
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
"svn: E200009: '" +
re.escape(Z_abspath) +
"' is not known to exist in the.*",
R_path)
#----------------------------------------------------------------------
# Does this make sense now that deleted files are always removed from the wc?
def commit_rmd_and_deleted_file(sbox):
"commit deleted (and missing) file"
sbox.build()
wc_dir = sbox.wc_dir
mu_path = sbox.ospath('A/mu')
# 'svn remove' mu
svntest.main.run_svn(None, 'rm', mu_path)
# Commit, hoping to see no errors
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'commit', '-m', 'logmsg', mu_path)
#----------------------------------------------------------------------
# Issue #644 which failed over ra_neon.
@Issue(644)
def commit_add_file_twice(sbox):
"issue 644 attempt to add a file twice"
sbox.build()
wc_dir = sbox.wc_dir
# Create a file
gloo_path = sbox.ospath('A/D/H/gloo')
svntest.main.file_append(gloo_path, "hello")
svntest.main.run_svn(None, 'add', gloo_path)
# Create expected output tree.
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/gloo' : Item(verb='Adding'),
})
# Created expected status tree.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.add({
'A/D/H/gloo' : Item(status=' ', wc_rev=2),
})
# Commit should succeed
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
# Update to state before commit
svntest.main.run_svn(None, 'up', '-r', '1', wc_dir)
# Create the file again
svntest.main.file_append(gloo_path, "hello")
svntest.main.run_svn(None, 'add', gloo_path)
# Commit and *expect* a failure:
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
".*E160020: File.*already exists.*")
#----------------------------------------------------------------------
# There was a problem that committing from a directory that had a
# longer name than the working copy directory caused the commit notify
# messages to display truncated/random filenames.
def commit_from_long_dir(sbox):
"commit from a dir with a longer name than the wc"
sbox.build()
wc_dir = sbox.wc_dir
was_dir = os.getcwd()
abs_wc_dir = os.path.realpath(os.path.join(was_dir, wc_dir))
# something to commit
svntest.main.file_append(sbox.ospath('iota'), "modified iota")
# Create expected output tree.
expected_output = svntest.wc.State('', {
'iota' : Item(verb='Sending'),
})
# Any length name was enough to provoke the original bug, but
# keeping its length less than that of the filename 'iota' avoided
# random behaviour, but still caused the test to fail
extra_name = 'xx'
os.chdir(wc_dir)
os.mkdir(extra_name)
os.chdir(extra_name)
svntest.actions.run_and_verify_commit(abs_wc_dir,
expected_output,
None)
#----------------------------------------------------------------------
def commit_with_lock(sbox):
"try to commit when directory is locked"
sbox.build()
# modify gamma and lock its directory
wc_dir = sbox.wc_dir
D_path = sbox.ospath('A/D')
gamma_path = os.path.join(D_path, 'gamma')
svntest.main.file_append(gamma_path, "modified gamma")
svntest.actions.lock_admin_dir(D_path)
# this commit should fail
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
'svn: E155004: '
'Working copy \'.*\' locked')
# unlock directory
svntest.actions.run_and_verify_svn([], [],
'cleanup', D_path)
# this commit should succeed
expected_output = svntest.wc.State(wc_dir, {
'A/D/gamma' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/D/gamma', wc_rev=2)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
#----------------------------------------------------------------------
# Explicitly commit the current directory. This did at one point fail
# in post-commit processing due to a path canonicalization problem.
def commit_current_dir(sbox):
"commit the current directory"
sbox.build()
wc_dir = sbox.wc_dir
svntest.main.run_svn(None, 'propset', 'pname', 'pval', wc_dir)
was_cwd = os.getcwd()
os.chdir(wc_dir)
expected_output = svntest.wc.State('.', {
'.' : Item(verb='Sending'),
})
svntest.actions.run_and_verify_commit('.',
expected_output,
None)
os.chdir(was_cwd)
# I can't get the status check to work as part of run_and_verify_commit.
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('', wc_rev=2, status=' ')
svntest.actions.run_and_verify_status(wc_dir, expected_status)
#----------------------------------------------------------------------
# Check that the pending txn gets removed from the repository after
# a failed commit.
def failed_commit(sbox):
"commit with conflicts and check txn in repo"
sbox.build()
wc_dir = sbox.wc_dir
# Make the other working copy
other_wc_dir = sbox.add_wc_path('other')
svntest.actions.duplicate_dir(wc_dir, other_wc_dir)
# Make different changes in the two working copies
iota_path = sbox.ospath('iota')
svntest.main.file_append(iota_path, "More stuff in iota")
other_iota_path = os.path.join(other_wc_dir, "iota")
svntest.main.file_append(other_iota_path, "More different stuff in iota")
# Commit both working copies. The second commit should fail.
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'commit', '-m', 'log', wc_dir)
svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput,
'commit', '-m', 'log', other_wc_dir)
# Now list the txns in the repo. The list should be empty.
svntest.actions.run_and_verify_svnadmin([], [],
'lstxns', sbox.repo_dir)
#----------------------------------------------------------------------
# Commit from multiple working copies is being worked on as issue #2381.
# Also related to issue #959, this test here doesn't use svn:externals
# but the behaviour needs to be considered.
# In this test two WCs are nested, one WC is child of the other.
@Issue(2381)
def commit_multiple_wc_nested(sbox):
"commit from two nested working copies"
sbox.build()
wc_dir = sbox.wc_dir
# Checkout a second working copy
wc2_dir = sbox.ospath('A/wc2')
url = sbox.repo_url
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'checkout',
url, wc2_dir)
# Modify both working copies
mu_path = sbox.ospath('A/mu')
svntest.main.file_append(mu_path, 'appended mu text')
lambda2_path = os.path.join(wc2_dir, 'A', 'B', 'lambda')
svntest.main.file_append(lambda2_path, 'appended lambda2 text')
# Verify modified status
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/mu', status='M ')
svntest.actions.run_and_verify_status(wc_dir, expected_status)
expected_status2 = svntest.actions.get_virginal_state(wc2_dir, 1)
expected_status2.tweak('A/B/lambda', status='M ')
svntest.actions.run_and_verify_status(wc2_dir, expected_status2)
# Commit should succeed, even though one target is a "child" of the other.
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'commit', '-m', 'log',
wc_dir, wc2_dir)
# Verify status changed
expected_status.tweak('A/mu', status=' ', wc_rev=2)
expected_status2.tweak('A/B/lambda', status=' ', wc_rev=2)
svntest.actions.run_and_verify_status(wc_dir, expected_status)
svntest.actions.run_and_verify_status(wc2_dir, expected_status2)
# Same as commit_multiple_wc_nested except that the two WCs are not nested.
@Issue(2381)
def commit_multiple_wc(sbox):
"commit from two working copies"
sbox.build()
wc_dir = sbox.wc_dir
# Cleanup original wc
svntest.sandbox._cleanup_test_path(wc_dir)
# Checkout two wcs
wc1_dir = sbox.ospath('wc1')
wc2_dir = sbox.ospath('wc2')
url = sbox.repo_url
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'checkout',
url, wc1_dir)
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'checkout',
url, wc2_dir)
# Modify both working copies
mu1_path = os.path.join(wc1_dir, 'A', 'mu')
svntest.main.file_append(mu1_path, 'appended mu1 text')
lambda2_path = os.path.join(wc2_dir, 'A', 'B', 'lambda')
svntest.main.file_append(lambda2_path, 'appended lambda2 text')
# Verify modified status
expected_status1 = svntest.actions.get_virginal_state(wc1_dir, 1)
expected_status1.tweak('A/mu', status='M ')
svntest.actions.run_and_verify_status(wc1_dir, expected_status1)
expected_status2 = svntest.actions.get_virginal_state(wc2_dir, 1)
expected_status2.tweak('A/B/lambda', status='M ')
svntest.actions.run_and_verify_status(wc2_dir, expected_status2)
# Commit should succeed.
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'commit', '-m', 'log',
wc1_dir, wc2_dir)
# Verify status changed
expected_status1.tweak('A/mu', status=' ', wc_rev=2)
expected_status2.tweak('A/B/lambda', status=' ', wc_rev=2)
svntest.actions.run_and_verify_status(wc1_dir, expected_status1)
svntest.actions.run_and_verify_status(wc2_dir, expected_status2)
# Same as commit_multiple_wc except that the two WCs come
# from different repositories. Commits to multiple repositories
# are outside the scope of issue #2381.
@Issue(2381)
def commit_multiple_wc_multiple_repos(sbox):
"committing two WCs from different repos fails"
sbox.build()
wc_dir = sbox.wc_dir
# Create another repository
repo2, url2 = sbox.add_repo_path("repo2")
svntest.main.copy_repos(sbox.repo_dir, repo2, 1, 1)
# Cleanup original wc
svntest.sandbox._cleanup_test_path(wc_dir)
# Checkout two wcs
wc1_dir = sbox.ospath('wc1')
wc2_dir = sbox.ospath('wc2')
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'checkout',
sbox.repo_url, wc1_dir)
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'checkout',
url2, wc2_dir)
# Modify both working copies
mu1_path = os.path.join(wc1_dir, 'A', 'mu')
svntest.main.file_append(mu1_path, 'appended mu1 text')
lambda2_path = os.path.join(wc2_dir, 'A', 'B', 'lambda')
svntest.main.file_append(lambda2_path, 'appended lambda2 text')
# Verify modified status
expected_status1 = svntest.actions.get_virginal_state(wc1_dir, 1)
expected_status1.tweak('A/mu', status='M ')
svntest.actions.run_and_verify_status(wc1_dir, expected_status1)
expected_status2 = svntest.actions.get_virginal_state(wc2_dir, 1)
expected_status2.tweak('A/B/lambda', status='M ')
svntest.actions.run_and_verify_status(wc2_dir, expected_status2)
# Commit should fail, since WCs come from different repositories.
# The exact error message depends on whether or not the tests are
# run below an existing working copy
error_re = ( ".*(is not a working copy" +
"|Are all targets part of the same working copy" +
"|was not found).*" )
svntest.actions.run_and_verify_svn([], error_re,
'commit', '-m', 'log',
wc1_dir, wc2_dir)
# Verify status unchanged
svntest.actions.run_and_verify_status(wc1_dir, expected_status1)
svntest.actions.run_and_verify_status(wc2_dir, expected_status2)
#----------------------------------------------------------------------
@Issues(1195,1239)
def commit_nonrecursive(sbox):
"commit named targets with -N"
sbox.build()
wc_dir = sbox.wc_dir
### Note: the original recipes used 'add -N'. These days, we use
### --depth={empty,files}, and both the code and the comments below
### have been adjusted to reflect this.
#####################################################
### Issue #1195:
###
### 1. Create these directories and files:
###
### file1
### dir1
### dir1/file2
### dir1/file3
### dir1/dir2
### dir1/dir2/file4
###
### 2. run 'svn add --depth=empty <all of the above>'
###
### 3. run 'svn ci -N <all of the above>'
###
### (The bug was that only 4 entities would get committed, when it
### should be 6: dir2/ and file4 were left out.)
# These paths are relative to the top of the test's working copy.
file1_path = 'file1'
dir1_path = 'dir1'
file2_path = 'dir1/file2'
file3_path = 'dir1/file3'
dir2_path = 'dir1/dir2'
file4_path = 'dir1/dir2/file4'
# Create the new files and directories.
svntest.main.file_append(sbox.ospath(file1_path), 'this is file1')
os.mkdir(sbox.ospath(dir1_path))
svntest.main.file_append(sbox.ospath(file2_path), 'this is file2')
svntest.main.file_append(sbox.ospath(file3_path), 'this is file3')
os.mkdir(sbox.ospath(dir2_path))
svntest.main.file_append(sbox.ospath(file4_path), 'this is file4')
# Add them to version control.
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'add', '--depth=empty',
sbox.ospath(file1_path),
sbox.ospath(dir1_path),
sbox.ospath(file2_path),
sbox.ospath(file3_path),
sbox.ospath(dir2_path),
sbox.ospath(file4_path))
# Commit. We should see all 6 items (2 dirs, 4 files) get sent.
expected_output = svntest.wc.State(
wc_dir,
{ file1_path : Item(verb='Adding'),
dir1_path : Item(verb='Adding'),
file2_path : Item(verb='Adding'),
file3_path : Item(verb='Adding'),
dir2_path : Item(verb='Adding'),
file4_path : Item(verb='Adding'),
}
)
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.add({
file1_path : Item(status=' ', wc_rev=2),
dir1_path : Item(status=' ', wc_rev=2),
file2_path : Item(status=' ', wc_rev=2),
file3_path : Item(status=' ', wc_rev=2),
dir2_path : Item(status=' ', wc_rev=2),
file4_path : Item(status=' ', wc_rev=2),
})
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
'-N',
sbox.ospath(file1_path),
sbox.ospath(dir1_path),
sbox.ospath(file2_path),
sbox.ospath(file3_path),
sbox.ospath(dir2_path),
sbox.ospath(file4_path))
#######################################################################
###
### There's some complex history here; please bear with me.
###
### First there was issue #1239, which had the following recipe:
###
### 1. Create these directories and files:
###
### dirA
### dirA/fileA
### dirA/fileB
### dirA/dirB
### dirA/dirB/fileC
### dirA/dirB/nocommit
###
### 2. run 'svn add --depth=empty <all of the above>'
###
### 3. run 'svn ci -N <all but nocommit>'
###
### (In this recipe, 'add -N' has been changed to 'add --depth...',
### but 'ci -N' has been left as-is, for reasons explained below.)
###
### Issue #1239 claimed a two-part bug: that step 3 would try to
### commit the file `nocommit' when it shouldn't, and that it would
### get an error anyway:
###
### Adding wc/dirA
### Adding wc/dirA/fileA
### Adding wc/dirA/fileB
### Adding wc/dirA/dirB
### Adding wc/dirA/dirB/nocommit
### Adding wc/dirA/dirB/fileC
### Transmitting file data ....svn: A problem occurred; \
### see later errors for details
### svn: Commit succeeded, but other errors follow:
### svn: Problem running log
### svn: Error bumping revisions post-commit (details follow):
### svn: in directory
### 'F:/Programmation/Projets/subversion/svnant/test/wc/dirA'
### svn: start_handler: error processing command 'committed' in
### 'F:/Programmation/Projets/subversion/svnant/test/wc/dirA'
### svn: Working copy not locked
### svn: directory not locked
### (F:/Programmation/Projets/subversion/svnant/test/wc)
###
### However, this was all in the days before --depth, and depended
### on an idiosyncratic interpretation of -N, one which required
### commit to behave differently from other commands taking -N.
###
### These days, -N should be equivalent to --depth=files in almost
### all cases. There are some exceptions (e.g., status), and commit
### is one of them: 'commit -N' means 'commit --depth=empty'.
###
### The original implementation, as well as this test, mistakenly
### mapped 'commit -N' to 'commit --depth=files'; that was a bug that
### made 'svn ci -N' incompatible with 1.4 and earlier versions.
###
### See also 'commit_propmods_with_depth_empty' in depth_tests.py .
# Now add these directories and files, except the last:
dirA_path = 'dirA'
fileA_path = 'dirA/fileA'
fileB_path = 'dirA/fileB'
dirB_path = 'dirA/dirB'
nope_1_path = 'dirA/dirB/nope_1'
nope_2_path = 'dirA/dirB/nope_2'
# Create the new files and directories.
os.mkdir(sbox.ospath(dirA_path))
svntest.main.file_append(sbox.ospath(fileA_path), 'fileA')
svntest.main.file_append(sbox.ospath(fileB_path), 'fileB')
os.mkdir(sbox.ospath(dirB_path))
svntest.main.file_append(sbox.ospath(nope_1_path), 'nope_1')
svntest.main.file_append(sbox.ospath(nope_2_path), 'nope_2')
# Add them to version control.
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'add', '-N',
sbox.ospath(dirA_path),
sbox.ospath(fileA_path),
# don't add fileB
sbox.ospath(dirB_path),
sbox.ospath(nope_1_path),
# don't add nope_2
)
expected_output = svntest.wc.State(
wc_dir,
{ dirA_path : Item(verb='Adding'),
# no children!
}
)
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
# Expect the leftovers from the first part of the test.
expected_status.add({
file1_path : Item(status=' ', wc_rev=2),
dir1_path : Item(status=' ', wc_rev=2),
file2_path : Item(status=' ', wc_rev=2),
file3_path : Item(status=' ', wc_rev=2),
dir2_path : Item(status=' ', wc_rev=2),
file4_path : Item(status=' ', wc_rev=2),
})
# Expect some commits and some non-commits from this part of the test.
expected_status.add({
dirA_path : Item(status=' ', wc_rev=3),
fileA_path : Item(status='A ', wc_rev=0),
# no fileB
dirB_path : Item(status='A ', wc_rev=0),
nope_1_path : Item(status='A ', wc_rev=0),
# no nope_2
})
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
'-N', sbox.ospath(dirA_path))
#----------------------------------------------------------------------
# Regression for #1017: ra_neon was allowing the deletion of out-of-date
# files or dirs, which majorly violates Subversion's semantics.
# An out-of-date error should be raised if the object to be committed has
# already been deleted or modified in the repo.
def commit_out_of_date_deletions(sbox):
"commit deletion of out-of-date file or dir"
# Path WC 1 WC backup
# =========== ==== =========
# A/C pset del
# A/I del pset
# A/B/F del del
# A/D/H/omega text del
# A/B/E/alpha pset del
# A/D/H/chi del text
# A/B/E/beta del pset
# A/D/H/psi del del
sbox.build()
wc_dir = sbox.wc_dir
# Need another empty dir
I_path = sbox.ospath('A/I')
os.mkdir(I_path)
svntest.main.run_svn(None, 'add', I_path)
sbox.simple_commit(message='prep')
svntest.main.run_svn(None, 'up', 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)
# Edits in wc 1
C_path = sbox.ospath('A/C')
omega_path = sbox.ospath('A/D/H/omega')
alpha_path = sbox.ospath('A/B/E/alpha')
svntest.main.run_svn(None, 'propset', 'fooprop', 'foopropval', C_path)
svntest.main.file_append(omega_path, 'appended omega text')
svntest.main.run_svn(None, 'propset', 'fooprop', 'foopropval', alpha_path)
# Deletions in wc 1
I_path = sbox.ospath('A/I')
F_path = sbox.ospath('A/B/F')
chi_path = sbox.ospath('A/D/H/chi')
beta_path = sbox.ospath('A/B/E/beta')
psi_path = sbox.ospath('A/D/H/psi')
svntest.main.run_svn(None, 'rm', I_path, F_path, chi_path, beta_path,
psi_path)
# Commit in wc 1
expected_output = svntest.wc.State(wc_dir, {
'A/C' : Item(verb='Sending'),
'A/I' : Item(verb='Deleting'),
'A/B/F' : Item(verb='Deleting'),
'A/D/H/omega' : Item(verb='Sending'),
'A/B/E/alpha' : Item(verb='Sending'),
'A/D/H/chi' : Item(verb='Deleting'),
'A/B/E/beta' : Item(verb='Deleting'),
'A/D/H/psi' : Item(verb='Deleting'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
expected_status.tweak('A/C', 'A/D/H/omega', 'A/B/E/alpha', wc_rev=3,
status=' ')
expected_status.remove('A/B/F', 'A/D/H/chi', 'A/B/E/beta', 'A/D/H/psi')
commit = svntest.actions.run_and_verify_commit
commit(wc_dir, expected_output, expected_status, [], wc_dir)
# Edits in wc backup
I_path = os.path.join(wc_backup, 'A', 'I')
chi_path = os.path.join(wc_backup, 'A', 'D', 'H', 'chi')
beta_path = os.path.join(wc_backup, 'A', 'B', 'E','beta')
svntest.main.run_svn(None, 'propset', 'fooprop', 'foopropval', I_path)
svntest.main.file_append(chi_path, 'appended chi text')
svntest.main.run_svn(None, 'propset', 'fooprop', 'foopropval', beta_path)
# Deletions in wc backup
C_path = os.path.join(wc_backup, 'A', 'C')
F_path = os.path.join(wc_backup, 'A', 'B', 'F')
omega_path = os.path.join(wc_backup, 'A', 'D', 'H', 'omega')
alpha_path = os.path.join(wc_backup, 'A', 'B', 'E', 'alpha')
psi_path = os.path.join(wc_backup, 'A', 'D', 'H', 'psi')
svntest.main.run_svn(None, 'rm', C_path, F_path, omega_path, alpha_path,
psi_path)
# A commit of any one of these files or dirs should fail, preferably
# with an out-of-date error message.
error_re = ".*(out of date|not found).*"
commit(wc_backup, None, None, error_re, C_path)
commit(wc_backup, None, None, error_re, I_path)
commit(wc_backup, None, None, error_re, F_path)
commit(wc_backup, None, None, error_re, omega_path)
commit(wc_backup, None, None, error_re, alpha_path)
commit(wc_backup, None, None, error_re, chi_path)
commit(wc_backup, None, None, error_re, beta_path)
commit(wc_backup, None, None, error_re, psi_path)
def commit_with_bad_log_message(sbox):
"commit with a log message containing bad data"
sbox.build()
wc_dir = sbox.wc_dir
iota_path = sbox.ospath('iota')
log_msg_path = sbox.ospath('log-message')
# Make a random change, so there's something to commit.
svntest.main.file_append(iota_path, 'fish')
# Create a log message containing a zero-byte.
svntest.main.file_append(log_msg_path, '\x00')
# Commit and expect an error.
svntest.actions.run_and_verify_commit(wc_dir,
None, None,
".*contains a zero byte.*",
'-F', log_msg_path,
iota_path)
def commit_with_mixed_line_endings(sbox):
"commit with log message with mixed EOL"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
iota_path = sbox.ospath('iota')
log_msg_path = sbox.ospath('log-message')
# Make a random change, so there's something to commit.
svntest.main.file_append(iota_path, 'kebab')
# Create a log message containing a zero-byte.
svntest.main.file_append(log_msg_path, "test\nthis\n\rcase\r\n--This line, and those below, will be ignored--\n")
# Commit and expect an error.
expected_stderr = ".*E135000: Error normalizing log message to internal format.*"
svntest.actions.run_and_verify_commit(wc_dir,
None, None,
expected_stderr,
'-F', log_msg_path,
iota_path)
def commit_with_mixed_line_endings_in_ignored_part(sbox):
"commit with log message with mixed EOL in tail"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
iota_path = sbox.ospath('iota')
log_msg_path = sbox.ospath('log-message')
# Make a random change, so there's something to commit.
svntest.main.file_append(iota_path, 'cheeseburger')
# Create a log message containing a zero-byte.
svntest.main.file_append(log_msg_path, "test\n--This line, and those below, will be ignored--\nfoo\r\nbar\nbaz\n\r")
# Create expected state.
expected_output = svntest.wc.State(wc_dir, {
'iota' : Item(verb='Sending'),
})
expected_status.tweak('iota', wc_rev=2, status=' ')
# Commit the one file.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
iota_path)
def from_wc_top_with_bad_editor(sbox):
"commit with invalid external editor cmd"
# Shortly after revision 5407, Vladimir Prus posted this bug recipe:
#
# #!/bin/bash
# cd /tmp
# rm -rf repo wc
# svnadmin create repo
# svn mkdir file:///tmp/repo/foo -m ""
# svn co file:///tmp/repo/foo wc
# cd wc
# svn ps svn:externals "lib http://something.org/lib" .
# svn ci
#
# The final 'svn ci' would seg fault because of a problem in
# calculating the paths to insert in the initial log message that
# gets passed to the editor.
#
# So this regression test is primarily about making sure the seg
# fault is gone, and only secondarily about testing that we get the
# expected error from passing a bad editor cmd to Subversion.
sbox.build()
wc_dir = sbox.wc_dir
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'pset', 'fish', 'food', wc_dir)
os.chdir(wc_dir)
exit_code, out, err = svntest.actions.run_and_verify_svn(
None, svntest.verify.AnyOutput,
'--force-interactive',
'ci', '--editor-cmd', 'no_such-editor')
err = " ".join([x.strip() for x in err])
if not (re.match(".*no_such-editor.*", err)
and re.match(".*Commit failed.*", err)):
print("Commit failed, but not in the way expected.")
raise svntest.Failure
def mods_in_schedule_delete(sbox):
"commit with mods in schedule delete"
sbox.build()
wc_dir = sbox.wc_dir
# Schedule a delete, then put in local mods
C_path = sbox.ospath('A/C')
svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [],
'rm', C_path)
if not os.path.exists(C_path):
os.mkdir(C_path)
foo_path = os.path.join(C_path, 'foo')
foo_contents = 'zig\nzag\n'
svntest.main.file_append(foo_path, foo_contents)
# Commit should succeed
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('A/C')
expected_output = svntest.wc.State(wc_dir, {
'A/C' : Item(verb='Deleting'),
})
svntest.actions.run_and_verify_commit(wc_dir,
expected_output, expected_status)
# Unversioned file still exists
actual_contents = open(foo_path).read()
if actual_contents != foo_contents:
raise svntest.Failure
#----------------------------------------------------------------------
@Skip(is_non_posix_os_or_cygwin_platform)
@Issue(1954)
def tab_test(sbox):
"tabs in paths"
# For issue #1954.
sbox.build()
wc_dir = sbox.wc_dir
tab_file = sbox.ospath('A/tab\tfile')
tab_dir = sbox.ospath('A/tab\tdir')
source_url = sbox.repo_url + "/source_dir"
tab_url = sbox.repo_url + "/tab%09dir"
svntest.main.file_append(tab_file, "This file has a tab in it.")
os.mkdir(tab_dir)
def match_bad_tab_path(path, errlines):
match_re = ".*: Invalid control character '0x09' in path .*"
for line in errlines:
if re.match (match_re, line):
break
else:
raise svntest.Failure("Failed to find match_re in " + str(errlines))
# add file to wc
exit_code, outlines, errlines = svntest.main.run_svn(1, 'add', tab_file)
match_bad_tab_path(tab_file, errlines)
# add dir to wc
exit_code, outlines, errlines = svntest.main.run_svn(1, 'add', tab_dir)
match_bad_tab_path(tab_dir, errlines)
# mkdir URL
exit_code, outlines, errlines = svntest.main.run_svn(1, 'mkdir',
'-m', 'msg', tab_url)
match_bad_tab_path(tab_dir, errlines)
# copy URL
svntest.main.run_svn(1,
'mkdir', '-m', 'msg', source_url)
exit_code, outlines, errlines = svntest.main.run_svn(1, 'copy',
'-m', 'msg',
source_url, tab_url)
match_bad_tab_path(tab_dir, errlines)
# mv URL
exit_code, outlines, errlines = svntest.main.run_svn(1, 'mv', '-m', 'msg',
source_url, tab_url)
match_bad_tab_path(tab_dir, errlines)
#----------------------------------------------------------------------
@Issue(2285)
def local_mods_are_not_commits(sbox):
"local ops should not be treated like commits"
# For issue #2285.
#
# Some commands can run on either a URL or a local path. These
# commands take a log message, intended for the URL case.
# Therefore, they should make sure that getting a log message for
# a local operation errors (because not committing).
#
# This is in commit_tests.py because the unifying theme is that
# commits are *not* happening. And because there was no better
# place to put it :-).
sbox.build()
wc_dir = sbox.wc_dir
expected_error = '.*Local, non-commit operations do not take a log message.*'
# copy wc->wc
svntest.actions.run_and_verify_svn(None, expected_error,
'cp', '-m', 'log msg',
sbox.ospath('iota'),
sbox.ospath('iota2'))
# copy repos->wc
svntest.actions.run_and_verify_svn(None, expected_error,
'cp', '-m', 'log msg',
sbox.repo_url + "/iota",
sbox.ospath('iota2'))
# delete
svntest.actions.run_and_verify_svn(None, expected_error,
'rm', '-m', 'log msg',
sbox.ospath('A/D/gamma'))
# mkdir
svntest.actions.run_and_verify_svn(None, expected_error,
'mkdir', '-m', 'log msg',
sbox.ospath('newdir'))
# rename
svntest.actions.run_and_verify_svn(None, expected_error,
'cp', '-m', 'log msg',
sbox.ospath('A/mu'),
sbox.ospath('A/yu'))
#----------------------------------------------------------------------
# Test if the post-commit error message is returned back to the svn
# client and is displayed as a warning.
@Issue(3553)
def post_commit_hook_test(sbox):
"post commit hook failure case testing"
sbox.build()
# Get paths to the working copy and repository
wc_dir = sbox.wc_dir
repo_dir = sbox.repo_dir
# Create a hook that outputs a message to stderr and returns exit code 1
# Include a non-XML-safe message to regression-test issue #3553.
error_msg = "Text with <angle brackets> & ampersand"
svntest.actions.create_failing_hook(repo_dir, "post-commit", error_msg)
# Modify iota just so there is something to commit.
iota_path = sbox.ospath('iota')
svntest.main.file_append(iota_path, "lakalakalakalaka")
# Now, commit and examine the output (we happen to know that the
# filesystem will report an absolute path because that's the way the
# filesystem is created by this test suite.
expected_output = [ "Sending "+ iota_path + "\n",
"Transmitting file data .done\n",
"Committing transaction...\n",
"Committed revision 2.\n",
"\n",
"Warning: " +
svntest.actions.hook_failure_message('post-commit'),
error_msg + "\n",
]
svntest.actions.run_and_verify_svn(expected_output, [],
'ci', '-m', 'log msg', iota_path)
#----------------------------------------------------------------------
# Commit two targets non-recursively, but both targets should be the
# same folder (in multiple variations). Test that svn handles this correctly.
def commit_same_folder_in_targets(sbox):
"commit two targets, both the same folder"
sbox.build()
wc_dir = sbox.wc_dir
iota_path = sbox.ospath('iota')
svntest.main.file_append(iota_path, "added extra line to file 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)
# Commit the wc_dir and iota.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
'-N',
wc_dir,
iota_path)
#----------------------------------------------------------------------
# test for issue 2459: verify that commit fails when a file with mixed
# eol-styles is included, and show an error message which includes the
# filename.
@Issue(2459)
def commit_inconsistent_eol(sbox):
"commit files with inconsistent eol should fail"
sbox.build()
wc_dir = sbox.wc_dir
iota_path = sbox.ospath('iota')
mu_path = sbox.ospath('A/mu')
svntest.main.run_svn(None, 'propset', 'svn:eol-style', 'native', iota_path)
svntest.main.file_append_binary(iota_path,
"added extra line to file iota\012"
"added extra line to file iota\015")
svntest.main.file_append(mu_path, "added extra line to file mu\n"
"added extra line to file mu\n")
expected_err = ".*iota.*"
svntest.actions.run_and_verify_svn(None, expected_err,
'commit', '-m', 'log message',
wc_dir)
@SkipUnless(server_has_revprop_commit)
def mkdir_with_revprop(sbox):
"set revision props during remote mkdir"
sbox.build()
remote_dir = sbox.repo_url + "/dir"
svntest.actions.run_and_verify_svn(None, [], 'mkdir', '-m', 'msg',
'--with-revprop', 'bug=42', remote_dir)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('42', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def delete_with_revprop(sbox):
"set revision props during remote delete"
sbox.build()
remote_dir = sbox.repo_url + "/dir"
svntest.actions.run_and_verify_svn(None, [], 'mkdir', '-m', 'msg',
remote_dir)
svntest.actions.run_and_verify_svn(None, [], 'delete', '-m', 'msg',
'--with-revprop', 'bug=52', remote_dir)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 3:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 3, sbox.repo_url)
svntest.actions.run_and_verify_svn('52', [], 'propget', 'bug',
'--revprop', '-r', 3, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def commit_with_revprop(sbox):
"set revision props during commit"
sbox.build()
wc_dir = sbox.wc_dir
expected_status = make_standard_slew_of_changes(wc_dir)
omega_path = sbox.ospath('A/D/H/omega')
gloo_path = sbox.ospath('A/D/H/gloo')
expected_output = svntest.wc.State(wc_dir, {
'A/D/H/omega' : Item(verb='Sending'),
'A/D/H/gloo' : Item(verb='Adding'),
})
expected_status.tweak('A/D/H/omega', wc_rev=2, status=' ')
expected_status.tweak('A/D/H/gloo', wc_rev=2, status=' ')
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
'-m', 'msg',
'--with-revprop', 'bug=62',
omega_path, gloo_path)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('62', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def import_with_revprop(sbox):
"set revision props during import"
sbox.build()
local_dir = sbox.ospath('folder')
local_file = sbox.ospath('folder/file')
os.mkdir(local_dir)
svntest.main.file_write(local_file, "xxxx")
svntest.actions.run_and_verify_svn(None, [], 'import', '-m', 'msg',
'--with-revprop', 'bug=72', local_dir,
sbox.repo_url)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('72', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def copy_R2R_with_revprop(sbox):
"set revision props during repos-to-repos copy"
sbox.build()
remote_dir1 = sbox.repo_url + "/dir1"
remote_dir2 = sbox.repo_url + "/dir2"
svntest.actions.run_and_verify_svn(None, [], 'mkdir', '-m', 'msg',
remote_dir1)
svntest.actions.run_and_verify_svn(None, [], 'copy', '-m', 'msg',
'--with-revprop', 'bug=82', remote_dir1,
remote_dir2)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 3:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 3, sbox.repo_url)
svntest.actions.run_and_verify_svn('82', [], 'propget', 'bug',
'--revprop', '-r', 3, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def copy_WC2R_with_revprop(sbox):
"set revision props during wc-to-repos copy"
sbox.build()
remote_dir = sbox.repo_url + "/dir"
local_dir = sbox.ospath('folder')
svntest.actions.run_and_verify_svn(None, [],
'mkdir', local_dir)
svntest.actions.run_and_verify_svn(None, [], 'copy', '-m', 'msg',
'--with-revprop', 'bug=92', local_dir,
remote_dir)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('92', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def move_R2R_with_revprop(sbox):
"set revision props during repos-to-repos move"
sbox.build()
remote_dir1 = sbox.repo_url + "/dir1"
remote_dir2 = sbox.repo_url + "/dir2"
svntest.actions.run_and_verify_svn(None, [], 'mkdir', '-m', 'msg',
remote_dir1)
svntest.actions.run_and_verify_svn(None, [], 'move', '-m', 'msg',
'--with-revprop', 'bug=102', remote_dir1,
remote_dir2)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 3:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 3, sbox.repo_url)
svntest.actions.run_and_verify_svn('102', [], 'propget', 'bug',
'--revprop', '-r', 3, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def propedit_with_revprop(sbox):
"set revision props during remote property edit"
sbox.build()
svntest.main.use_editor('append_foo')
svntest.actions.run_and_verify_svn(None, [], 'propedit', '-m', 'msg',
'--with-revprop', 'bug=112', 'prop',
sbox.repo_url)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('112', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def set_multiple_props_with_revprop(sbox):
"set multiple revision props during remote mkdir"
sbox.build()
remote_dir = sbox.repo_url + "/dir"
svntest.actions.run_and_verify_svn(None, [], 'mkdir', '-m', 'msg',
'--with-revprop', 'bug=32',
'--with-revprop', 'ref=22', remote_dir)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n', ' ref\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('32', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('22', [], 'propget', 'ref',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def use_empty_value_in_revprop_pair(sbox):
"set revprop without value ('') during remote mkdir"
sbox.build()
remote_dir = sbox.repo_url + "/dir"
svntest.actions.run_and_verify_svn(None, [], 'mkdir', '-m', 'msg',
'--with-revprop', 'bug=',
'--with-revprop', 'ref=', remote_dir)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n', ' ref\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('', [], 'propget', 'ref',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def no_equals_in_revprop_pair(sbox):
"set revprop without '=' during remote mkdir"
sbox.build()
remote_dir = sbox.repo_url + "/dir"
svntest.actions.run_and_verify_svn(None, [], 'mkdir', '-m', 'msg',
'--with-revprop', 'bug',
'--with-revprop', 'ref', remote_dir)
expected = svntest.verify.UnorderedOutput(
['Unversioned properties on revision 2:\n',
' svn:author\n',' svn:date\n', ' svn:log\n',
' bug\n', ' ref\n'])
svntest.actions.run_and_verify_svn(expected, [], 'proplist',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('', [], 'propget', 'bug',
'--revprop', '-r', 2, sbox.repo_url)
svntest.actions.run_and_verify_svn('', [], 'propget', 'ref',
'--revprop', '-r', 2, sbox.repo_url)
@SkipUnless(server_has_revprop_commit)
def set_invalid_revprops(sbox):
"set invalid revision props during remote mkdir"
sbox.build()
remote_dir = sbox.repo_url + "/dir"
# Try to set svn: revprops.
expected = '.*Standard properties can\'t.*'
svntest.actions.run_and_verify_svn([], expected, 'mkdir', '-m', 'msg',
'--with-revprop', 'svn:author=42', remote_dir)
svntest.actions.run_and_verify_svn([], expected, 'mkdir', '-m', 'msg',
'--with-revprop', 'svn:log=42', remote_dir)
svntest.actions.run_and_verify_svn([], expected, 'mkdir', '-m', 'msg',
'--with-revprop', 'svn:date=42', remote_dir)
svntest.actions.run_and_verify_svn([], expected, 'mkdir', '-m', 'msg',
'--with-revprop', 'svn:foo=bar', remote_dir)
# Empty revprop pair.
svntest.actions.run_and_verify_svn([],
'svn: E205000: '
'Revision property pair is empty',
'mkdir', '-m', 'msg',
'--with-revprop', '',
remote_dir)
#----------------------------------------------------------------------
@Issue(3553)
def start_commit_hook_test(sbox):
"start-commit hook failure case testing"
sbox.build()
# Get paths to the working copy and repository
wc_dir = sbox.wc_dir
repo_dir = sbox.repo_dir
# Create a hook that outputs a message to stderr and returns exit code 1
# Include a non-XML-safe message to regression-test issue #3553.
error_msg = "Text with <angle brackets> & ampersand"
svntest.actions.create_failing_hook(repo_dir, "start-commit", error_msg)
# Modify iota just so there is something to commit.
iota_path = sbox.ospath('iota')
svntest.main.file_append(iota_path, "More stuff in iota")
# Commit, expect error code 1
exit_code, actual_stdout, actual_stderr = svntest.main.run_svn(
1, 'ci', '--quiet', '-m', 'log msg', wc_dir)
# No stdout expected
svntest.verify.compare_and_display_lines('Start-commit hook test',
'STDOUT', [], actual_stdout)
# Compare only the last two lines of stderr since the preceding ones
# contain source code file and line numbers.
if len(actual_stderr) > 2:
actual_stderr = actual_stderr[-2:]
expected_stderr = [ "svn: E165001: " +
svntest.actions.hook_failure_message('start-commit'),
error_msg + "\n",
]
svntest.verify.compare_and_display_lines('Start-commit hook test',
'STDERR',
expected_stderr, actual_stderr)
# Now list the txns in the repo. The list should be empty.
svntest.actions.run_and_verify_svnadmin([], [],
'lstxns', sbox.repo_dir)
#----------------------------------------------------------------------
@Issue(3553)
def pre_commit_hook_test(sbox):
"pre-commit hook failure case testing"
sbox.build()
# Get paths to the working copy and repository
wc_dir = sbox.wc_dir
repo_dir = sbox.repo_dir
# Create a hook that outputs a message to stderr and returns exit code 1
# Include a non-XML-safe message to regression-test issue #3553.
error_msg = "Text with <angle brackets> & ampersand"
svntest.actions.create_failing_hook(repo_dir, "pre-commit", error_msg)
# Modify iota just so there is something to commit.
iota_path = sbox.ospath('iota')
svntest.main.file_append(iota_path, "More stuff in iota")
# Commit, expect error code 1
exit_code, actual_stdout, actual_stderr = svntest.main.run_svn(
1, 'ci', '--quiet', '-m', 'log msg', wc_dir)
# No stdout expected
svntest.verify.compare_and_display_lines('Pre-commit hook test',
'STDOUT', [], actual_stdout)
# Compare only the last two lines of stderr since the preceding ones
# contain source code file and line numbers.
if len(actual_stderr) > 2:
actual_stderr = actual_stderr[-2:]
expected_stderr = [ "svn: E165001: " +
svntest.actions.hook_failure_message('pre-commit'),
error_msg + "\n",
]
svntest.verify.compare_and_display_lines('Pre-commit hook test',
'STDERR',
expected_stderr, actual_stderr)
#----------------------------------------------------------------------
def versioned_log_message(sbox):
"'svn commit -F foo' when foo is a versioned file"
sbox.build()
os.chdir(sbox.wc_dir)
iota_path = os.path.join('iota')
mu_path = os.path.join('A', 'mu')
log_path = os.path.join('A', 'D', 'H', 'omega')
svntest.main.file_append(iota_path, "2")
# try to check in a change using a versioned file as your log entry.
svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput,
'ci', '-F', log_path)
# force it. should not produce any errors.
svntest.actions.run_and_verify_svn(None, [],
'ci', '-F', log_path, '--force-log')
svntest.main.file_append(mu_path, "2")
# try the same thing, but specifying the file to commit explicitly.
svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput,
'ci', '-F', log_path, mu_path)
# force it... should succeed.
svntest.actions.run_and_verify_svn(None, [],
'ci',
'-F', log_path,
'--force-log', mu_path)
#----------------------------------------------------------------------
def changelist_near_conflict(sbox):
"'svn commit --changelist=foo' above a conflict"
sbox.build()
wc_dir = sbox.wc_dir
iota_path = sbox.ospath('iota')
mu_path = sbox.ospath('A/mu')
gloo_path = sbox.ospath('A/D/H/gloo')
expected_status = make_standard_slew_of_changes(wc_dir)
# Create a changelist.
changelist_name = "logical-changeset"
svntest.actions.run_and_verify_svn(None, [],
"changelist", changelist_name,
mu_path, gloo_path)
# Create a conflict (making r2 in the process).
inject_conflict_into_wc(sbox, 'iota', iota_path,
None, expected_status, 2)
# Commit the changelist.
expected_output = svntest.wc.State(wc_dir, {
"A/D/H/gloo" : Item(verb='Adding'),
})
expected_status.tweak("A/D/H/gloo", wc_rev=3, status=" ")
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status,
[],
"--changelist=" + changelist_name,
"-m", "msg", wc_dir)
#----------------------------------------------------------------------
def commit_out_of_date_file(sbox):
"try to commit a file that is out-of-date"
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)
pi_path = sbox.ospath('A/D/G/pi')
backup_pi_path = os.path.join(wc_backup, 'A', 'D', 'G', 'pi')
svntest.main.file_append(pi_path, "new line\n")
expected_output = svntest.wc.State(wc_dir, {
"A/D/G/pi" : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak("A/D/G/pi", wc_rev=2, status=" ")
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
svntest.main.file_append(backup_pi_path, "hello")
expected_err = ".*(pi.*out of date|Out of date.*pi).*"
svntest.actions.run_and_verify_svn(None, expected_err,
'commit', '-m', 'log message',
wc_backup)
@SkipUnless(server_gets_client_capabilities)
@Issue(2991)
def start_commit_detect_capabilities(sbox):
"start-commit hook sees client capabilities" # Issue #2991
sbox.build()
wc_dir = sbox.wc_dir
repos_dir = sbox.repo_dir
# Create a start-commit hook that detects the "mergeinfo" capability.
hook_text = "import sys\n" + \
"fp = open(sys.argv[1] + '/hooks.log', 'w')\n" + \
"caps = sys.argv[3].split(':')\n" + \
"if 'mergeinfo' in caps:\n" + \
" fp.write('yes')\n" + \
"else:\n" + \
" fp.write('no')\n" + \
"fp.close()\n"
start_commit_hook = svntest.main.get_start_commit_hook_path(repos_dir)
svntest.main.create_python_hook_script(start_commit_hook, hook_text)
# Commit something.
iota_path = sbox.ospath('iota')
svntest.main.file_append(iota_path, "More stuff in iota")
svntest.actions.run_and_verify_svn([], [], 'ci', '--quiet',
'-m', 'log msg', wc_dir)
# Check that "mergeinfo" was detected.
log_path = os.path.join(repos_dir, "hooks.log")
if os.path.exists(log_path):
data = open(log_path).read()
os.unlink(log_path)
else:
raise svntest.verify.SVNUnexpectedOutput("'%s' not found") % log_path
if data != 'yes':
raise svntest.Failure
# Test for issue #3198
@Issue(3198)
def commit_added_missing(sbox):
"commit a missing to-be-added file should fail"
sbox.build()
wc_dir = sbox.wc_dir
mu_path = sbox.ospath('A/mu')
a_path = sbox.ospath('A/a.txt')
b_path = sbox.ospath('A/b.txt')
# Make two copies of mu: a and b
svntest.main.run_svn(None, 'cp', mu_path, a_path)
svntest.main.run_svn(None, 'cp', mu_path, b_path)
# remove b, make it missing
os.remove(b_path)
# Commit, hoping to see an error
svntest.actions.run_and_verify_svn([], ".* is scheduled for addition, but is missing",
'commit', '-m', 'logmsg', wc_dir)
#----------------------------------------------------------------------
# Helper for commit-failure tests
def commit_fails_at_path(path, wc_dir, error_re):
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
error_re,
path)
def tree_conflicts_block_commit(sbox):
"tree conflicts block commit"
# Commit is not allowed in a directory containing tree conflicts.
# This test corresponds to use cases 1-3 (with file victims) in
# notes/tree-conflicts/use-cases.txt.
svntest.actions.build_greek_tree_conflicts(sbox)
wc_dir = sbox.wc_dir
A = sbox.ospath('A')
D = sbox.ospath('A/D')
G = sbox.ospath('A/D/G')
error_re = ".*remains in conflict.*"
commit_fails_at_path(wc_dir, wc_dir, error_re)
commit_fails_at_path(A, A, error_re)
commit_fails_at_path(D, D, error_re)
commit_fails_at_path(G, G, error_re)
commit_fails_at_path(os.path.join(G, 'pi'), G, error_re)
def tree_conflicts_resolved(sbox):
"tree conflicts resolved"
# Commit is allowed after tree conflicts are resolved.
# This test corresponds to use cases 1-3 in
# notes/tree-conflicts/use-cases.txt.
svntest.actions.build_greek_tree_conflicts(sbox)
wc_dir = sbox.wc_dir
# Duplicate wc for tests
wc_dir_2 = sbox.add_wc_path('2')
svntest.actions.duplicate_dir(wc_dir, wc_dir_2)
# Mark the tree conflict victims as resolved
G = sbox.ospath('A/D/G')
victims = [ os.path.join(G, v) for v in ['pi', 'rho', 'tau'] ]
svntest.actions.run_and_verify_resolved(victims)
expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
expected_status.tweak('A/D/G/pi', status='D ')
expected_status.tweak('A/D/G/rho', status='A ', copied='+', wc_rev='-')
expected_status.remove('A/D/G/tau')
svntest.actions.run_and_verify_status(wc_dir, expected_status)
# Recursively resolved in parent directory -- expect same result
G2 = os.path.join(wc_dir_2, 'A', 'D', 'G')
victims = [ os.path.join(G2, v) for v in ['pi', 'rho', 'tau'] ]
svntest.actions.run_and_verify_resolved(victims, G2, '-R')
expected_status.wc_dir = wc_dir_2
svntest.actions.run_and_verify_status(wc_dir_2, expected_status)
#----------------------------------------------------------------------
def commit_multiple_nested_deletes(sbox):
"committing multiple nested deletes"
sbox.build()
wc_dir = sbox.wc_dir
A = sbox.ospath('A')
A_B = os.path.join(A, 'B')
sbox.simple_rm('A')
svntest.main.run_svn(None, 'ci', A, A_B, '-m', 'Q')
@Issue(4042)
def commit_incomplete(sbox):
"commit an incomplete dir"
sbox.build()
wc_dir = sbox.wc_dir
sbox.simple_propset('pname', 'pval', 'A/B')
svntest.actions.set_incomplete(sbox.ospath('A/B'), 1)
expected_output = svntest.wc.State(wc_dir, {
'A/B' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.tweak('A/B', status='! ', wc_rev=2)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
#----------------------------------------------------------------------
# Reported here:
# Message-ID: <4EBF0FC9.300@gmail.com>
# Date: Sun, 13 Nov 2011 13:31:05 +1300
# From: Fergus Slorach <sugref@gmail.com>
# Subject: svn commit --targets behaviour change in 1.7?
@Issue(4059)
def commit_add_subadd(sbox):
"committing add with explicit subadd targets"
sbox.build()
wc_dir = sbox.wc_dir
targets_file = sbox.ospath('targets') # ### better tempdir?
targets_file = os.path.abspath(targets_file)
# prepare targets file
targets = "A/D A/D/H A/D/H/chi A/D/H/omega A/D/H/psi".split()
with open(targets_file, 'w') as f:
f.write("\n".join(targets))
# r2: rm A/D
sbox.simple_rm('A/D')
sbox.simple_commit(message='rm')
# r3: revert r2, with specific invocation
os.chdir(wc_dir)
svntest.main.run_svn(None, 'up')
svntest.main.run_svn(None, 'merge', '-c', '-2', './')
svntest.main.run_svn(None, 'commit', '--targets', targets_file, '-mm')
def commit_danglers(sbox):
"verify committing some dangling children fails"
sbox.build(read_only=True)
wc_dir = sbox.wc_dir
sbox.simple_copy('A','A_copied')
A_copied = sbox.ospath('A_copied')
mu_copied = sbox.ospath('A_copied/mu')
svntest.main.file_write(mu_copied, "xxxx")
# We already test for this problem for some time
expected_error = "svn: E200009: '.*A_copied' .*exist.*yet.* '.*mu'.*part"
svntest.actions.run_and_verify_commit(mu_copied,
None,
None,
expected_error)
# But now do the same thing via changelist filtering
svntest.main.run_svn(None, 'changelist', 'L', mu_copied, sbox.ospath('A/mu'))
# And try to commit A_copied itself with changelist filtering
svntest.actions.run_and_verify_commit(A_copied,
None,
None,
expected_error,
A_copied, '--cl', 'L')
# And on the wcroot
svntest.actions.run_and_verify_commit(wc_dir,
None,
None,
expected_error,
wc_dir, '--cl', 'L')
#----------------------------------------------------------------------
# Test for issue 4203: Commit of moved dir with modified file in
# dir/subdir should bump LastChangedRev of subdir in originating WC
@XFail()
@Issue(4203)
def last_changed_of_copied_subdir(sbox):
"last changed of copied subdir"
sbox.build()
wc_dir = sbox.wc_dir
sbox.simple_move('A/B','A/B_copied')
B_copied = sbox.ospath('A/B_copied')
E_copied = sbox.ospath('A/B_copied/E')
alpha_copied = sbox.ospath('A/B_copied/E/alpha')
svntest.main.file_write(alpha_copied, "xxxx")
svntest.main.run_svn(None, 'commit', wc_dir, '-mm')
expected = {'Revision' : '2',
'Last Changed Rev' : '2',
}
svntest.actions.run_and_verify_info([expected], E_copied)
def commit_unversioned(sbox):
"verify behavior on unversioned targets"
sbox.build(read_only=True)
wc_dir = sbox.wc_dir
expected_err = '.*E200009: .*existing.*\' is not under version control.*'
# Unversioned, but existing file
svntest.main.file_write(sbox.ospath('existing'), "xxxx")
svntest.actions.run_and_verify_commit(wc_dir, None, None, expected_err,
sbox.ospath('existing'))
# Unversioned, not existing
svntest.actions.run_and_verify_commit(wc_dir, None, None, expected_err,
sbox.ospath('not-existing'))
@Issue(4400)
def commit_cp_with_deep_delete(sbox):
"verify behavior of a copy with a deep (>=3) delete"
sbox.build()
wc_dir = sbox.wc_dir
# Prep by adding a tree deep enough to exercise the issue.
sbox.simple_mkdir('A/B/E/I')
sbox.simple_commit(message='prep')
svntest.main.run_svn(None, 'up', wc_dir)
# copy the deep tree and then delete a dir 3 deep.
sbox.simple_copy('A','A2')
sbox.simple_rm('A2/B/E/I')
# come up with the expected output and status
expected_output = svntest.wc.State(wc_dir, {
'A2' : Item(verb='Adding'),
'A2/B/E/I' : Item(verb='Deleting'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
expected_status.add({
'A/B/E/I' : Item(status=' ', wc_rev='2'),
'A2' : Item(status=' ', wc_rev='3'),
'A2/B' : Item(status=' ', wc_rev='3'),
'A2/B/lambda' : Item(status=' ', wc_rev='3'),
'A2/B/F' : Item(status=' ', wc_rev='3'),
'A2/B/E' : Item(status=' ', wc_rev='3'),
'A2/B/E/alpha' : Item(status=' ', wc_rev='3'),
'A2/B/E/beta' : Item(status=' ', wc_rev='3'),
'A2/D' : Item(status=' ', wc_rev='3'),
'A2/D/gamma' : Item(status=' ', wc_rev='3'),
'A2/D/H' : Item(status=' ', wc_rev='3'),
'A2/D/H/psi' : Item(status=' ', wc_rev='3'),
'A2/D/H/omega' : Item(status=' ', wc_rev='3'),
'A2/D/H/chi' : Item(status=' ', wc_rev='3'),
'A2/D/G' : Item(status=' ', wc_rev='3'),
'A2/D/G/tau' : Item(status=' ', wc_rev='3'),
'A2/D/G/rho' : Item(status=' ', wc_rev='3'),
'A2/D/G/pi' : Item(status=' ', wc_rev='3'),
'A2/C' : Item(status=' ', wc_rev='3'),
'A2/mu' : Item(status=' ', wc_rev='3'),
})
# Commit the copy without the one dir.
svntest.actions.run_and_verify_commit(wc_dir,
expected_output,
expected_status)
def commit_deep_deleted(sbox):
"try to commit a deep descendant of a deleted node"
sbox.build()
sbox.simple_move('A', 'AA')
sbox.simple_propset('k', 'v', 'AA/D/G')
# Committing some added descendant returns a proper error
expected_err = ('.*svn: E200009: \'%s\' is not known to exist in the ' +
'repository and is not part of the commit, yet its ' +
'child \'%s\' is part of the commit.*') % (
re.escape(os.path.abspath(sbox.ospath('AA'))),
re.escape(os.path.abspath(sbox.ospath('AA/D/G'))))
svntest.actions.run_and_verify_commit(sbox.wc_dir,
None,
None,
expected_err,
sbox.ospath('AA/D/G'))
sbox.simple_propdel('k', 'AA/D/G')
sbox.simple_rm('AA/D/G')
# But a delete fails..
# This used to trigger an assertion in Subversion 1.8.0-1.8.8, because
# the status walker couldn't find the repository path for AA/D/G
svntest.actions.run_and_verify_commit(sbox.wc_dir,
None,
None,
expected_err,
sbox.ospath('AA/D/G'))
# And now commit like how a GUI client would do it, but forgetting the move
expected_err = ('svn: E200009: Cannot commit \'%s\' because it was moved ' +
'from \'%s\' which is not part of the commit; both sides ' +
'of the move must be committed together') % (
re.escape(os.path.abspath(sbox.ospath('AA'))),
re.escape(os.path.abspath(sbox.ospath('A'))))
svntest.actions.run_and_verify_commit(sbox.wc_dir,
None,
None,
expected_err,
'--depth', 'empty',
sbox.ospath('AA/D/G'),
sbox.ospath('AA'))
# And now how it works
svntest.actions.run_and_verify_commit(sbox.wc_dir,
None,
None,
[],
'--depth', 'empty',
sbox.ospath('AA/D/G'),
sbox.ospath('AA'),
sbox.ospath('A'))
@Issue(4480)
def commit_mergeinfo_ood(sbox):
"commit of mergeinfo that should cause out of date"
sbox.build()
sbox.simple_rm('A', 'iota')
sbox.simple_commit() # r2
sbox.simple_mkdir('trunk', 'branch')
sbox.simple_commit() # r3
sbox.simple_append('trunk/a', 'This is a\n')
sbox.simple_add('trunk/a')
sbox.simple_commit() # r4
sbox.simple_append('trunk/b', 'This is b\n')
sbox.simple_add('trunk/b')
sbox.simple_commit() # r5
sbox.simple_update() # To r5
expected_output = [
'--- Merging r4 into \'%s\':\n' % sbox.ospath('branch'),
'A %s\n' % sbox.ospath('branch/a'),
'--- Recording mergeinfo for merge of r4' \
' into \'%s\':\n' % sbox.ospath('branch'),
' U %s\n' % sbox.ospath('branch'),
]
svntest.actions.run_and_verify_svn(expected_output, [],
'merge', '-c4', '^/trunk',
sbox.ospath('branch'))
sbox.simple_commit()
sbox.simple_update(revision='5')
expected_output = [
'--- Merging r5 into \'%s\':\n' % sbox.ospath('branch'),
'A %s\n' % sbox.ospath('branch/b'),
'--- Recording mergeinfo for merge of r5 into \'%s\':\n' % sbox.ospath('branch'),
' U %s\n' % sbox.ospath('branch'),
]
svntest.actions.run_and_verify_svn(expected_output, [],
'merge', '-c5', '^/trunk',
sbox.ospath('branch'))
# Currently this commit succeeds with dav over HTTPv2, while it should really fail
expected_err = '.*out of date.*'
svntest.actions.run_and_verify_svn(None, expected_err,
'commit', sbox.ospath(''), '-m', 'M')
@Issue(2295)
def mkdir_conflict_proper_error(sbox):
"mkdir conflict should produce a proper error"
sbox.build(create_wc=False)
repo_url = sbox.repo_url
expected_error = "svn: E160020: .* already exists.*'/A'"
svntest.actions.run_and_verify_svn(None, expected_error,
'mkdir', repo_url + '/A',
'-m', '')
def commit_xml(sbox):
"commit an xml file"
sbox.build()
sbox.simple_add_text('index.xml', 'index.xml')
sbox.simple_add_text('index.html', 'index.html')
sbox.simple_propset('svn:mime-type', 'text/xml', 'index.xml')
sbox.simple_propset('svn:mime-type', 'text/html', 'index.html')
# This currently (2015-04-09) makes mod_dav return a 'HTTP/1.1 201 Created'
# result with content type text/xml (copied from file), which used to
# invoke the error parsing.
#
# Depending on the Apache version and config, this may cause an xml error.
sbox.simple_commit()
# This currently (2015-04-09) makes mod_dav return a 'HTTP/1.1 204 Updated'
# result with content type text/xml (copied from file), which used to
# invoke the error parsing.
#
# Depending on the Apache version and config, this may cause an xml error.
sbox.simple_append('index.xml', '<Q></R>', True)
sbox.simple_append('index.html', '<Q></R>', True)
sbox.simple_commit()
@Issue(4722)
def commit_issue4722_checksum(sbox):
"commit that triggered checksum failure"
sbox.build()
# This bug only ever affected FSFS in 1.9.7. The test could be
# considered a bit "fragile" as any change to the on-disk
# representation may well make it pass trivially. On the other hand
# it should still pass irrespective of that representation, and for
# all other repository types.
# Enough data to allow the bug to occur
with open(sbox.ospath('f'), 'w') as fp:
for i in range(0, 2001):
fp.write('abcdefghijklmnopqrstuvwxyz')
sbox.simple_add('f')
sbox.simple_commit()
# Just the right data to trigger the bug
with open(sbox.ospath('f'), 'w') as fp:
for i in range(0, 8713):
fp.write(str(i))
fp.write("11111")
sbox.simple_commit()
# Trigger deduplication which is when the bug occurred
with open(sbox.ospath('f'), 'w') as fp:
for i in range(0, 2001):
fp.write('abcdefghijklmnopqrstuvwxyz')
sbox.simple_commit()
@XFail()
def commit_sees_tree_conflict_on_unversioned_path(sbox):
"commit sees tree conflict on unversioned path"
sbox.build(empty=True)
was_cwd = os.getcwd()
os.chdir(sbox.wc_dir)
sbox.wc_dir = '.'
# create a tree conflict victim at an unversioned path
sbox.simple_mkdir('topdir')
sbox.simple_commit()
sbox.simple_mkdir('topdir/subdir')
sbox.simple_commit()
sbox.simple_update()
sbox.simple_rm('topdir')
sbox.simple_commit()
sbox.simple_update()
svntest.actions.run_and_verify_svn(
None, [],
'merge', '-c2', sbox.wc_dir, '--ignore-ancestry', '--accept', 'postpone')
# check that we did create a conflict
svntest.actions.run_and_verify_svn(
None, 'svn: E155015:.*existing.*conflict.*',
'merge', '-c1', sbox.wc_dir, '--ignore-ancestry', '--accept', 'postpone')
# attempt to commit; should fail
expected_err = "svn: E155015: .* '.*topdir' remains in conflict"
svntest.actions.run_and_verify_commit(sbox.wc_dir, None, None,
expected_err,
sbox.wc_dir)
os.chdir(was_cwd)
########################################################################
# Run the tests
# list all tests here, starting with None:
test_list = [ None,
commit_one_file,
commit_one_new_file,
commit_one_new_binary_file,
commit_multiple_targets,
commit_multiple_targets_2,
commit_inclusive_dir,
commit_top_dir,
commit_unversioned_thing,
nested_dir_replacements,
hudson_part_1,
hudson_part_1_variation_1,
hudson_part_1_variation_2,
hudson_part_2,
hudson_part_2_1,
hook_test,
merge_mixed_revisions,
commit_uri_unsafe,
commit_deleted_edited,
commit_in_dir_scheduled_for_addition,
commit_rmd_and_deleted_file,
commit_add_file_twice,
commit_from_long_dir,
commit_with_lock,
commit_current_dir,
commit_multiple_wc_nested,
commit_multiple_wc,
commit_multiple_wc_multiple_repos,
commit_nonrecursive,
failed_commit,
commit_out_of_date_deletions,
commit_with_bad_log_message,
commit_with_mixed_line_endings,
commit_with_mixed_line_endings_in_ignored_part,
from_wc_top_with_bad_editor,
mods_in_schedule_delete,
tab_test,
local_mods_are_not_commits,
post_commit_hook_test,
commit_same_folder_in_targets,
commit_inconsistent_eol,
mkdir_with_revprop,
delete_with_revprop,
commit_with_revprop,
import_with_revprop,
copy_R2R_with_revprop,
copy_WC2R_with_revprop,
move_R2R_with_revprop,
propedit_with_revprop,
set_multiple_props_with_revprop,
use_empty_value_in_revprop_pair,
no_equals_in_revprop_pair,
set_invalid_revprops,
start_commit_hook_test,
pre_commit_hook_test,
versioned_log_message,
changelist_near_conflict,
commit_out_of_date_file,
start_commit_detect_capabilities,
commit_added_missing,
tree_conflicts_block_commit,
tree_conflicts_resolved,
commit_multiple_nested_deletes,
commit_incomplete,
commit_add_subadd,
commit_danglers,
last_changed_of_copied_subdir,
commit_unversioned,
commit_cp_with_deep_delete,
commit_deep_deleted,
commit_mergeinfo_ood,
mkdir_conflict_proper_error,
commit_xml,
commit_issue4722_checksum,
commit_sees_tree_conflict_on_unversioned_path,
]
if __name__ == '__main__':
svntest.main.run_tests(test_list)
# NOTREACHED
### End of file.