You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2011/02/17 23:09:03 UTC

svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

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)



Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Stefan Sperling <st...@elego.de> writes:

> On Mon, Feb 28, 2011 at 10:03:45AM +0530, Noorul Islam K M wrote:
>
>> >> Pinging to get some attention to this thread.
>> >
>> > Hi Noorul,
>> >
>> > I can't evaluate this patch since I don't have a linux box.
>> >
>
>> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
>> TESTS=subversion/tests/cmdline/merge_tests.py
>> 
>>   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)]
>> 
>> Thanks and Regards
>> Noorul
>
> Committed in r1132622, thanks! (and sorry this took so long...)

No problems. Thank you!

Thanks and Regards
Noorul

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Stefan Sperling <st...@elego.de> writes:

> On Mon, Feb 28, 2011 at 10:03:45AM +0530, Noorul Islam K M wrote:
>
>> >> Pinging to get some attention to this thread.
>> >
>> > Hi Noorul,
>> >
>> > I can't evaluate this patch since I don't have a linux box.
>> >
>
>> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
>> TESTS=subversion/tests/cmdline/merge_tests.py
>> 
>>   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)]
>> 
>> Thanks and Regards
>> Noorul
>
> Committed in r1132622, thanks! (and sorry this took so long...)

No problems. Thank you!

Thanks and Regards
Noorul

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Stefan Sperling <st...@elego.de>.
On Mon, Feb 28, 2011 at 10:03:45AM +0530, Noorul Islam K M wrote:
> >> Pinging to get some attention to this thread.
> >
> > Hi Noorul,
> >
> > I can't evaluate this patch since I don't have a linux box.
> >

> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
> TESTS=subversion/tests/cmdline/merge_tests.py
> 
>   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)]
> 
> Thanks and Regards
> Noorul

Committed in r1132622, thanks! (and sorry this took so long...)

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Stefan Sperling <st...@elego.de>.
On Mon, Feb 28, 2011 at 10:03:45AM +0530, Noorul Islam K M wrote:
> >> Pinging to get some attention to this thread.
> >
> > Hi Noorul,
> >
> > I can't evaluate this patch since I don't have a linux box.
> >

> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
> TESTS=subversion/tests/cmdline/merge_tests.py
> 
>   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)]
> 
> Thanks and Regards
> Noorul

Committed in r1132622, thanks! (and sorry this took so long...)

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Paul Burba <pt...@gmail.com> writes:

