Author: rinrab
Date: Wed May 28 19:29:41 2025
New Revision: 1925914
URL: http://svn.apache.org/viewvc?rev=1925914&view=rev
Log:
On the 'utf8-cmdline-prototype' branch: revert reversion.
Modified:
subversion/branches/utf8-cmdline-prototype/Makefile.in
subversion/branches/utf8-cmdline-prototype/build/run_tests.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/blame_tests.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/log_tests.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
Modified: subversion/branches/utf8-cmdline-prototype/Makefile.in
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/Makefile.in?rev=1925914&r1=1925913&r2=1925914&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/Makefile.in (original)
+++ subversion/branches/utf8-cmdline-prototype/Makefile.in Wed May 28 19:29:41
2025
@@ -645,7 +645,7 @@ check: bin @TRANSFORM_LIBTOOL_SCRIPTS@ $
$$flags \
'$(abs_srcdir)' '$(abs_builddir)' $(TESTS); \
else \
- echo "make check: Python 2.7 or greater is required,"; \
+ echo "make check: Python 3.6 or greater is required,"; \
echo " but was not detected during configure"; \
exit 1; \
fi;
Modified: subversion/branches/utf8-cmdline-prototype/build/run_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/build/run_tests.py?rev=1925914&r1=1925913&r2=1925914&view=diff
==============================================================================
--- subversion/branches/utf8-cmdline-prototype/build/run_tests.py (original)
+++ subversion/branches/utf8-cmdline-prototype/build/run_tests.py Wed May 28
19:29:41 2025
@@ -326,8 +326,16 @@ class TestHarness:
global svntest
svntest = importlib.import_module('svntest')
+ extra_packages = svntest.main.ensure_dependencies()
svntest.main.parse_options(cmdline, optparse.SUPPRESS_USAGE)
svntest.testcase.TextColors.disable()
+
+ # We have to update PYTHONPATH, otherwise the whole setting up of a
+ # virtualenv and installing dependencies will happen for every test case.
+ python_path = os.environ.get("PYTHONPATH")
+ python_path = (extra_packages if not python_path
+ else "%s:%s" % (extra_packages, python_path))
+ os.environ["PYTHONPATH"] = python_path
finally:
os.chdir(old_cwd)
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/blame_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/blame_tests.py?rev=1925914&r1=1925913&r2=1925914&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/blame_tests.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/blame_tests.py
Wed May 28 19:29:41 2025
@@ -216,7 +216,7 @@ def blame_in_xml(sbox):
None)
# Retrieve last changed date from svn info
- exit_code, output, error = svntest.actions.run_and_verify_svn(
+ exit_code, output, error = svntest.actions.run_and_verify_svn_xml(
None, [],
'log', file_path, '--xml', '-r1:2')
@@ -256,7 +256,7 @@ def blame_in_xml(sbox):
'</target>\n',
'</blame>\n']
- exit_code, output, error = svntest.actions.run_and_verify_svn(
+ exit_code, output, error = svntest.actions.run_and_verify_svn_xml(
None, [],
'blame', file_path, '--xml')
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/log_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/log_tests.py?rev=1925914&r1=1925913&r2=1925914&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/log_tests.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/log_tests.py
Wed May 28 19:29:41 2025
@@ -1008,7 +1008,7 @@ def log_xml_empty_date(sbox):
date_re = re.compile('<date')
# Ensure that we get a date before we delete the property.
- exit_code, output, errput = svntest.actions.run_and_verify_svn(
+ exit_code, output, errput = svntest.actions.run_and_verify_svn_xml(
None, [], 'log', '--xml', '-r1', sbox.wc_dir)
matched = 0
@@ -1023,7 +1023,7 @@ def log_xml_empty_date(sbox):
'pdel', '--revprop', '-r1', 'svn:date',
sbox.wc_dir)
- exit_code, output, errput = svntest.actions.run_and_verify_svn(
+ exit_code, output, errput = svntest.actions.run_and_verify_svn_xml(
None, [], 'log', '--xml', '-r1', sbox.wc_dir)
for line in output:
@@ -2798,22 +2798,11 @@ def log_with_merge_history_and_search(sb
sbox.simple_commit(message='r4: merge')
sbox.simple_update()
- # Helper function
- def count(haystack, needle):
- """Return the number of times the string NEEDLE occurs in the string
- HAYSTACK."""
- return len(haystack.split(needle)) - 1
-
# Check the output is valid
- # ### Since the test is currently XFail, we only smoke test the output.
- # ### When fixing this test to PASS, extend this validation.
_, output, _ = svntest.main.run_svn(None, 'log', '--xml', '-g',
'--search', "this will have no matches",
sbox.ospath('A2'))
-
- output = '\n'.join(output)
- if count(output, "<logentry") != count(output, "</logentry"):
- raise svntest.Failure("Apparently invalid XML in " + repr(output))
+ svntest.verify.validate_xml_schema('log', output)
@XFail(svntest.main.is_ra_type_file)
@Issue(4856)
@@ -2852,21 +2841,10 @@ def log_xml_with_merge_history(sbox):
sbox.simple_commit(message='r9: merge A3=>A4')
sbox.simple_update()
- # Helper function
- def count(haystack, needle):
- """Return the number of times the string NEEDLE occurs in the string
- HAYSTACK."""
- return len(haystack.split(needle)) - 1
-
# Check the output is valid
- # ### Since the test is currently XFail, we only smoke test the output.
- # ### When fixing this test to PASS, extend this validation.
_, output, _ = svntest.main.run_svn(None, 'log', '--xml', '-g', '-r', '8:9',
sbox.ospath('A4'))
-
- output = '\n'.join(output)
- if count(output, "<logentry") != count(output, "</logentry"):
- raise svntest.Failure("Apparently invalid XML in " + repr(output))
+ svntest.verify.validate_xml_schema('log', output)
########################################################################
# Run the tests
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py?rev=1925914&r1=1925913&r2=1925914&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/actions.py
Wed May 28 19:29:41 2025
@@ -325,6 +325,16 @@ def run_and_verify_svnversion2(wc_dir, t
verify.verify_exit_code("Unexpected return code", exit_code, expected_exit)
return exit_code, out, err
+def run_and_verify_svn_xml(expected_stdout, expected_stderr,
+ command, *varargs):
+ """Like run_and_verify_svn but expects the output to be XML
+ and validates it against the schema for the given command"""
+ exit_code, out, err = run_and_verify_svn(expected_stdout, expected_stderr,
+ command, *varargs)
+ if exit_code == 0:
+ verify.validate_xml_schema(command, out)
+ return exit_code, out, err
+
def run_and_verify_svn(expected_stdout, expected_stderr, *varargs):
"""like run_and_verify_svn2, but the expected exit code is assumed to
be 0 if no output is expected on stderr, and 1 otherwise."""
@@ -339,6 +349,16 @@ def run_and_verify_svn(expected_stdout,
return run_and_verify_svn2(expected_stdout, expected_stderr,
expected_exit, *varargs)
+def run_and_verify_svn_xml2(expected_stdout, expected_stderr,
+ expected_exit, command, *varargs):
+ """Like run_and_verify_svn2 but expects the output to be XML
+ and validates it against the schema for the given command"""
+ exit_code, out, err = run_and_verify_svn2(expected_stdout, expected_stderr,
+ expected_exit, command, *varargs)
+ if exit_code == 0:
+ verify.validate_xml_schema(command, out)
+ return exit_code, out, err
+
def run_and_verify_svn2(expected_stdout, expected_stderr,
expected_exit, *varargs):
"""Invoke main.run_svn() with *VARARGS. Return exit code as int; stdout,
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py?rev=1925914&r1=1925913&r2=1925914&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/main.py
Wed May 28 19:29:41 2025
@@ -39,6 +39,7 @@ import hashlib
import zipfile
import codecs
import queue
+import venv
from urllib.parse import quote as urllib_parse_quote
from urllib.parse import unquote as urllib_parse_unquote
@@ -119,11 +120,13 @@ class SVNRepositoryCreateFailure(Failure
if sys.platform == 'win32':
windows = True
file_scheme_prefix = 'file:///'
+ venv_bin = 'Scripts'
_exe = '.exe'
_bat = '.bat'
os.environ['SVN_DBG_STACKTRACES_TO_STDERR'] = 'y'
else:
windows = False
+ venv_bin = 'bin'
file_scheme_prefix = 'file://'
_exe = ''
_bat = ''
@@ -170,7 +173,7 @@ S_ALL_RWX = S_ALL_READ | S_ALL_WRITE | S
def P(relpath,
head=os.path.dirname(os.path.dirname(os.path.abspath('.')))
):
- if sys.platform=='win32':
+ if windows:
return os.path.join(head, relpath + '.exe')
else:
return os.path.join(head, relpath)
@@ -217,6 +220,14 @@ options = None
# this dir, so there's one point at which to mount, e.g., a ramdisk.
work_dir = "svn-test-work"
+# Directory for the Python virtual environment where we install
+# external dependencies of the test environment
+venv_dir = os.path.join(work_dir, "__venv__")
+
+# List of dependencies
+SVN_TESTS_REQUIRE = ["lxml", "rnc2rng"]
+dependencies_ensured = False
+
# Constant for the merge info property.
SVN_PROP_MERGEINFO = "svn:mergeinfo"
@@ -859,7 +870,7 @@ def run_svnadmin(*varargs):
exit_code, stdout_lines, stderr_lines = \
run_command(svnadmin_binary, 1, use_binary, *varargs)
- if use_binary and sys.platform == 'win32':
+ if use_binary and windows:
# Callers don't expect binary output on stderr
stderr_lines = [x.replace('\r', '') for x in stderr_lines]
@@ -2406,8 +2417,50 @@ def run_tests(test_list, serial_only = F
appropriate exit code.
"""
+ ensure_dependencies()
sys.exit(execute_tests(test_list, serial_only))
+def ensure_dependencies():
+ """Install the dependencies we need for running the tests.
+
+ NOTE: this function des not handle the case where the Python
+ version has changed. In theory, we could automagically
+ upgrade the venv in that case. In practice, we won't.
+ """
+
+ global dependencies_ensured
+ if dependencies_ensured:
+ return
+
+ package_path = os.path.join(venv_dir, "lib",
+ "python%d.%d" % sys.version_info[:2],
+ "site-packages")
+ package_path = os.path.abspath(package_path)
+ if package_path in sys.path:
+ dependencies_ensured = True
+ return
+
+ try:
+ # Create the virtual environment
+ if not os.path.isdir(venv_dir):
+ if os.path.exists(venv_dir):
+ safe_rmtree(venv_dir)
+ venv.create(venv_dir, with_pip=True)
+
+ # Install any (new) dependencies
+ pip = os.path.join(venv_dir, venv_bin, "pip"+_exe)
+ pip_options = ("--disable-pip-version-check", "--require-virtualenv")
+ subprocess.run([pip, *pip_options, "install", *SVN_TESTS_REQUIRE],
+ check=True)
+
+ sys.path.append(package_path)
+ dependencies_ensured = True
+ return package_path
+ except Exception as ex:
+ print("WARNING: Could not install test dependencies,"
+ " some tests will be skipped", file=sys.stderr)
+ print(ex, file=sys.stderr)
+
def get_issue_details(issue_numbers):
"""For each issue number in ISSUE_NUMBERS query the issue
tracker and determine what the target milestone is and
Modified:
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
URL:
http://svn.apache.org/viewvc/subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py?rev=1925914&r1=1925913&r2=1925914&view=diff
==============================================================================
---
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
(original)
+++
subversion/branches/utf8-cmdline-prototype/subversion/tests/cmdline/svntest/verify.py
Wed May 28 19:29:41 2025
@@ -24,11 +24,13 @@
# under the License.
######################################################################
-import re, sys
+import os, re
from difflib import unified_diff, ndiff
import pprint
import logging
import itertools
+from io import BytesIO
+from typing import Iterable
import svntest
@@ -77,6 +79,9 @@ class SVNDumpParseError(svntest.Failure)
"""Exception raised if parsing a dump file fails"""
pass
+class SVNXMLSchemaValidationError(SVNUnexpectedOutput):
+ """Exception raised if XML output failed validation against its schema"""
+ pass
######################################################################
# Comparison of expected vs. actual output
@@ -1039,3 +1044,26 @@ def make_diff_prop_modified(pname, pval1
"## -1 +1 ##\n",
] + make_diff_prop_val("-", pval1) + make_diff_prop_val("+", pval2)
+
+__schema_dir = os.path.join(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.abspath(__file__))))),
+ "svn", "schema")
+def validate_xml_schema(name: str, lines: Iterable[str]) -> None:
+ schema_name = name + ".rnc"
+ try:
+ # Imported in this scope because sys.path may not have been updated yet.
+ from lxml import etree #type:ignore
+ schema_file = os.path.join(__schema_dir, schema_name)
+ schema = etree.RelaxNG(file=schema_file)
+ source = ''.join(lines)
+ document = etree.parse(BytesIO(source.encode("utf-8")))
+ if not schema.validate(document):
+ raise SVNXMLSchemaValidationError("schema %s" % schema_name)
+ except Exception:
+ print("ERROR: XML output does not conform to schema", schema_name)
+ print(source)
+ raise