#!/usr/bin/env python
#
#
# 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.
#
#
# Usage: svnmucc-test.py [build-dir-top [base-url]]
import sys
import os
import re
import shutil
# calculate the absolute directory in which this test script lives
this_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
# add the Subversion Python test suite libraries to the path, and import
sys.path.insert(0, '%s/../../../subversion/tests/cmdline' % (this_dir))
import svntest
# setup the global 'svntest.main.options' object so functions in the
# module don't freak out.
svntest.main._parse_options(arglist=[])
# calculate the top of the build tree
if len(sys.argv) > 1:
build_top = os.path.abspath(sys.argv[1])
else:
build_top = os.path.abspath('%s/../../../' % (this_dir))
# where lives svnmucc?
svnmucc_binary = \
os.path.abspath('%s/tools/client-side/svnmucc/svnmucc' % (build_top))
# override some svntest binary locations
svntest.main.svn_binary = \
os.path.abspath('%s/subversion/svn/svn' % (build_top))
svntest.main.svnlook_binary = \
os.path.abspath('%s/subversion/svnlook/svnlook' % (build_top))
svntest.main.svnadmin_binary = \
os.path.abspath('%s/subversion/svnadmin/svnadmin' % (build_top))
# where lives the test repository?
repos_path = \
os.path.abspath(('%s/tools/client-side/svnmucc/svnmucc-test-repos'
% (build_top)))
if (len(sys.argv) > 2):
repos_url = sys.argv[2] + '/svnmucc-test-repos'
else:
repos_url = 'file://' + repos_path
def die(msg):
"""Write MSG (formatted as a failure) to stderr, and exit with a
non-zero errorcode."""
sys.stderr.write("FAIL: " + msg + "\n")
sys.exit(1)
_svnmucc_re = re.compile('^(r[0-9]+) committed by svnmuccuser at (.*)$')
_log_re = re.compile('^ ([ADRM] /[^\(]+($| \(from .*:[0-9]+\)$))')
_err_re = re.compile('^svnmucc: (.*)$')
def xrun_svnmucc(expected_errors, *varargs):
"""Run svnmucc with the list of SVNMUCC_ARGS arguments. Verify that
its run results match the list of EXPECTED_ERRORS."""
# First, run svnmucc.
exit_code, outlines, errlines = \
svntest.main.run_command(svnmucc_binary, 1, 0,
'-U', repos_url,
'-u', 'svnmuccuser',
'-p', 'svnmuccpass',
'--config-dir', 'dummy',
*varargs)
errors = []
for line in errlines:
match = _err_re.match(line)
if match:
errors.append(line.rstrip('\n\r'))
if errors != expected_errors:
raise svntest.main.SVNUnmatchedError(str(errors))
def run_svnmucc(expected_path_changes, *varargs):
"""Run svnmucc with the list of SVNMUCC_ARGS arguments. Verify that
its run results in a new commit with 'svn log -rHEAD' changed paths
that match the list of EXPECTED_PATH_CHANGES."""
# First, run svnmucc.
exit_code, outlines, errlines = \
svntest.main.run_command(svnmucc_binary, 1, 0,
'-U', repos_url,
'-u', 'svnmuccuser',
'-p', 'svnmuccpass',
'--config-dir', 'dummy',
*varargs)
if errlines:
raise svntest.main.SVNCommitFailure(str(errlines))
if len(outlines) != 1 or not _svnmucc_re.match(outlines[0]):
raise svntest.main.SVNLineUnequal(str(outlines))
# Now, run 'svn log -vq -rHEAD'
changed_paths = []
exit_code, outlines, errlines = \
svntest.main.run_svn(None, 'log', '-vqrHEAD', repos_url)
if errlines:
raise svntest.Failure("Unable to verify commit with 'svn log': %s"
% (str(errlines)))
for line in outlines:
match = _log_re.match(line)
if match:
changed_paths.append(match.group(1).rstrip('\n\r'))
expected_path_changes.sort()
changed_paths.sort()
if changed_paths != expected_path_changes:
raise svntest.Failure("Logged path changes differ from expectations\n"
" expected: %s\n"
" actual: %s" % (str(expected_path_changes),
str(changed_paths)))
def main():
"""Test svnmucc."""
# revision 1
run_svnmucc(['A /foo'
], # ---------
'mkdir', 'foo')
# revision 2
run_svnmucc(['A /z.c',
], # ---------
'put', '/dev/null', 'z.c')
# revision 3
run_svnmucc(['A /foo/z.c (from /z.c:2)',
'A /foo/bar (from /foo:2)',
], # ---------
'cp', '2', 'z.c', 'foo/z.c',
'cp', '2', 'foo', 'foo/bar')
# revision 4
run_svnmucc(['A /zig (from /foo:3)',
'D /zig/bar',
'D /foo',
'A /zig/zag (from /foo:3)',
], # ---------
'cp', '3', 'foo', 'zig',
'rm', 'zig/bar',
'mv', 'foo', 'zig/zag')
# revision 5
run_svnmucc(['D /z.c',
'A /zig/zag/bar/y.c (from /z.c:4)',
'A /zig/zag/bar/x.c (from /z.c:2)',
], # ---------
'mv', 'z.c', 'zig/zag/bar/y.c',
'cp', '2', 'z.c', 'zig/zag/bar/x.c')
# revision 6
run_svnmucc(['D /zig/zag/bar/y.c',
'A /zig/zag/bar/y y.c (from /zig/zag/bar/y.c:5)',
'A /zig/zag/bar/y%20y.c (from /zig/zag/bar/y.c:5)',
], # ---------
'mv', 'zig/zag/bar/y.c', 'zig/zag/bar/y%20y.c',
'cp', 'HEAD', 'zig/zag/bar/y.c', 'zig/zag/bar/y%2520y.c')
# revision 7
run_svnmucc(['D /zig/zag/bar/y y.c',
'A /zig/zag/bar/z z1.c (from /zig/zag/bar/y y.c:6)',
'A /zig/zag/bar/z%20z.c (from /zig/zag/bar/y%20y.c:6)',
'A /zig/zag/bar/z z2.c (from /zig/zag/bar/y y.c:6)',
], #---------
'mv', 'zig/zag/bar/y%20y.c', 'zig/zag/bar/z z1.c',
'cp', 'HEAD', 'zig/zag/bar/y%2520y.c', 'zig/zag/bar/z%2520z.c',
'cp', 'HEAD', 'zig/zag/bar/y y.c', 'zig/zag/bar/z z2.c')
# revision 8
run_svnmucc(['D /zig/zag',
'A /zig/foo (from /zig/zag:7)',
'D /zig/foo/bar/z%20z.c',
'D /zig/foo/bar/z z2.c',
'R /zig/foo/bar/z z1.c (from /zig/zag/bar/x.c:5)',
], #---------
'mv', 'zig/zag', 'zig/foo',
'rm', 'zig/foo/bar/z z1.c',
'rm', 'zig/foo/bar/z%20z2.c',
'rm', 'zig/foo/bar/z%2520z.c',
'cp', '5', 'zig/zag/bar/x.c', 'zig/foo/bar/z%20z1.c')
# revision 9
run_svnmucc(['R /zig/foo/bar (from /zig/z.c:8)',
], #---------
'rm', 'zig/foo/bar',
'cp', '8', 'zig/z.c', 'zig/foo/bar')
# revision 10
run_svnmucc(['R /zig/foo/bar (from /zig/foo/bar:8)',
'D /zig/foo/bar/z z1.c',
], #---------
'rm', 'zig/foo/bar',
'cp', '8', 'zig/foo/bar', 'zig/foo/bar',
'rm', 'zig/foo/bar/z%20z1.c')
# revision 11
run_svnmucc(['R /zig/foo (from /zig/foo/bar:10)',
], #---------
'rm', 'zig/foo',
'cp', 'head', 'zig/foo/bar', 'zig/foo')
# revision 12
run_svnmucc(['D /zig',
'A /foo (from /foo:3)',
'A /foo/foo (from /foo:3)',
'A /foo/foo/foo (from /foo:3)',
'D /foo/foo/bar',
'R /foo/foo/foo/bar (from /foo:3)',
], #---------
'rm', 'zig',
'cp', '3', 'foo', 'foo',
'cp', '3', 'foo', 'foo/foo',
'cp', '3', 'foo', 'foo/foo/foo',
'rm', 'foo/foo/bar',
'rm', 'foo/foo/foo/bar',
'cp', '3', 'foo', 'foo/foo/foo/bar')
# revision 13
run_svnmucc(['A /boozle (from /foo:3)',
'A /boozle/buz',
'A /boozle/buz/nuz',
], #---------
'cp', '3', 'foo', 'boozle',
'mkdir', 'boozle/buz',
'mkdir', 'boozle/buz/nuz')
# revision 14
run_svnmucc(['A /boozle/buz/svnmucc-test.py',
'A /boozle/guz (from /boozle/buz:13)',
'A /boozle/guz/svnmucc-test.py',
], #---------
'put', '/dev/null', 'boozle/buz/svnmucc-test.py',
'cp', '13', 'boozle/buz', 'boozle/guz',
'put', '/dev/null', 'boozle/guz/svnmucc-test.py')
# revision 15
run_svnmucc(['M /boozle/buz/svnmucc-test.py',
'R /boozle/guz/svnmucc-test.py',
], #---------
'put', sys.argv[0], 'boozle/buz/svnmucc-test.py',
'rm', 'boozle/guz/svnmucc-test.py',
'put', sys.argv[0], 'boozle/guz/svnmucc-test.py')
# revision 16
run_svnmucc(['R /foo/bar (from /foo/foo:15)'], #---------
'rm', 'foo/bar',
'cp', '15', 'foo/foo', 'foo/bar',
'propset', 'testprop', 'true', 'foo/bar')
# revision 17
run_svnmucc(['M /foo/bar'], #---------
'propdel', 'testprop', 'foo/bar')
# revision 18
run_svnmucc(['M /foo/z.c',
'M /foo/foo',
], #---------
'propset', 'testprop', 'true', 'foo/z.c',
'propset', 'testprop', 'true', 'foo/foo')
# revision 19
run_svnmucc(['M /foo/z.c',
'M /foo/foo',
], #---------
'propsetf', 'testprop', sys.argv[0], 'foo/z.c',
'propsetf', 'testprop', sys.argv[0], 'foo/foo')
# Expected missing revision error
xrun_svnmucc(["svnmucc: E200004: 'a' is not a revision"
], #---------
'cp', 'a', 'b')
# Expected cannot be younger error
xrun_svnmucc(['svnmucc: E205000: Copy source revision cannot be younger ' +
'than base revision',
], #---------
'cp', '42', 'a', 'b')
# Expected already exists error
xrun_svnmucc(["svnmucc: E125002: 'foo' already exists",
], #---------
'cp', '17', 'a', 'foo')
# Expected copy_src already exists error
xrun_svnmucc(["svnmucc: E125002: 'a/bar' (from 'foo/bar:17') already exists",
], #---------
'cp', '17', 'foo', 'a',
'cp', '17', 'foo/foo', 'a/bar')
# Expected not found error
xrun_svnmucc(["svnmucc: E125002: 'a' not found",
], #---------
'cp', '17', 'a', 'b')
if __name__ == "__main__":
try:
# remove any previously existing repository, then create a new one
if os.path.exists(repos_path):
shutil.rmtree(repos_path)
exit_code, outlines, errlines = \
svntest.main.run_svnadmin('create', '--fs-type',
'fsfs', repos_path)
if errlines:
raise svntest.main.SVNRepositoryCreateFailure(repos_path)
fp = open(os.path.join(repos_path, 'conf', 'svnserve.conf'), 'w')
fp.write('[general]\nauth-access = write\npassword-db = passwd\n')
fp.close()
fp = open(os.path.join(repos_path, 'conf', 'passwd'), 'w')
fp.write('[users]\nsvnmuccuser = svnmuccpass\n')
fp.close()
main()
except SystemExit, e:
raise
except svntest.main.SVNCommitFailure, e:
die("Error committing via svnmucc: %s" % (str(e)))
except svntest.main.SVNLineUnequal, e:
die("Unexpected svnmucc output line: %s" % (str(e)))
except svntest.main.SVNRepositoryCreateFailure, e:
die("Error creating test repository: %s" % (str(e)))
except svntest.Failure, e:
die("Test failed: %s" % (str(e)))
except Exception, e:
die("Something bad happened: %s" % (str(e)))
# cleanup the repository on a successful run
try:
if os.path.exists(repos_path):
shutil.rmtree(repos_path)
except:
pass
print("SUCCESS!")