> On Wed, Feb 23, 2011 at 9:59 PM, Noorul Islam K M <no...@collab.net> wrote:
>> Noorul Islam K M <no...@collab.net> writes:
>>
>>> Paul Burba <pt...@gmail.com> writes:
>>>
>>>> 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,  <pb...@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)
>>>>>
>>>>>
>>>>>
>>>
>>> Please find attached patch for Makefile.in to make the same work on
>>> linux. I am not that proficient with make files. But still I think I did
>>> it right.
>>>
>>> Log
>>> [[[
>>>
>>> Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
>>> MODE_FILTER options.
>>>
>>> Now we can easily answer questions like, "What xfailing merge tests need to
>>> be fixed before we can release 1.7?"
>>>
>>> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail
>>> TESTS=subversion/tests/cmdline/merge_tests.py
>>>
>>>   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)]
>>>
>>> * Makefile.in
>>>   (check): Pass --list, --milestone-filter, --mode-filter and
>>>     --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.
>>>
>>> * build/run_tests.py
>>>   (__doc__): Add --list, --milestone-filter and --mode-filter options to
>>>     usage doc.
>>>
>>>   (main): Accept --list, --milestone-filter and --mode-filter as a valid
>>>    option, pass it to TestHarness()
>>>
>>> Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
>>> ]]]
>>>
>>> Index: Makefile.in
>>> ===================================================================
>>> --- Makefile.in       (revision 1072234)
>>> +++ Makefile.in       (working copy)
>>> @@ -473,6 +473,10 @@
>>>         if test "$(LOG_TO_STDOUT)" != ""; then                             \
>>>           flags="--log-to-stdout $$flags";                                 \
>>>         fi;                                                                \
>>> +       if test "$(MILESTONE_FILTER)" != ""; then                          \
>>> +         flags="--list --milestone-filter=$(MILESTONE_FILTER)             \
>>> +                --mode-filter=$(MODE_FILTER) --log-to-stdout $$flags";    \
>>> +       fi;                                                                \
>>>         $(PYTHON) $(top_srcdir)/build/run_tests.py                         \
>>>                   --config-file $(top_srcdir)/subversion/tests/tests.conf  \
>>>                   $$flags                                                  \
>>> Index: build/run_tests.py
>>> ===================================================================
>>> --- build/run_tests.py        (revision 1072234)
>>> +++ build/run_tests.py        (working copy)
>>> @@ -27,6 +27,7 @@
>>>              [--verbose] [--log-to-stdout] [--cleanup] [--parallel]
>>>              [--url=<base-url>] [--http-library=<http-library>] [--enable-sasl]
>>>              [--fs-type=<fs-type>] [--fsfs-packing] [--fsfs-sharding=<n>]
>>> +            [--list] [--milestone-filter=<regex>] [--mode-filter=<type>]
>>>              [--server-minor-version=<version>]
>>>              [--config-file=<file>]
>>>              <abs_srcdir> <abs_builddir>
>>> @@ -522,7 +523,7 @@
>>>                              'http-library=', 'server-minor-version=',
>>>                              'fsfs-packing', 'fsfs-sharding=',
>>>                              'enable-sasl', 'parallel', 'config-file=',
>>> -                            'log-to-stdout'])
>>> +                            'log-to-stdout', 'list', 'milestone-filter=', 'mode-filter='])
>>>    except getopt.GetoptError:
>>>      args = []
>>>
>>> @@ -532,9 +533,9 @@
>>>
>>>    base_url, fs_type, verbose, cleanup, enable_sasl, http_library, \
>>>      server_minor_version, fsfs_sharding, fsfs_packing, parallel, \
>>> -    config_file, log_to_stdout = \
>>> +    config_file, log_to_stdout, list_tests, mode_filter, milestone_filter= \
>>>              None, None, None, None, None, None, None, None, None, None, None, \
>>> -            None
>>> +            None, None, None, None
>>>    for opt, val in opts:
>>>      if opt in ['-u', '--url']:
>>>        base_url = val
>>> @@ -560,6 +561,12 @@
>>>        config_file = val
>>>      elif opt in ['--log-to-stdout']:
>>>        log_to_stdout = 1
>>> +    elif opt in ['--list']:
>>> +      list_tests = 1
>>> +    elif opt in ['--milestone-filter']:
>>> +      milestone_filter = val
>>> +    elif opt in ['--mode-filter']:
>>> +      mode_filter = val
>>>      else:
>>>        raise getopt.GetoptError
>>>
>>> @@ -573,7 +580,8 @@
>>>    th = TestHarness(args[0], args[1], logfile, faillogfile,
>>>                     base_url, fs_type, http_library, server_minor_version,
>>>                     verbose, cleanup, enable_sasl, parallel, config_file,
>>> -                   fsfs_sharding, fsfs_packing)
>>> +                   fsfs_sharding, fsfs_packing, list_tests,
>>> +                   mode_filter=mode_filter, milestone_filter=milestone_filter)
>>>
>>>    failed = th.run(args[2:])
>>>    if failed:
>>
>> Pinging to get some attention to this thread.
>
> Hi Noorul,
>
> I can't evaluate this patch since I don't have a linux box.
>
> This may be a silly question, but have you tried it out?  Can you
> generate a listing of xfailing tests that have associated issues with
> the 1.7 milestone for example?
>

I mentioned this in the commit log message. Here is how I ran it. 

I mentioned the output in commit log. I once again pasting it here.

$ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
TESTS=subversion/tests/cmdline/merge_tests.py

  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)]

Thanks and Regards
Noorul

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Paul Burba <pt...@gmail.com> writes:

