Author: pburba
Date: Thu Feb 17 22:09:02 2011
New Revision: 1071809
URL: http://svn.apache.org/viewvc?rev=1071809&view=rev
Log:
Add an option (--milestone-filter=REGEX) to the Python tests so we can list a
subset of the tests based on their associated issues' target milestone.
This option is currently only available to win-tests.py and
subversion/tests/cmdline/svntest/main.py. So it isn't quite as useful
on non-Windows platforms just yet.
Now we can easily answer questions like, "What xfailing merge tests need to
be fixed before we can release 1.7?"
C:\SVN\src-trunk>win-tests.py --list --milestone-filter="(1.7.*)|(---)"
--mode-filter xfail --log-to-stdout --test merge
Listing Debug configuration on local repository.
LISTING: merge_tests.py
Test # Mode Test Description
------ ----- ----------------
64 XFAIL merge target with non inheritable mergeinfo
[#2970(blue-sky),#3642(1.7.0)]
75 XFAIL merge added subtree [#1962(1.7-consider)]
* build/run_tests.py
(TestHarness.__init__): Add mode_filter argument.
(TestHarness._run_c_test): Issue warning that --milestone-filter doesn't
work when listing C tests.
(TestHarness._run_py_test): Accept --milestone-filter option.
* subversion/tests/cmdline/svntest/main.py
(global): Import xml and urllib.
(TestSpawningThread.run_one): Support --milestone-filter option.
(TestRunner.list): Add optional argument mapping issues to target
milestones.
(TestRunner.get_issues): New.
(_create_parser): Handle --milestone-filter.
(get_target_milestones_for_issues): New.
(execute_tests): Handle --milestone-filter.
* win-tests.py
(_usage_exit): Add --milestone-filter to usage text.
(milestone_filter): New global variable.
(global): Accept --milestone-filter as a valid option, pass it to
run_tests.TestHarness().
Modified:
subversion/trunk/build/run_tests.py
subversion/trunk/subversion/tests/cmdline/svntest/main.py
subversion/trunk/win-tests.py
Modified: subversion/trunk/build/run_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/build/run_tests.py?rev=1071809&r1=1071808&r2=1071809&view=diff
==============================================================================
--- subversion/trunk/build/run_tests.py (original)
+++ subversion/trunk/build/run_tests.py Thu Feb 17 22:09:02 2011
@@ -79,7 +79,8 @@ class TestHarness:
server_minor_version=None, verbose=None,
cleanup=None, enable_sasl=None, parallel=None, config_file=None,
fsfs_sharding=None, fsfs_packing=None,
- list_tests=None, svn_bin=None, mode_filter=None):
+ list_tests=None, svn_bin=None, mode_filter=None,
+ milestone_filter=None):
'''Construct a TestHarness instance.
ABS_SRCDIR and ABS_BUILDDIR are the source and build directories.
@@ -91,8 +92,12 @@ class TestHarness:
HTTP_LIBRARY is the HTTP library for DAV-based communications.
SERVER_MINOR_VERSION is the minor version of the server being tested.
SVN_BIN is the path where the svn binaries are installed.
- mode_filter restricts the TestHarness to tests with the expected mode
- XFail, Skip, Pass, or All tests (default).
+ MODE_FILTER restricts the TestHarness to tests with the expected mode
+ XFail, Skip, Pass, or All tests (default). MILESTONE_FILTER is a
+ string representation of a valid regular expression pattern; when used
+ in conjunction with LIST_TESTS, the only tests that are listed are
+ those with an associated issue in the tracker which has a target
+ milestone that matches the regex.
'''
self.srcdir = abs_srcdir
self.builddir = abs_builddir
@@ -114,6 +119,7 @@ class TestHarness:
if config_file is not None:
self.config_file = os.path.abspath(config_file)
self.list_tests = list_tests
+ self.milestone_filter = milestone_filter
self.svn_bin = svn_bin
self.mode_filter = mode_filter
self.log = None
@@ -280,6 +286,8 @@ class TestHarness:
if not self.list_tests:
sys.stdout.write('.' * dot_count)
sys.stdout.flush()
+ elif self.milestone_filter:
+ print 'WARNING: --milestone-filter option does not currently work with C
tests'
if os.access(progbase, os.X_OK):
progname = './' + progbase
@@ -349,6 +357,8 @@ class TestHarness:
svntest.main.options.server_minor_version = self.server_minor_version
if self.list_tests is not None:
svntest.main.options.list_tests = True
+ if self.milestone_filter is not None:
+ svntest.main.options.milestone_filter = self.milestone_filter
if self.svn_bin is not None:
svntest.main.options.svn_bin = self.svn_bin
if self.fsfs_sharding is not None:
Modified: subversion/trunk/subversion/tests/cmdline/svntest/main.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/main.py?rev=1071809&r1=1071808&r2=1071809&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/main.py Thu Feb 17
22:09:02 2011
@@ -34,6 +34,8 @@ import time # for time()
import traceback # for print_exc()
import threading
import optparse # for argument parsing
+import xml
+import urllib
try:
# Python >=3.0
@@ -1132,6 +1134,8 @@ class TestSpawningThread(threading.Threa
args.append('--server-minor-version=' +
str(options.server_minor_version))
if options.mode_filter:
args.append('--mode-filter=' + options.mode_filter)
+ if options.milestone_filter:
+ args.append('--milestone-filter=' + options.milestone_filter)
result, stdout_lines, stderr_lines = spawn_process(command, 0, 0, None,
*args)
@@ -1152,26 +1156,61 @@ class TestRunner:
self.pred = svntest.testcase.create_test_case(func)
self.index = index
- def list(self):
+ def list(self, milestones_dict=None):
+ """Print test doc strings. MILESTONES_DICT is an optional mapping
+ of issue numbers to target milestones."""
if options.mode_filter.upper() == 'ALL' \
or options.mode_filter.upper() == self.pred.list_mode().upper() \
or (options.mode_filter.upper() == 'PASS' \
and self.pred.list_mode() == ''):
+ issues = []
tail = ''
if self.pred.issues:
- tail += " [%s]" % ','.join(['#%d' % i for i in self.pred.issues])
- if options.verbose and self.pred.inprogress:
- tail += " [[%s]]" % self.pred.inprogress
- else:
- print(" %3d %-5s %s%s" % (self.index,
- self.pred.list_mode(),
- self.pred.description,
- tail))
+ if not options.milestone_filter or milestones_dict is None:
+ issues = self.pred.issues
+ else: # Limit listing by requested target milestone(s).
+ filter_issues = []
+ matches_filter = False
+
+ # Get the milestones for all the issues associated with this test.
+ # If any one of them matches the MILESTONE_FILTER then we'll print
+ # them all.
+ for issue in self.pred.issues:
+ # A safe starting assumption.
+ milestone = 'unknown'
+ if milestones_dict:
+ if milestones_dict.has_key(str(issue)):
+ milestone = milestones_dict[str(issue)]
+
+ filter_issues.append(str(issue) + '(' + milestone + ')')
+ pattern = re.compile(options.milestone_filter)
+ if pattern.match(milestone):
+ matches_filter = True
+
+ # Did at least one of the associated issues meet our filter?
+ if matches_filter:
+ issues = filter_issues
+
+ tail += " [%s]" % ','.join(['#%s' % str(i) for i in issues])
+
+ # If there is no filter or this test made if through
+ # the filter then print it!
+ if options.milestone_filter is None or len(issues):
+ if options.verbose and self.pred.inprogress:
+ tail += " [[%s]]" % self.pred.inprogress
+ else:
+ print(" %3d %-5s %s%s" % (self.index,
+ self.pred.list_mode(),
+ self.pred.description,
+ tail))
sys.stdout.flush()
def get_mode(self):
return self.pred.list_mode()
+ def get_issues(self):
+ return self.pred.issues
+
def get_function_name(self):
return self.pred.get_function_name()
@@ -1376,6 +1415,8 @@ def _create_parser():
parser = optparse.OptionParser(usage=usage)
parser.add_option('-l', '--list', action='store_true', dest='list_tests',
help='Print test doc strings instead of running them')
+ parser.add_option('--milestone-filter', action='store',
dest='milestone_filter',
+ help='Limit --list to those with target milestone
specified')
parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
help='Print binary command-lines (not with --quiet)')
parser.add_option('-q', '--quiet', action='store_true',
@@ -1470,6 +1511,47 @@ def run_tests(test_list, serial_only = F
sys.exit(execute_tests(test_list, serial_only))
+def get_target_milestones_for_issues(issue_numbers):
+ xml_url = "http://subversion.tigris.org/issues/xml.cgi?id="
+ issue_dict = {}
+
+ if isinstance(issue_numbers, int):
+ issue_numbers = [str(issue_numbers)]
+ elif isinstance(issue_numbers, str):
+ issue_numbers = [issue_numbers]
+
+ if issue_numbers is None or len(issue_numbers) == 0:
+ return issue_dict
+
+ for num in issue_numbers:
+ xml_url += str(num) + ','
+ issue_dict[str(num)] = 'unknown'
+
+ try:
+ # Parse the xml for ISSUE_NO from the issue tracker into a Document.
+ issue_xml_f = urllib.urlopen(xml_url)
+ except:
+ print "WARNING: Unable to contact issue tracker; " \
+ "milestones defaulting to 'unknown'."
+ return issue_dict
+
+ try:
+ xmldoc = xml.dom.minidom.parse(issue_xml_f)
+ issue_xml_f.close()
+
+ # Get the target milestone for each issue.
+ issue_element = xmldoc.getElementsByTagName('issue')
+ for i in issue_element:
+ issue_id_element = i.getElementsByTagName('issue_id')
+ issue_id = issue_id_element[0].childNodes[0].nodeValue
+ milestone_element = i.getElementsByTagName('target_milestone')
+ milestone = milestone_element[0].childNodes[0].nodeValue
+ issue_dict[issue_id] = milestone
+ except:
+ print "ERROR: Unable to parse target milestones from issue tracker"
+ raise
+
+ return issue_dict
# Main func. This is the "entry point" that all the test scripts call
# to run their list of tests.
@@ -1586,6 +1668,23 @@ def execute_tests(test_list, serial_only
testnums = list(range(1, len(test_list)))
if options.list_tests:
+
+ # If we want to list the target milestones, then get all the issues
+ # associated with all the individual tests.
+ milestones_dict = None
+ if options.milestone_filter:
+ issues_dict = {}
+ for testnum in testnums:
+ issues = TestRunner(test_list[testnum], testnum).get_issues()
+ test_mode = TestRunner(test_list[testnum], testnum).get_mode().upper()
+ if issues:
+ for issue in issues:
+ if (options.mode_filter.upper() == 'ALL' or
+ options.mode_filter.upper() == test_mode or
+ (options.mode_filter.upper() == 'PASS' and test_mode == '')):
+ issues_dict[issue]=issue
+ milestones_dict = get_target_milestones_for_issues(issues_dict.keys())
+
header = "Test # Mode Test Description\n" \
"------ ----- ----------------"
printed_header = False
@@ -1597,7 +1696,7 @@ def execute_tests(test_list, serial_only
if not printed_header:
print header
printed_header = True
- TestRunner(test_list[testnum], testnum).list()
+ TestRunner(test_list[testnum], testnum).list(milestones_dict)
# We are simply listing the tests so always exit with success.
return 0
Modified: subversion/trunk/win-tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/win-tests.py?rev=1071809&r1=1071808&r2=1071809&view=diff
==============================================================================
--- subversion/trunk/win-tests.py (original)
+++ subversion/trunk/win-tests.py Thu Feb 17 22:09:02 2011
@@ -79,6 +79,10 @@ def _usage_exit():
print(" --http-library : dav library to use, neon (default) or
serf")
print(" --javahl : Run the javahl tests instead of the normal
tests")
print(" --list : print test doc strings only")
+ print(" --milestone-filter=RE : RE is a regular expression pattern that
(when")
+ print(" used with --list) limits the tests listed
to")
+ print(" those with an associated issue in the
tracker")
+ print(" which has a target milestone that matches
RE.")
print(" --mode-filter=TYPE : limit tests to expected TYPE = XFAIL,
SKIP, PASS,")
print(" or 'ALL' (default)")
print(" --enable-sasl : enable Cyrus SASL authentication for")
@@ -123,7 +127,7 @@ opts, args = my_getopt(sys.argv[1:], 'hr
'fsfs-packing', 'fsfs-sharding=', 'javahl',
'list', 'enable-sasl', 'bin=', 'parallel',
'config-file=', 'server-minor-version=',
- 'log-to-stdout', 'mode-filter='])
+ 'log-to-stdout', 'mode-filter=', 'milestone-filter='])
if len(args) > 1:
print('Warning: non-option arguments after the first one will be ignored')
@@ -140,6 +144,7 @@ httpd_port = None
httpd_service = None
http_library = 'neon'
list_tests = None
+milestone_filter = None
test_javahl = None
enable_sasl = None
svn_bin = None
@@ -195,6 +200,8 @@ for opt, val in opts:
test_javahl = 1
elif opt == '--list':
list_tests = 1
+ elif opt == '--milestone-filter':
+ milestone_filter = val
elif opt == '--mode-filter':
mode_filter = val
elif opt == '--enable-sasl':
@@ -688,7 +695,8 @@ if not test_javahl:
server_minor_version, not quiet,
cleanup, enable_sasl, parallel, config_file,
fsfs_sharding, fsfs_packing,
- list_tests, svn_bin, mode_filter)
+ list_tests, svn_bin, mode_filter,
+ milestone_filter)
old_cwd = os.getcwd()
try:
os.chdir(abs_builddir)