If someone with the requisite linux skills/hardware could tweak makefile.in so it can take advantage of the --milestone-filter option, well that would be fabulous.
Paul On Thu, Feb 17, 2011 at 5:09 PM, <pbu...@apache.org> wrote: > 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) > > >