blob: 4263669499d6c1626ca34f2727067955df538e5e [file] [log] [blame]
#!/usr/bin/env python
#
# basic_tests.py: testing working-copy interactions with ra_local
#
# Subversion is a tool for revision control.
# See http://subversion.tigris.org for more information.
#
# ====================================================================
# Copyright (c) 2000-2001 CollabNet. All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://subversion.tigris.org/license-1.html.
# If newer versions of this license are posted there, you may use a
# newer version instead, at your option.
#
######################################################################
# General modules
import string, sys, re, os.path
# Our testing module
import svntest
# (abbreviation)
path_index = svntest.actions.path_index
######################################################################
# Tests
#
# Each test must return 0 on success or non-zero on failure.
#----------------------------------------------------------------------
def basic_checkout(sbox):
"basic checkout of a wc"
return sbox.build()
#----------------------------------------------------------------------
def basic_status(sbox):
"basic status command"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
# Created expected output tree for 'svn status'
status_list = svntest.actions.get_virginal_status_list(wc_dir, '1')
expected_output_tree = svntest.tree.build_generic_tree(status_list)
return svntest.actions.run_and_verify_status (wc_dir, expected_output_tree)
#----------------------------------------------------------------------
def basic_commit(sbox):
"basic commit command"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
# Make a couple of local mods to files
mu_path = os.path.join(wc_dir, 'A', 'mu')
rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
svntest.main.file_append (mu_path, 'appended mu text')
svntest.main.file_append (rho_path, 'new appended text for rho')
# Created expected output tree for 'svn ci'
output_list = [ [mu_path, None, {}, {'verb' : 'Sending' }],
[rho_path, None, {}, {'verb' : 'Sending' }] ]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected status tree; all local revisions should be at 1,
# but mu and rho should be at revision 2.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '2')
for item in status_list:
if (item[0] != mu_path) and (item[0] != rho_path):
item[3]['wc_rev'] = '1'
expected_status_tree = svntest.tree.build_generic_tree(status_list)
return svntest.actions.run_and_verify_commit (wc_dir,
expected_output_tree,
expected_status_tree,
None,
None, None,
None, None,
wc_dir)
#----------------------------------------------------------------------
def basic_update(sbox):
"basic update command"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
# Make a backup copy of the working copy
wc_backup = wc_dir + 'backup'
svntest.actions.duplicate_dir(wc_dir, wc_backup)
# Make a couple of local mods to files
mu_path = os.path.join(wc_dir, 'A', 'mu')
rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
svntest.main.file_append (mu_path, 'appended mu text')
svntest.main.file_append (rho_path, 'new appended text for rho')
# Created expected output tree for 'svn ci'
output_list = [ [mu_path, None, {}, {'verb' : 'Sending' }],
[rho_path, None, {}, {'verb' : 'Sending' }] ]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected status tree; all local revisions should be at 1,
# but mu and rho should be at revision 2.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '2')
for item in status_list:
if (item[0] != mu_path) and (item[0] != rho_path):
item[3]['wc_rev'] = '1'
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# Commit.
if svntest.actions.run_and_verify_commit (wc_dir, expected_output_tree,
expected_status_tree, None,
None, None, None, None, wc_dir):
return 1
# Create expected output tree for an update of the wc_backup.
output_list = [[os.path.join(wc_backup, 'A', 'mu'),
None, {}, {'status' : 'U '}],
[os.path.join(wc_backup, 'A', 'D', 'G', 'rho'),
None, {}, {'status' : 'U '}]]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected disk tree for the update.
my_greek_tree = svntest.main.copy_greek_tree()
my_greek_tree[2][1] = my_greek_tree[2][1] + 'appended mu text'
my_greek_tree[14][1] = my_greek_tree[14][1] + 'new appended text for rho'
expected_disk_tree = svntest.tree.build_generic_tree(my_greek_tree)
# Create expected status tree for the update.
status_list = svntest.actions.get_virginal_status_list(wc_backup, '2')
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# Do the update and check the results in three ways.
return svntest.actions.run_and_verify_update(wc_backup,
expected_output_tree,
expected_disk_tree,
expected_status_tree)
#----------------------------------------------------------------------
def basic_merge(sbox):
"basic merge"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
# First change the greek tree to make two files 10 lines long
mu_path = os.path.join(wc_dir, 'A', 'mu')
rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
mu_text = ""
rho_text = ""
for x in range(2,11):
mu_text = mu_text + '\nThis is line ' + `x` + ' in mu'
rho_text = rho_text + '\nThis is line ' + `x` + ' in rho'
svntest.main.file_append (mu_path, mu_text)
svntest.main.file_append (rho_path, rho_text)
# Create expected output tree for initial commit
output_list = [ [mu_path, None, {}, {'verb' : 'Sending' }],
[rho_path, None, {}, {'verb' : 'Sending' }] ]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected status tree : rev 2 for rho and mu.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '1')
for item in status_list:
item[3]['repos_rev'] = '2'
if (item[0] == mu_path) or (item[0] == rho_path):
item[3]['wc_rev'] = '2'
item[3]['status'] = '_ '
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# Initial commit.
if svntest.actions.run_and_verify_commit (wc_dir,
expected_output_tree,
expected_status_tree,
None,
None, None, None, None,
wc_dir):
return 1
# Make a backup copy of the working copy
wc_backup = wc_dir + 'backup'
svntest.actions.duplicate_dir(wc_dir, wc_backup)
# Make a couple of local mods to files
svntest.main.file_append (mu_path, ' Appended to line 10 of mu')
svntest.main.file_append (rho_path, ' Appended to line 10 of rho')
# Created expected output tree for 'svn ci'
output_list = [ [mu_path, None, {}, {'verb' : 'Sending' }],
[rho_path, None, {}, {'verb' : 'Sending' }] ]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected status tree; all local revisions should be at 1,
# but mu and rho should be at revision 3.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '1')
for item in status_list:
item[3]['repos_rev'] = '3'
if (item[0] == mu_path) or (item[0] == rho_path):
item[3]['wc_rev'] = '3'
item[3]['status'] = '_ '
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# Commit.
if svntest.actions.run_and_verify_commit (wc_dir,
expected_output_tree,
expected_status_tree,
None,
None, None, None, None,
wc_dir):
return 1
# Make local mods to wc_backup by recreating mu and rho
mu_path_backup = os.path.join(wc_backup, 'A', 'mu')
rho_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'rho')
fp_mu = open(mu_path_backup, 'w+')
# open in 'truncate to zero then write" mode
backup_mu_text='This is the new line 1 in the backup copy of mu'
for x in range(2,11):
backup_mu_text = backup_mu_text + '\nThis is line ' + `x` + ' in mu'
fp_mu.write(backup_mu_text)
fp_mu.close()
fp_rho = open(rho_path_backup, 'w+') # now open rho in write mode
backup_rho_text='This is the new line 1 in the backup copy of rho'
for x in range(2,11):
backup_rho_text = backup_rho_text + '\nThis is line ' + `x` + ' in rho'
fp_rho.write(backup_rho_text)
fp_rho.close()
# Create expected output tree for an update of the wc_backup.
output_list = [[os.path.join(wc_backup, 'A', 'mu'),
None, {}, {'status' : 'G '}],
[os.path.join(wc_backup, 'A', 'D', 'G', 'rho'),
None, {}, {'status' : 'G '}]]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected disk tree for the update.
my_greek_tree = svntest.main.copy_greek_tree()
my_greek_tree[2][1] = 'This is the new line 1 in the backup copy of mu'
for x in range(2,11):
my_greek_tree[2][1] = my_greek_tree[2][1] + '\nThis is line ' + `x` + ' in mu'
my_greek_tree[2][1] = my_greek_tree[2][1] + ' Appended to line 10 of mu'
my_greek_tree[14][1] = 'This is the new line 1 in the backup copy of rho'
for x in range(2,11):
my_greek_tree[14][1] = my_greek_tree[14][1] + '\nThis is line ' + `x` + ' in rho'
my_greek_tree[14][1] = my_greek_tree[14][1] + ' Appended to line 10 of rho'
expected_disk_tree = svntest.tree.build_generic_tree(my_greek_tree)
# Create expected status tree for the update.
status_list = svntest.actions.get_virginal_status_list(wc_backup, '3')
for item in status_list:
if (item[0] == mu_path_backup) or (item[0] == rho_path_backup):
item[3]['status'] = 'M '
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# Do the update and check the results in three ways.
return svntest.actions.run_and_verify_update(wc_backup,
expected_output_tree,
expected_disk_tree,
expected_status_tree)
#----------------------------------------------------------------------
# Helper for basic_conflict() test -- a custom singleton handler.
def detect_conflict_files(node, extra_files):
"""NODE has been discovered an an extra file on disk. Verify that
it matches one of the regular expressions in the EXTRA_FILES list.
If it matches, remove the match from the list. If it doesn't match,
raise an exception."""
for pattern in extra_files:
mo = re.match(pattern, node.name)
if mo:
extra_files.pop(extra_files.index(pattern)) # delete pattern from list
return 0
print "Found unexpected disk object:", node.name
raise svntest.tree.SVNTreeUnequal
def basic_conflict(sbox):
"basic conflict creation and resolution"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
# Make a backup copy of the working copy
wc_backup = wc_dir + 'backup'
svntest.actions.duplicate_dir(wc_dir, wc_backup)
# Make a couple of local mods to files which will be committed
mu_path = os.path.join(wc_dir, 'A', 'mu')
rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
svntest.main.file_append (mu_path, '\nOriginal appended text for mu')
svntest.main.file_append (rho_path, '\nOriginal appended text for rho')
# Make a couple of local mods to files which will be conflicted
mu_path_backup = os.path.join(wc_backup, 'A', 'mu')
rho_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'rho')
svntest.main.file_append (mu_path_backup,
'\nConflicting appended text for mu')
svntest.main.file_append (rho_path_backup,
'\nConflicting appended text for rho')
# Created expected output tree for 'svn ci'
output_list = [ [mu_path, None, {}, {'verb' : 'Sending' }],
[rho_path, None, {}, {'verb' : 'Sending' }] ]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected status tree; all local revisions should be at 1,
# but mu and rho should be at revision 2.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '2')
for item in status_list:
if (item[0] != mu_path) and (item[0] != rho_path):
item[3]['wc_rev'] = '1'
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# Commit.
if svntest.actions.run_and_verify_commit (wc_dir, expected_output_tree,
expected_status_tree, None,
None, None, None, None, wc_dir):
return 1
# Create expected output tree for an update of the wc_backup.
output_list = [ [mu_path_backup, None, {}, {'status' : 'C '}],
[rho_path_backup, None, {}, {'status' : 'C '}]]
expected_output_tree = svntest.tree.build_generic_tree(output_list)
# Create expected disk tree for the update.
my_greek_tree = svntest.main.copy_greek_tree()
my_greek_tree[2][1] = """<<<<<<< .mine
This is the file 'mu'.
Conflicting appended text for mu||||||| .r1
This is the file 'mu'.=======
This is the file 'mu'.
Original appended text for mu>>>>>>> .r2
"""
my_greek_tree[14][1] = """<<<<<<< .mine
This is the file 'rho'.
Conflicting appended text for rho||||||| .r1
This is the file 'rho'.=======
This is the file 'rho'.
Original appended text for rho>>>>>>> .r2
"""
expected_disk_tree = svntest.tree.build_generic_tree(my_greek_tree)
# Create expected status tree for the update.
status_list = svntest.actions.get_virginal_status_list(wc_backup, '2')
for item in status_list:
if (item[0] == mu_path_backup) or (item[0] == rho_path_backup):
item[3]['status'] = 'C '
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# "Extra" files that we expect to result from the conflicts.
# These are expressed as list of regexps. What a cool system! :-)
extra_files = ['mu.*\.r1', 'mu.*\.r2', 'mu.*\.mine',
'rho.*\.r1', 'rho.*\.r2', 'rho.*\.mine',]
# Do the update and check the results in three ways.
# All "extra" files are passed to detect_conflict_files().
if svntest.actions.run_and_verify_update(wc_backup,
expected_output_tree,
expected_disk_tree,
expected_status_tree,
detect_conflict_files, # our singleton handler func
extra_files): # our handler will look for these
return 1
# verify that the extra_files list is now empty.
if len(extra_files) != 0:
# Because we want to be a well-behaved test, we silently return
# non-zero if the test fails. However, these two print statements
# would probably reveal the cause for the failure, if they were
# uncommented:
#
# print "Not all extra reject files have been accounted for:"
# print extra_files
return 1
# So now mu and rho are both in a "conflicted" state. Run 'svn
# resolve' on them.
stdout_lines, stderr_lines = svntest.main.run_svn(None, 'resolve',
mu_path_backup,
rho_path_backup)
if len (stderr_lines) > 0:
print "Resolve command printed the following to stderr:"
print stderr_lines
return 1
# See if they've changed back to plain old 'M' state.
for item in status_list:
if (item[0] == mu_path_backup) or (item[0] == rho_path_backup):
item[3]['status'] = 'M '
expected_status_tree = svntest.tree.build_generic_tree(status_list)
# There should be *no* extra backup files lying around the working
# copy after resolving the conflict; thus we're not passing a custom
# singleton handler.
return svntest.actions.run_and_verify_status (wc_backup,
expected_status_tree)
#----------------------------------------------------------------------
def basic_cleanup(sbox):
"basic cleanup command"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
# Lock some directories.
B_path = os.path.join(wc_dir, 'A', 'B')
G_path = os.path.join(wc_dir, 'A', 'D', 'G')
C_path = os.path.join(wc_dir, 'A', 'C')
svntest.actions.lock_admin_dir(B_path)
svntest.actions.lock_admin_dir(G_path)
svntest.actions.lock_admin_dir(C_path)
# Verify locked status.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '1')
for item in status_list:
if (item[0] == B_path) or (item[0] == G_path) or (item[0] == C_path):
item[3]['locked'] = 'L'
expected_output_tree = svntest.tree.build_generic_tree(status_list)
if svntest.actions.run_and_verify_status (wc_dir, expected_output_tree):
return 1
# Run cleanup (### todo: cleanup doesn't currently print anything)
stdout_lines, stderr_lines = svntest.main.run_svn(None, 'cleanup', wc_dir)
if len (stderr_lines) > 0:
print "Cleanup command printed the following to stderr:"
print stderr_lines
return 1
# Verify unlocked status.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '1')
expected_output_tree = svntest.tree.build_generic_tree(status_list)
return svntest.actions.run_and_verify_status (wc_dir, expected_output_tree)
#----------------------------------------------------------------------
def basic_revert(sbox):
"basic revert command"
if sbox.build():
return 1
wc_dir = sbox.wc_dir
# Modify some files.
beta_path = os.path.join(wc_dir, 'A', 'B', 'E', 'beta')
iota_path = os.path.join(wc_dir, 'iota')
rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
svntest.main.file_append(beta_path, "Added some text to 'beta'.")
svntest.main.file_append(iota_path, "Added some text to 'iota'.")
svntest.main.file_append(rho_path, "Added some text to 'rho'.")
# Verify modified status.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '1')
for item in status_list:
if (item[0] == beta_path) or (item[0] == iota_path) or (item[0] == rho_path):
item[3]['status'] = 'M '
expected_output_tree = svntest.tree.build_generic_tree(status_list)
if svntest.actions.run_and_verify_status (wc_dir, expected_output_tree):
return 1
# Run revert (### todo: revert doesn't currently print anything)
stdout_lines, stderr_lines = svntest.main.run_svn(None, 'revert', beta_path)
if len (stderr_lines) > 0:
print "Revert command printed the following to stderr:"
print stderr_lines
return 1
stdout_lines, stderr_lines = svntest.main.run_svn(None, 'revert', iota_path)
if len (stderr_lines) > 0:
print "Revert command printed the following to stderr:"
print stderr_lines
return 1
stdout_lines, stderr_lines = svntest.main.run_svn(None, 'revert', rho_path)
if len (stderr_lines) > 0:
print "Revert command printed the following to stderr:"
print stderr_lines
return 1
# Verify unmodified status.
status_list = svntest.actions.get_virginal_status_list(wc_dir, '1')
expected_output_tree = svntest.tree.build_generic_tree(status_list)
if svntest.actions.run_and_verify_status (wc_dir, expected_output_tree):
return 1
# Now, really make sure the contents are back to their original state.
fp = open(beta_path, 'r')
lines = fp.readlines()
if not ((len (lines) == 1) and (lines[0] == "This is the file 'beta'.")):
print "Revert failed to restore original text."
return 1
fp = open(iota_path, 'r')
lines = fp.readlines()
if not ((len (lines) == 1) and (lines[0] == "This is the file 'iota'.")):
print "Revert failed to restore original text."
return 1
fp = open(rho_path, 'r')
lines = fp.readlines()
if not ((len (lines) == 1) and (lines[0] == "This is the file 'rho'.")):
print "Revert failed to restore original text."
return 1
# Finally, check that reverted file is not readonly
os.remove(beta_path)
svntest.main.run_svn(None, 'revert', beta_path)
if not (open(beta_path, 'rw+')):
return 1
#----------------------------------------------------------------------
########################################################################
# Run the tests
# list all tests here, starting with None:
test_list = [ None,
basic_checkout,
basic_status,
basic_commit,
basic_update,
basic_merge,
basic_conflict,
basic_cleanup,
basic_revert,
### todo: more tests needed:
### test "svn rm http://some_url"
### not sure this file is the right place, though.
]
if __name__ == '__main__':
svntest.main.run_tests(test_list)
# NOTREACHED
### End of file.
# local variables:
# eval: (load-file "../../../../tools/dev/svn-dev.el")
# end: