blob: 490e981c86368e3e3dd0cad8fa02d9817929e736 [file] [log] [blame]
#!/usr/bin/env python
#
# wc_tests.py: testing working-copy operations
#
# 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
from __future__ import with_statement
import shutil, stat, re, os, logging
logger = logging.getLogger()
# Our testing module
import svntest
from svntest import wc
# (abbreviation)
Skip = svntest.testcase.Skip_deco
SkipUnless = svntest.testcase.SkipUnless_deco
XFail = svntest.testcase.XFail_deco
Issues = svntest.testcase.Issues_deco
Issue = svntest.testcase.Issue_deco
Wimp = svntest.testcase.Wimp_deco
Item = wc.StateItem
UnorderedOutput = svntest.verify.UnorderedOutput
######################################################################
# Tests
#
# Each test must return on success or raise on failure.
@XFail()
@Issue(4193)
@SkipUnless(svntest.main.is_posix_os)
def status_through_unversioned_symlink(sbox):
"""file status through unversioned symlink"""
sbox.build(read_only = True)
state = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
os.symlink('A', sbox.ospath('Z'))
svntest.actions.run_and_verify_status(sbox.ospath('Z/mu'), state)
@XFail()
@Issue(4193)
@SkipUnless(svntest.main.is_posix_os)
def status_through_versioned_symlink(sbox):
"""file status through versioned symlink"""
sbox.build(read_only = True)
state = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
os.symlink('A', sbox.ospath('Z'))
sbox.simple_add('Z')
state.add({'Z': Item(status='A ')})
svntest.actions.run_and_verify_status(sbox.ospath('Z/mu'), state)
@XFail()
@Issue(4193)
@SkipUnless(svntest.main.is_posix_os)
def status_with_symlink_in_path(sbox):
"""file status with not-parent symlink"""
sbox.build(read_only = True)
state = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
os.symlink('A', sbox.ospath('Z'))
svntest.actions.run_and_verify_status(sbox.ospath('Z/B/lambda'), state)
@XFail()
@Issue(4193)
@SkipUnless(svntest.main.is_posix_os)
def add_through_unversioned_symlink(sbox):
"""add file through unversioned symlink"""
sbox.build(read_only = True)
os.symlink('A', sbox.ospath('Z'))
sbox.simple_append('A/kappa', 'xyz', True)
sbox.simple_add('Z/kappa')
@XFail()
@Issue(4193)
@SkipUnless(svntest.main.is_posix_os)
def add_through_versioned_symlink(sbox):
"""add file through versioned symlink"""
sbox.build(read_only = True)
os.symlink('A', sbox.ospath('Z'))
sbox.simple_add('Z')
sbox.simple_append('A/kappa', 'xyz', True)
sbox.simple_add('Z/kappa')
@XFail()
@Issue(4193)
@SkipUnless(svntest.main.is_posix_os)
def add_with_symlink_in_path(sbox):
"""add file with not-parent symlink"""
sbox.build(read_only = True)
os.symlink('A', sbox.ospath('Z'))
sbox.simple_append('A/B/kappa', 'xyz', True)
sbox.simple_add('Z/B/kappa')
def is_posix_os_and_not_root():
if not svntest.main.is_posix_os():
return False
return os.getuid() != 0
@Issue(4118)
@SkipUnless(is_posix_os_and_not_root)
def status_with_inaccessible_wc_db(sbox):
"""inaccessible .svn/wc.db"""
sbox.build(read_only = True)
os.chmod(sbox.ospath(".svn/wc.db"), 0)
svntest.actions.run_and_verify_svn(
None,
r"[^ ]+ E155016: The working copy database at '.*' is corrupt",
"st", sbox.wc_dir)
@Issue(4118)
def status_with_corrupt_wc_db(sbox):
"""corrupt .svn/wc.db"""
sbox.build(read_only = True)
with open(sbox.ospath(".svn/wc.db"), 'wb') as fd:
fd.write(b'\0' * 17)
svntest.actions.run_and_verify_svn(
None,
r"[^ ]+ E155016: The working copy database at '.*' is corrupt",
"st", sbox.wc_dir)
@Issue(4118)
def status_with_zero_length_wc_db(sbox):
"""zero-length .svn/wc.db"""
sbox.build(read_only = True)
os.close(os.open(sbox.ospath(".svn/wc.db"), os.O_RDWR | os.O_TRUNC))
svntest.actions.run_and_verify_svn(
None,
r"[^ ]+ E200030:", # SVN_ERR_SQLITE_ERROR
"st", sbox.wc_dir)
@Issue(4118)
def status_without_wc_db(sbox):
"""missing .svn/wc.db"""
sbox.build(read_only = True)
os.remove(sbox.ospath(".svn/wc.db"))
svntest.actions.run_and_verify_svn(
None,
r"[^ ]+ E155016: The working copy database at '.*' is missing",
"st", sbox.wc_dir)
@Issue(4118)
@Skip() # FIXME: Test fails in-tree because it finds the source WC root
def status_without_wc_db_and_entries(sbox):
"""missing .svn/wc.db and .svn/entries"""
sbox.build(read_only = True)
os.remove(sbox.ospath(".svn/wc.db"))
os.remove(sbox.ospath(".svn/entries"))
svntest.actions.run_and_verify_svn2(
None,
r"[^ ]+ warning: W155007: '.*' is not a working copy",
0, "st", sbox.wc_dir)
@Issue(4118)
def status_with_missing_wc_db_and_maybe_valid_entries(sbox):
"""missing .svn/wc.db, maybe valid .svn/entries"""
sbox.build(read_only = True)
with open(sbox.ospath(".svn/entries"), 'ab') as fd:
fd.write(b'something\n')
os.remove(sbox.ospath(".svn/wc.db"))
svntest.actions.run_and_verify_svn(
None,
r"[^ ]+ E155036:", # SVN_ERR_WC_UPGRADE_REQUIRED
"st", sbox.wc_dir)
@Issue(4267)
def cleanup_below_wc_root(sbox):
"""cleanup from directory below WC root"""
sbox.build(read_only = True)
svntest.actions.lock_admin_dir(sbox.ospath(""), True)
svntest.actions.run_and_verify_svn(None, [],
"cleanup", sbox.ospath("A"))
@SkipUnless(svntest.main.is_posix_os)
@Issue(4383)
def update_through_unversioned_symlink(sbox):
"""update through unversioned symlink"""
sbox.build(read_only = True)
wc_dir = sbox.wc_dir
state = svntest.actions.get_virginal_state(wc_dir, 1)
symlink = sbox.get_tempname()
os.symlink(os.path.abspath(sbox.wc_dir), symlink)
expected_output = []
expected_disk = []
expected_status = []
# Subversion 1.8.0 crashes when updating a working copy through a symlink
svntest.actions.run_and_verify_update(wc_dir, expected_output,
expected_disk, expected_status,
[], True, symlink)
@Issue(3549)
def cleanup_unversioned_items(sbox):
"""cleanup --remove-unversioned / --remove-ignored"""
sbox.build(read_only = True)
wc_dir = sbox.wc_dir
# create some unversioned items
os.mkdir(sbox.ospath('dir1'))
os.mkdir(sbox.ospath('dir2'))
contents = "This is an unversioned file\n."
svntest.main.file_write(sbox.ospath('dir1/dir1_child1'), contents)
svntest.main.file_write(sbox.ospath('dir2/dir2_child1'), contents)
os.mkdir(sbox.ospath('dir2/foo_child2'))
svntest.main.file_write(sbox.ospath('file_foo'), contents),
os.mkdir(sbox.ospath('dir_foo'))
svntest.main.file_write(sbox.ospath('dir_foo/foo_child1'), contents)
os.mkdir(sbox.ospath('dir_foo/foo_child2'))
# a file that matches a default ignore pattern
svntest.main.file_write(sbox.ospath('foo.o'), contents)
# ignore some of the unversioned items
sbox.simple_propset('svn:ignore', '*_foo', '.')
os.chdir(wc_dir)
expected_output = [
' M .\n',
'? dir1\n',
'? dir2\n',
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], 'status')
expected_output += [
'I dir_foo\n',
'I file_foo\n',
'I foo.o\n',
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], 'status', '--no-ignore')
expected_output = [
'D dir1\n',
'D dir2\n',
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], 'cleanup', '--remove-unversioned')
expected_output = [
' M .\n',
'I dir_foo\n',
'I file_foo\n',
'I foo.o\n',
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], 'status', '--no-ignore')
# remove ignored items, with an empty global-ignores list
expected_output = [
'D dir_foo\n',
'D file_foo\n',
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], 'cleanup', '--remove-ignored',
'--config-option',
'config:miscellany:global-ignores=')
# the file matching global-ignores should still be present
expected_output = [
' M .\n',
'I foo.o\n',
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], 'status', '--no-ignore')
# un-ignore the file matching global ignores, making it unversioned,
# and remove it with --remove-unversioned
expected_output = [
'D foo.o\n',
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], 'cleanup', '--remove-unversioned',
'--config-option',
'config:miscellany:global-ignores=')
expected_output = [
' M .\n',
]
svntest.actions.run_and_verify_svn(expected_output,
[], 'status', '--no-ignore')
def cleanup_unversioned_items_in_locked_wc(sbox):
"""cleanup unversioned items in locked WC should fail"""
sbox.build(read_only = True)
contents = "This is an unversioned file\n."
svntest.main.file_write(sbox.ospath('unversioned_file'), contents)
svntest.actions.lock_admin_dir(sbox.ospath(""), True)
for option in ['--remove-unversioned', '--remove-ignored']:
svntest.actions.run_and_verify_svn(None,
"svn: E155004: Working copy locked;.*",
"cleanup", option,
sbox.ospath(""))
def cleanup_dir_external(sbox):
"""cleanup --include-externals"""
sbox.build(read_only = True)
# configure a directory external
sbox.simple_propset("svn:externals", "^/A A_ext", ".")
sbox.simple_update()
svntest.actions.lock_admin_dir(sbox.ospath("A_ext"), True)
svntest.actions.run_and_verify_svn(["Performing cleanup on external " +
"item at '%s'.\n" % sbox.ospath("A_ext")],
[], "cleanup", '--include-externals',
sbox.ospath(""))
@Issue(4390)
def checkout_within_locked_wc(sbox):
"""checkout within a locked working copy"""
sbox.build(read_only = True)
# lock working copy and create outstanding work queue items
svntest.actions.lock_admin_dir(sbox.ospath(""), True, True)
expected_output = [
"A %s\n" % sbox.ospath("nested-wc/alpha"),
"A %s\n" % sbox.ospath("nested-wc/beta"),
"Checked out revision 1.\n"
]
svntest.actions.run_and_verify_svn(UnorderedOutput(expected_output),
[], "checkout", sbox.repo_url + '/A/B/E',
sbox.ospath("nested-wc"))
########################################################################
# Run the tests
# list all tests here, starting with None:
test_list = [ None,
status_through_unversioned_symlink,
status_through_versioned_symlink,
status_with_symlink_in_path,
add_through_unversioned_symlink,
add_through_versioned_symlink,
add_with_symlink_in_path,
status_with_inaccessible_wc_db,
status_with_corrupt_wc_db,
status_with_zero_length_wc_db,
status_without_wc_db,
status_without_wc_db_and_entries,
status_with_missing_wc_db_and_maybe_valid_entries,
cleanup_below_wc_root,
update_through_unversioned_symlink,
cleanup_unversioned_items,
cleanup_unversioned_items_in_locked_wc,
cleanup_dir_external,
checkout_within_locked_wc,
]
if __name__ == '__main__':
svntest.main.run_tests(test_list)
# NOTREACHED
### End of file.