> On Wed, Feb 23, 2011 at 9:59 PM, Noorul Islam K M <no...@collab.net> wrote:
>> Noorul Islam K M <no...@collab.net> writes:
>>
>>> Paul Burba <pt...@gmail.com> writes:
>>>
>>>> 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,  <pb...@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)
>>>>>
>>>>>
>>>>>
>>>
>>> Please find attached patch for Makefile.in to make the same work on
>>> linux. I am not that proficient with make files. But still I think I did
>>> it right.
>>>
>>> Log
>>> [[[
>>>
>>> Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
>>> MODE_FILTER options.
>>>
>>> Now we can easily answer questions like, "What xfailing merge tests need to
>>> be fixed before we can release 1.7?"
>>>
>>> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail
>>> TESTS=subversion/tests/cmdline/merge_tests.py
>>>
>>>   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)]
>>>
>>> * Makefile.in
>>>   (check): Pass --list, --milestone-filter, --mode-filter and
>>>     --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.
>>>
>>> * build/run_tests.py
>>>   (__doc__): Add --list, --milestone-filter and --mode-filter options to
>>>     usage doc.
>>>
>>>   (main): Accept --list, --milestone-filter and --mode-filter as a valid
>>>    option, pass it to TestHarness()
>>>
>>> Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
>>> ]]]
>>>
>>> Index: Makefile.in
>>> ===================================================================
>>> --- Makefile.in       (revision 1072234)
>>> +++ Makefile.in       (working copy)
>>> @@ -473,6 +473,10 @@
>>>         if test "$(LOG_TO_STDOUT)" != ""; then                             \
>>>           flags="--log-to-stdout $$flags";                                 \
>>>         fi;                                                                \
>>> +       if test "$(MILESTONE_FILTER)" != ""; then                          \
>>> +         flags="--list --milestone-filter=$(MILESTONE_FILTER)             \
>>> +                --mode-filter=$(MODE_FILTER) --log-to-stdout $$flags";    \
>>> +       fi;                                                                \
>>>         $(PYTHON) $(top_srcdir)/build/run_tests.py                         \
>>>                   --config-file $(top_srcdir)/subversion/tests/tests.conf  \
>>>                   $$flags                                                  \
>>> Index: build/run_tests.py
>>> ===================================================================
>>> --- build/run_tests.py        (revision 1072234)
>>> +++ build/run_tests.py        (working copy)
>>> @@ -27,6 +27,7 @@
>>>              [--verbose] [--log-to-stdout] [--cleanup] [--parallel]
>>>              [--url=<base-url>] [--http-library=<http-library>] [--enable-sasl]
>>>              [--fs-type=<fs-type>] [--fsfs-packing] [--fsfs-sharding=<n>]
>>> +            [--list] [--milestone-filter=<regex>] [--mode-filter=<type>]
>>>              [--server-minor-version=<version>]
>>>              [--config-file=<file>]
>>>              <abs_srcdir> <abs_builddir>
>>> @@ -522,7 +523,7 @@
>>>                              'http-library=', 'server-minor-version=',
>>>                              'fsfs-packing', 'fsfs-sharding=',
>>>                              'enable-sasl', 'parallel', 'config-file=',
>>> -                            'log-to-stdout'])
>>> +                            'log-to-stdout', 'list', 'milestone-filter=', 'mode-filter='])
>>>    except getopt.GetoptError:
>>>      args = []
>>>
>>> @@ -532,9 +533,9 @@
>>>
>>>    base_url, fs_type, verbose, cleanup, enable_sasl, http_library, \
>>>      server_minor_version, fsfs_sharding, fsfs_packing, parallel, \
>>> -    config_file, log_to_stdout = \
>>> +    config_file, log_to_stdout, list_tests, mode_filter, milestone_filter= \
>>>              None, None, None, None, None, None, None, None, None, None, None, \
>>> -            None
>>> +            None, None, None, None
>>>    for opt, val in opts:
>>>      if opt in ['-u', '--url']:
>>>        base_url = val
>>> @@ -560,6 +561,12 @@
>>>        config_file = val
>>>      elif opt in ['--log-to-stdout']:
>>>        log_to_stdout = 1
>>> +    elif opt in ['--list']:
>>> +      list_tests = 1
>>> +    elif opt in ['--milestone-filter']:
>>> +      milestone_filter = val
>>> +    elif opt in ['--mode-filter']:
>>> +      mode_filter = val
>>>      else:
>>>        raise getopt.GetoptError
>>>
>>> @@ -573,7 +580,8 @@
>>>    th = TestHarness(args[0], args[1], logfile, faillogfile,
>>>                     base_url, fs_type, http_library, server_minor_version,
>>>                     verbose, cleanup, enable_sasl, parallel, config_file,
>>> -                   fsfs_sharding, fsfs_packing)
>>> +                   fsfs_sharding, fsfs_packing, list_tests,
>>> +                   mode_filter=mode_filter, milestone_filter=milestone_filter)
>>>
>>>    failed = th.run(args[2:])
>>>    if failed:
>>
>> Pinging to get some attention to this thread.
>
> Hi Noorul,
>
> I can't evaluate this patch since I don't have a linux box.
>
> This may be a silly question, but have you tried it out?  Can you
> generate a listing of xfailing tests that have associated issues with
> the 1.7 milestone for example?
>

