blob: 78ba037557dd690af6a564e3a553ad651a22a85c [file] [log] [blame]
#!/usr/bin/env python
#
# entries_tests.py: test the old entries API using entries-dump
#
# 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.
######################################################################
#
# This test series is to validate the old entries API using the entries-dump
# tool to see what the API reports. In particular, this test is designed to
# try and exercise all "extraordinary" code paths in the read_entries()
# function in libsvn_wc/entries.c. Much of that function is exercised by
# the regular test suite and its secondary "status" via entries-dump. This
# test tries to pick up the straggly little edge cases.
#
import os, logging
logger = logging.getLogger()
import svntest
Item = svntest.wc.StateItem
SCHEDULE_NORMAL = 0
SCHEDULE_ADD = 1
SCHEDULE_DELETE = 2
SCHEDULE_REPLACE = 3
def validate(entry, **kw):
for key, value in kw.items():
if getattr(entry, key) != value:
logger.warn("Entry '%s' has an incorrect value for .%s", entry.name, key)
logger.warn(" Expected: %s", value)
logger.warn(" Actual: %s", getattr(entry, key))
raise svntest.Failure
def check_names(entries, *names):
if entries is None:
logger.warn('entries-dump probably exited with a failure.')
raise svntest.Failure
have = set(entries.keys())
want = set(names)
missing = want - have
if missing:
logger.warn("Entry name(s) not found: %s",
', '.join("'%s'" % name for name in missing))
raise svntest.Failure
def basic_entries(sbox):
"basic entries behavior"
sbox.build()
wc_dir = sbox.wc_dir
alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
beta_path = os.path.join(wc_dir, 'A', 'B', 'E', 'beta')
added_path = os.path.join(wc_dir, 'A', 'B', 'E', 'added')
G_path = os.path.join(wc_dir, 'A', 'D', 'G')
G2_path = os.path.join(wc_dir, 'A', 'D', 'G2')
iota_path = os.path.join(wc_dir, 'iota')
iota2_path = os.path.join(wc_dir, 'A', 'B', 'E', 'iota2')
# Remove 'alpha'. When it is committed, it will be marked DELETED.
svntest.actions.run_and_verify_svn(None, [], 'rm', alpha_path)
# Tweak 'beta' in order to bump its revision to ensure the replacement
# gets the new revision (2), not the value from the parent (1).
svntest.actions.run_and_verify_svn(None, [],
'ps', 'random-prop', 'propvalue',
beta_path)
expected_output = svntest.wc.State(wc_dir, {
'A/B/E/alpha' : Item(verb='Deleting'),
'A/B/E/beta' : Item(verb='Sending'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.remove('A/B/E/alpha')
expected_status.tweak('A/B/E/beta', wc_rev=2)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output, expected_status,
[],
alpha_path, beta_path)
# bump 'G' and iota another revision (3) for later testing
svntest.actions.run_and_verify_svn(None, [],
'ps', 'random-prop', 'propvalue',
G_path, iota_path)
expected_output = svntest.wc.State(wc_dir, {
'A/D/G' : Item(verb='Sending'),
'iota' : Item(verb='Sending'),
})
expected_status.tweak('A/D/G', 'iota', wc_rev=3)
svntest.actions.run_and_verify_commit(wc_dir,
expected_output, expected_status,
[],
G_path, iota_path)
# Add a file over the DELETED 'alpha'. It should be schedule-add.
with open(alpha_path, 'w') as f:
f.write('New alpha contents\n')
# Delete 'beta', then add a file over it. Should be schedule-replace.
svntest.actions.run_and_verify_svn(None, [], 'rm', beta_path)
with open(beta_path, 'w') as f:
f.write('New beta contents\n')
# Plain old add. Should have revision == 0.
with open(added_path, 'w') as f:
f.write('Added file contents\n')
svntest.actions.run_and_verify_svn(None, [], 'add',
alpha_path, beta_path, added_path)
svntest.actions.run_and_verify_svn(None, [], 'cp',
iota_path, iota2_path)
entries = svntest.main.run_entriesdump(os.path.join(wc_dir, 'A', 'B', 'E'))
check_names(entries, 'alpha', 'beta', 'added', 'iota2')
# plain add should be rev=0. over a DELETED, should be SCHEDULE_ADD
validate(entries['alpha'], schedule=SCHEDULE_ADD, revision=0, copied=False)
# should pick up the BASE node's revision
validate(entries['beta'], schedule=SCHEDULE_REPLACE, revision=2,
copied=False)
# plain add should be rev=0
validate(entries['added'], schedule=SCHEDULE_ADD, revision=0, copied=False)
# copyfrom_rev is (3), but we inherit the rev from the parent (1)
validate(entries['iota2'], schedule=SCHEDULE_ADD, revision=1, copied=True,
copyfrom_rev=3)
svntest.actions.run_and_verify_svn(None, [], 'cp', G_path, G2_path)
entries = svntest.main.run_entriesdump(G2_path)
check_names(entries, 'pi', 'rho', 'tau')
# added, but revision should match the copyfrom_rev (directories don't
# inherit a revision like iota2 did above)
validate(entries[''], schedule=SCHEDULE_ADD, copied=True, revision=3)
# children should be SCHEDULE_NORMAL. still rev=1 cuz of mixed-rev source.
validate(entries['pi'], schedule=SCHEDULE_NORMAL, copied=True, revision=1)
def obstructed_entries(sbox):
"validate entries when obstructions exist"
sbox.build()
wc_dir = sbox.wc_dir
D_path = os.path.join(wc_dir, 'A', 'D')
H_path = os.path.join(wc_dir, 'A', 'D', 'H')
# blast a directory. its revision should become SVN_INVALID_REVNUM.
entries = svntest.main.run_entriesdump(D_path)
check_names(entries, 'H')
validate(entries['H'], revision=1)
svntest.main.safe_rmtree(H_path)
entries = svntest.main.run_entriesdump(D_path)
check_names(entries, 'H')
# Data is not missing in single-db
validate(entries['H'], revision=1)
### need to get svn_wc__db_read_info() to generate obstructed_add
def deletion_details(sbox):
"various details about deleted nodes"
sbox.build()
wc_dir = sbox.wc_dir
iota_path = os.path.join(wc_dir, 'iota')
D_path = os.path.join(wc_dir, 'A', 'D')
D2_path = os.path.join(wc_dir, 'A', 'D2')
D2_G_path = os.path.join(wc_dir, 'A', 'D2', 'G')
E_path = os.path.join(wc_dir, 'A', 'B', 'E')
H_path = os.path.join(wc_dir, 'A', 'D', 'H')
entries = svntest.main.run_entriesdump(wc_dir)
check_names(entries, 'iota')
iota = entries['iota']
# blast iota, then verify the now-deleted entry still contains much of
# the same information.
svntest.actions.run_and_verify_svn(None, [], 'rm', iota_path)
entries = svntest.main.run_entriesdump(wc_dir)
check_names(entries, 'iota')
validate(entries['iota'], revision=iota.revision,
cmt_rev=iota.cmt_rev, cmt_author=iota.cmt_author)
# even deleted nodes have a URL
validate(entries['iota'], url='%s/iota' % sbox.repo_url)
svntest.actions.run_and_verify_svn(None, [], 'cp', D_path, D2_path)
svntest.actions.run_and_verify_svn(None, [], 'rm', D2_G_path)
entries = svntest.main.run_entriesdump(D2_path)
check_names(entries, 'gamma', 'G')
# copied nodes have URLs
validate(entries['gamma'], url='%s/A/D2/gamma' % sbox.repo_url,
copied=True, schedule=SCHEDULE_NORMAL)
entries = svntest.main.run_entriesdump(D2_G_path)
check_names(entries, 'pi')
# oh, and this sucker has a URL, too
validate(entries['pi'], url='%s/A/D2/G/pi' % sbox.repo_url,
copied=True, schedule=SCHEDULE_DELETE)
### hmm. somehow, subtrees can be *added* over a *deleted* subtree.
### maybe this can happen via 'svn merge' ? ... the operations below
### will fail because E_path is scheduled for deletion, disallowing
### any new node to sit on top of it. (tho it *should* allow it...)
### for now... this test case is done. just return
return
svntest.actions.run_and_verify_svn(None, [], 'rm', E_path)
svntest.actions.run_and_verify_svn(None, [], 'cp', H_path, E_path)
entries = svntest.main.run_entriesdump(E_path)
check_names(entries, 'chi', 'omega', 'psi', 'alpha', 'beta')
validate(entries['alpha'], schedule=SCHEDULE_DELETE)
validate(entries['chi'], schedule=SCHEDULE_NORMAL, copied=True)
########################################################################
# Run the tests
# list all tests here, starting with None:
test_list = [ None,
basic_entries,
obstructed_entries,
deletion_details,
]
if __name__ == '__main__':
svntest.main.run_tests(test_list)
# NOTREACHED