| #!/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!") |