I mentioned this in the commit log message. Here is how I ran it. 

I mentioned the output in commit log. I once again pasting it here.

$ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
TESTS=subversion/tests/cmdline/merge_tests.py

  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)]

Thanks and Regards
Noorul

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Paul Burba <pt...@gmail.com>.
On Wed, Feb 23, 2011 at 9:59 PM, Noorul Islam K M <no...@collab.net> wrote:
> Noorul Islam K M <no...@collab.net> writes:
>
>> Paul Burba <pt...@gmail.com> writes:
>>
>>> 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,  <pb...@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)
>>>>
>>>>
>>>>
>>
>> Please find attached patch for Makefile.in to make the same work on
>> linux. I am not that proficient with make files. But still I think I did
>> it right.
>>
>> Log
>> [[[
>>
>> Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
>> MODE_FILTER options.
>>
>> Now we can easily answer questions like, "What xfailing merge tests need to
>> be fixed before we can release 1.7?"
>>
>> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail
>> TESTS=subversion/tests/cmdline/merge_tests.py
>>
>>   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)]
>>
>> * Makefile.in
>>   (check): Pass --list, --milestone-filter, --mode-filter and
>>     --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.
>>
>> * build/run_tests.py
>>   (__doc__): Add --list, --milestone-filter and --mode-filter options to
>>     usage doc.
>>
>>   (main): Accept --list, --milestone-filter and --mode-filter as a valid
>>    option, pass it to TestHarness()
>>
>> Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
>> ]]]
>>
>> Index: Makefile.in
>> ===================================================================
>> --- Makefile.in       (revision 1072234)
>> +++ Makefile.in       (working copy)
>> @@ -473,6 +473,10 @@
>>         if test "$(LOG_TO_STDOUT)" != ""; then                             \
>>           flags="--log-to-stdout $$flags";                                 \
>>         fi;                                                                \
>> +       if test "$(MILESTONE_FILTER)" != ""; then                          \
>> +         flags="--list --milestone-filter=$(MILESTONE_FILTER)             \
>> +                --mode-filter=$(MODE_FILTER) --log-to-stdout $$flags";    \
>> +       fi;                                                                \
>>         $(PYTHON) $(top_srcdir)/build/run_tests.py                         \
>>                   --config-file $(top_srcdir)/subversion/tests/tests.conf  \
>>                   $$flags                                                  \
>> Index: build/run_tests.py
>> ===================================================================
>> --- build/run_tests.py        (revision 1072234)
>> +++ build/run_tests.py        (working copy)
>> @@ -27,6 +27,7 @@
>>              [--verbose] [--log-to-stdout] [--cleanup] [--parallel]
>>              [--url=<base-url>] [--http-library=<http-library>] [--enable-sasl]
>>              [--fs-type=<fs-type>] [--fsfs-packing] [--fsfs-sharding=<n>]
>> +            [--list] [--milestone-filter=<regex>] [--mode-filter=<type>]
>>              [--server-minor-version=<version>]
>>              [--config-file=<file>]
>>              <abs_srcdir> <abs_builddir>
>> @@ -522,7 +523,7 @@
>>                              'http-library=', 'server-minor-version=',
>>                              'fsfs-packing', 'fsfs-sharding=',
>>                              'enable-sasl', 'parallel', 'config-file=',
>> -                            'log-to-stdout'])
>> +                            'log-to-stdout', 'list', 'milestone-filter=', 'mode-filter='])
>>    except getopt.GetoptError:
>>      args = []
>>
>> @@ -532,9 +533,9 @@
>>
>>    base_url, fs_type, verbose, cleanup, enable_sasl, http_library, \
>>      server_minor_version, fsfs_sharding, fsfs_packing, parallel, \
>> -    config_file, log_to_stdout = \
>> +    config_file, log_to_stdout, list_tests, mode_filter, milestone_filter= \
>>              None, None, None, None, None, None, None, None, None, None, None, \
>> -            None
>> +            None, None, None, None
>>    for opt, val in opts:
>>      if opt in ['-u', '--url']:
>>        base_url = val
>> @@ -560,6 +561,12 @@
>>        config_file = val
>>      elif opt in ['--log-to-stdout']:
>>        log_to_stdout = 1
>> +    elif opt in ['--list']:
>> +      list_tests = 1
>> +    elif opt in ['--milestone-filter']:
>> +      milestone_filter = val
>> +    elif opt in ['--mode-filter']:
>> +      mode_filter = val
>>      else:
>>        raise getopt.GetoptError
>>
>> @@ -573,7 +580,8 @@
>>    th = TestHarness(args[0], args[1], logfile, faillogfile,
>>                     base_url, fs_type, http_library, server_minor_version,
>>                     verbose, cleanup, enable_sasl, parallel, config_file,
>> -                   fsfs_sharding, fsfs_packing)
>> +                   fsfs_sharding, fsfs_packing, list_tests,
>> +                   mode_filter=mode_filter, milestone_filter=milestone_filter)
>>
>>    failed = th.run(args[2:])
>>    if failed:
>
> Pinging to get some attention to this thread.

