#!/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.