Hi Noorul,

I can't evaluate this patch since I don't have a linux box.

This may be a silly question, but have you tried it out?  Can you
generate a listing of xfailing tests that have associated issues with
the 1.7 milestone for example?

Paul

> Thanks and Regards
> Noorul
>

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Paul Burba <pt...@gmail.com>.
On Wed, Feb 23, 2011 at 9:59 PM, Noorul Islam K M <no...@collab.net> wrote:
> Noorul Islam K M <no...@collab.net> writes:
>
>> Paul Burba <pt...@gmail.com> writes:
>>
>>> 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,  <pb...@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)
>>>>
>>>>
>>>>
>>
>> Please find attached patch for Makefile.in to make the same work on
>> linux. I am not that proficient with make files. But still I think I did
>> it right.
>>
>> Log
>> [[[
>>
>> Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
>> MODE_FILTER options.
>>
>> Now we can easily answer questions like, "What xfailing merge tests need to
>> be fixed before we can release 1.7?"
>>
>> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail
>> TESTS=subversion/tests/cmdline/merge_tests.py
>>
>>   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)]
>>
>> * Makefile.in
>>   (check): Pass --list, --milestone-filter, --mode-filter and
>>     --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.
>>
>> * build/run_tests.py
>>   (__doc__): Add --list, --milestone-filter and --mode-filter options to
>>     usage doc.
>>
>>   (main): Accept --list, --milestone-filter and --mode-filter as a valid
>>    option, pass it to TestHarness()
>>
>> Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
>> ]]]
>>
>> Index: Makefile.in
>> ===================================================================
>> --- Makefile.in       (revision 1072234)
>> +++ Makefile.in       (working copy)
>> @@ -473,6 +473,10 @@
>>         if test "$(LOG_TO_STDOUT)" != ""; then                             \
>>           flags="--log-to-stdout $$flags";                                 \
>>         fi;                                                                \
>> +       if test "$(MILESTONE_FILTER)" != ""; then                          \
>> +         flags="--list --milestone-filter=$(MILESTONE_FILTER)             \
>> +                --mode-filter=$(MODE_FILTER) --log-to-stdout $$flags";    \
>> +       fi;                                                                \
>>         $(PYTHON) $(top_srcdir)/build/run_tests.py                         \
>>                   --config-file $(top_srcdir)/subversion/tests/tests.conf  \
>>                   $$flags                                                  \
>> Index: build/run_tests.py
>> ===================================================================
>> --- build/run_tests.py        (revision 1072234)
>> +++ build/run_tests.py        (working copy)
>> @@ -27,6 +27,7 @@
>>              [--verbose] [--log-to-stdout] [--cleanup] [--parallel]
>>              [--url=<base-url>] [--http-library=<http-library>] [--enable-sasl]
>>              [--fs-type=<fs-type>] [--fsfs-packing] [--fsfs-sharding=<n>]
>> +            [--list] [--milestone-filter=<regex>] [--mode-filter=<type>]
>>              [--server-minor-version=<version>]
>>              [--config-file=<file>]
>>              <abs_srcdir> <abs_builddir>
>> @@ -522,7 +523,7 @@
>>                              'http-library=', 'server-minor-version=',
>>                              'fsfs-packing', 'fsfs-sharding=',
>>                              'enable-sasl', 'parallel', 'config-file=',
>> -                            'log-to-stdout'])
>> +                            'log-to-stdout', 'list', 'milestone-filter=', 'mode-filter='])
>>    except getopt.GetoptError:
>>      args = []
>>
>> @@ -532,9 +533,9 @@
>>
>>    base_url, fs_type, verbose, cleanup, enable_sasl, http_library, \
>>      server_minor_version, fsfs_sharding, fsfs_packing, parallel, \
>> -    config_file, log_to_stdout = \
>> +    config_file, log_to_stdout, list_tests, mode_filter, milestone_filter= \
>>              None, None, None, None, None, None, None, None, None, None, None, \
>> -            None
>> +            None, None, None, None
>>    for opt, val in opts:
>>      if opt in ['-u', '--url']:
>>        base_url = val
>> @@ -560,6 +561,12 @@
>>        config_file = val
>>      elif opt in ['--log-to-stdout']:
>>        log_to_stdout = 1
>> +    elif opt in ['--list']:
>> +      list_tests = 1
>> +    elif opt in ['--milestone-filter']:
>> +      milestone_filter = val
>> +    elif opt in ['--mode-filter']:
>> +      mode_filter = val
>>      else:
>>        raise getopt.GetoptError
>>
>> @@ -573,7 +580,8 @@
>>    th = TestHarness(args[0], args[1], logfile, faillogfile,
>>                     base_url, fs_type, http_library, server_minor_version,
>>                     verbose, cleanup, enable_sasl, parallel, config_file,
>> -                   fsfs_sharding, fsfs_packing)
>> +                   fsfs_sharding, fsfs_packing, list_tests,
>> +                   mode_filter=mode_filter, milestone_filter=milestone_filter)
>>
>>    failed = th.run(args[2:])
>>    if failed:
>
> Pinging to get some attention to this thread.

Hi Noorul,

I can't evaluate this patch since I don't have a linux box.

This may be a silly question, but have you tried it out?  Can you
generate a listing of xfailing tests that have associated issues with
the 1.7 milestone for example?

Paul

> Thanks and Regards
> Noorul
>

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Noorul Islam K M <no...@collab.net> writes:

> Paul Burba <pt...@gmail.com> writes:
>
>> 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,  <pb...@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)
>>>
>>>
>>>
>
> Please find attached patch for Makefile.in to make the same work on
> linux. I am not that proficient with make files. But still I think I did
> it right.
>
> Log
> [[[
>
> Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
> MODE_FILTER options.
>
> Now we can easily answer questions like, "What xfailing merge tests need to
> be fixed before we can release 1.7?"
>
> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
> TESTS=subversion/tests/cmdline/merge_tests.py
>
>   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)]
>
> * Makefile.in
>   (check): Pass --list, --milestone-filter, --mode-filter and
>     --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.
>
> * build/run_tests.py
>   (__doc__): Add --list, --milestone-filter and --mode-filter options to
>     usage doc.
>
>   (main): Accept --list, --milestone-filter and --mode-filter as a valid
>    option, pass it to TestHarness()
>
> Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
> ]]]
>
> Index: Makefile.in
> ===================================================================
> --- Makefile.in	(revision 1072234)
> +++ Makefile.in	(working copy)
> @@ -473,6 +473,10 @@
>  	  if test "$(LOG_TO_STDOUT)" != ""; then                             \
>  	    flags="--log-to-stdout $$flags";                                 \
>  	  fi;                                                                \
> +	  if test "$(MILESTONE_FILTER)" != ""; then                          \
> +	    flags="--list --milestone-filter=$(MILESTONE_FILTER)             \
> +		   --mode-filter=$(MODE_FILTER) --log-to-stdout $$flags";    \
> +	  fi;                                                                \
>  	  $(PYTHON) $(top_srcdir)/build/run_tests.py                         \
>  	            --config-file $(top_srcdir)/subversion/tests/tests.conf  \
>  	            $$flags                                                  \
> Index: build/run_tests.py
> ===================================================================
> --- build/run_tests.py	(revision 1072234)
> +++ build/run_tests.py	(working copy)
> @@ -27,6 +27,7 @@
>              [--verbose] [--log-to-stdout] [--cleanup] [--parallel]
>              [--url=<base-url>] [--http-library=<http-library>] [--enable-sasl]
>              [--fs-type=<fs-type>] [--fsfs-packing] [--fsfs-sharding=<n>]
> +            [--list] [--milestone-filter=<regex>] [--mode-filter=<type>]
>              [--server-minor-version=<version>]
>              [--config-file=<file>]
>              <abs_srcdir> <abs_builddir>
> @@ -522,7 +523,7 @@
>                              'http-library=', 'server-minor-version=',
>                              'fsfs-packing', 'fsfs-sharding=',
>                              'enable-sasl', 'parallel', 'config-file=',
> -                            'log-to-stdout'])
> +                            'log-to-stdout', 'list', 'milestone-filter=', 'mode-filter='])
>    except getopt.GetoptError:
>      args = []
>  
> @@ -532,9 +533,9 @@
>  
>    base_url, fs_type, verbose, cleanup, enable_sasl, http_library, \
>      server_minor_version, fsfs_sharding, fsfs_packing, parallel, \
> -    config_file, log_to_stdout = \
> +    config_file, log_to_stdout, list_tests, mode_filter, milestone_filter= \
>              None, None, None, None, None, None, None, None, None, None, None, \
> -            None
> +            None, None, None, None
>    for opt, val in opts:
>      if opt in ['-u', '--url']:
>        base_url = val
> @@ -560,6 +561,12 @@
>        config_file = val
>      elif opt in ['--log-to-stdout']:
>        log_to_stdout = 1
> +    elif opt in ['--list']:
> +      list_tests = 1
> +    elif opt in ['--milestone-filter']:
> +      milestone_filter = val
> +    elif opt in ['--mode-filter']:
> +      mode_filter = val
>      else:
>        raise getopt.GetoptError
>  
> @@ -573,7 +580,8 @@
>    th = TestHarness(args[0], args[1], logfile, faillogfile,
>                     base_url, fs_type, http_library, server_minor_version,
>                     verbose, cleanup, enable_sasl, parallel, config_file,
> -                   fsfs_sharding, fsfs_packing)
> +                   fsfs_sharding, fsfs_packing, list_tests,
> +                   mode_filter=mode_filter, milestone_filter=milestone_filter)
>  
>    failed = th.run(args[2:])
>    if failed:

Pinging to get some attention to this thread.

Thanks and Regards
Noorul

Re: [PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Noorul Islam K M <no...@collab.net> writes:

> Paul Burba <pt...@gmail.com> writes:
>
>> 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,  <pb...@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)
>>>
>>>
>>>
>
> Please find attached patch for Makefile.in to make the same work on
> linux. I am not that proficient with make files. But still I think I did
> it right.
>
> Log
> [[[
>
> Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
> MODE_FILTER options.
>
> Now we can easily answer questions like, "What xfailing merge tests need to
> be fixed before we can release 1.7?"
>
> $ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
> TESTS=subversion/tests/cmdline/merge_tests.py
>
>   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)]
>
> * Makefile.in
>   (check): Pass --list, --milestone-filter, --mode-filter and
>     --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.
>
> * build/run_tests.py
>   (__doc__): Add --list, --milestone-filter and --mode-filter options to
>     usage doc.
>
>   (main): Accept --list, --milestone-filter and --mode-filter as a valid
>    option, pass it to TestHarness()
>
> Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
> ]]]
>
> Index: Makefile.in
> ===================================================================
> --- Makefile.in	(revision 1072234)
> +++ Makefile.in	(working copy)
> @@ -473,6 +473,10 @@
>  	  if test "$(LOG_TO_STDOUT)" != ""; then                             \
>  	    flags="--log-to-stdout $$flags";                                 \
>  	  fi;                                                                \
> +	  if test "$(MILESTONE_FILTER)" != ""; then                          \
> +	    flags="--list --milestone-filter=$(MILESTONE_FILTER)             \
> +		   --mode-filter=$(MODE_FILTER) --log-to-stdout $$flags";    \
> +	  fi;                                                                \
>  	  $(PYTHON) $(top_srcdir)/build/run_tests.py                         \
>  	            --config-file $(top_srcdir)/subversion/tests/tests.conf  \
>  	            $$flags                                                  \
> Index: build/run_tests.py
> ===================================================================
> --- build/run_tests.py	(revision 1072234)
> +++ build/run_tests.py	(working copy)
> @@ -27,6 +27,7 @@
>              [--verbose] [--log-to-stdout] [--cleanup] [--parallel]
>              [--url=<base-url>] [--http-library=<http-library>] [--enable-sasl]
>              [--fs-type=<fs-type>] [--fsfs-packing] [--fsfs-sharding=<n>]
> +            [--list] [--milestone-filter=<regex>] [--mode-filter=<type>]
>              [--server-minor-version=<version>]
>              [--config-file=<file>]
>              <abs_srcdir> <abs_builddir>
> @@ -522,7 +523,7 @@
>                              'http-library=', 'server-minor-version=',
>                              'fsfs-packing', 'fsfs-sharding=',
>                              'enable-sasl', 'parallel', 'config-file=',
> -                            'log-to-stdout'])
> +                            'log-to-stdout', 'list', 'milestone-filter=', 'mode-filter='])
>    except getopt.GetoptError:
>      args = []
>  
> @@ -532,9 +533,9 @@
>  
>    base_url, fs_type, verbose, cleanup, enable_sasl, http_library, \
>      server_minor_version, fsfs_sharding, fsfs_packing, parallel, \
> -    config_file, log_to_stdout = \
> +    config_file, log_to_stdout, list_tests, mode_filter, milestone_filter= \
>              None, None, None, None, None, None, None, None, None, None, None, \
> -            None
> +            None, None, None, None
>    for opt, val in opts:
>      if opt in ['-u', '--url']:
>        base_url = val
> @@ -560,6 +561,12 @@
>        config_file = val
>      elif opt in ['--log-to-stdout']:
>        log_to_stdout = 1
> +    elif opt in ['--list']:
> +      list_tests = 1
> +    elif opt in ['--milestone-filter']:
> +      milestone_filter = val
> +    elif opt in ['--mode-filter']:
> +      mode_filter = val
>      else:
>        raise getopt.GetoptError
>  
> @@ -573,7 +580,8 @@
>    th = TestHarness(args[0], args[1], logfile, faillogfile,
>                     base_url, fs_type, http_library, server_minor_version,
>                     verbose, cleanup, enable_sasl, parallel, config_file,
> -                   fsfs_sharding, fsfs_packing)
> +                   fsfs_sharding, fsfs_packing, list_tests,
> +                   mode_filter=mode_filter, milestone_filter=milestone_filter)
>  
>    failed = th.run(args[2:])
>    if failed:

Pinging to get some attention to this thread.

Thanks and Regards
Noorul

[PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Paul Burba <pt...@gmail.com> writes:

> 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,  <pb...@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)
>>
>>
>>

Please find attached patch for Makefile.in to make the same work on
linux. I am not that proficient with make files. But still I think I did
it right.

Log
[[[

Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
MODE_FILTER options.

Now we can easily answer questions like, "What xfailing merge tests need to
be fixed before we can release 1.7?"

$ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
TESTS=subversion/tests/cmdline/merge_tests.py

  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)]

* Makefile.in
  (check): Pass --list, --milestone-filter, --mode-filter and
    --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.

* build/run_tests.py
  (__doc__): Add --list, --milestone-filter and --mode-filter options to
    usage doc.

  (main): Accept --list, --milestone-filter and --mode-filter as a valid
   option, pass it to TestHarness()

Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
]]]


[PATCH] Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Noorul Islam K M <no...@collab.net>.
Paul Burba <pt...@gmail.com> writes:

> 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,  <pb...@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)
>>
>>
>>

Please find attached patch for Makefile.in to make the same work on
linux. I am not that proficient with make files. But still I think I did
it right.

Log
[[[

Follow-up to r1071809. Allow 'make check' to take MILESTON_FILTER and
MODE_FILTER options.

Now we can easily answer questions like, "What xfailing merge tests need to
be fixed before we can release 1.7?"

$ make check MILESTONE_FILTER="(1.7.*)|(---)" MODE_FILTER=xfail 
TESTS=subversion/tests/cmdline/merge_tests.py

  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)]

* Makefile.in
  (check): Pass --list, --milestone-filter, --mode-filter and
    --log-to-stdout to run_tests.py if MILESTONE_FILTER is set.

* build/run_tests.py
  (__doc__): Add --list, --milestone-filter and --mode-filter options to
    usage doc.

  (main): Accept --list, --milestone-filter and --mode-filter as a valid
   option, pass it to TestHarness()

Patch by: Noorul Islam K M <noorul{_AT_}collab.net>
]]]


Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Paul Burba <pt...@gmail.com>.
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,  <pb...@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)
>
>
>

Re: svn commit: r1071809 - in /subversion/trunk: build/run_tests.py subversion/tests/cmdline/svntest/main.py win-tests.py

Posted by Paul Burba <pt...@gmail.com>.
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,  <pb...@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)
>
>
>