Rev 2530: Speed up tests by deleting test directories immediately after they're used, and put them in (mbp, spiv) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Jun 15 09:22:25 BST 2007


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 2530
revision-id: pqm at pqm.ubuntu.com-20070615082222-98j9j9nbl6p2dx0m
parent: pqm at pqm.ubuntu.com-20070615062113-gl52qb0poutr1rm2
parent: mbp at sourcefrog.net-20070615072849-0u2u4suxx241ifzv
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2007-06-15 09:22:22 +0100
message:
  Speed up tests by deleting test directories immediately after they're used, and put them in  (mbp, spiv)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzr                            bzr.py-20050313053754-5485f144c7006fa6
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
  bzrlib/tests/workingtree_implementations/test_remove.py test_remove.py-20070413183901-rvnp85rtc0q0sclp-1
    ------------------------------------------------------------
    revno: 2485.6.9
    merged: mbp at sourcefrog.net-20070615072849-0u2u4suxx241ifzv
    parent: mbp at sourcefrog.net-20070615070124-clpwqh5gxc4wbf9l
    parent: pqm at pqm.ubuntu.com-20070615062113-gl52qb0poutr1rm2
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Fri 2007-06-15 17:28:49 +1000
    message:
      merge news
    ------------------------------------------------------------
    revno: 2485.6.8
    merged: mbp at sourcefrog.net-20070615070124-clpwqh5gxc4wbf9l
    parent: mbp at sourcefrog.net-20070615070005-zazxgg6r00wivdlm
    parent: pqm at pqm.ubuntu.com-20070614060745-ywfqw6rm1sgtfx6i
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Fri 2007-06-15 17:01:24 +1000
    message:
      Merge trunk
    ------------------------------------------------------------
    revno: 2485.6.7
    merged: mbp at sourcefrog.net-20070615070005-zazxgg6r00wivdlm
    parent: mbp at sourcefrog.net-20070519083934-uowlkzt7k007k0rg
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Fri 2007-06-15 17:00:05 +1000
    message:
      Run exitfuncs explicitly before exiting
    ------------------------------------------------------------
    revno: 2485.6.6
    merged: mbp at sourcefrog.net-20070519083934-uowlkzt7k007k0rg
    parent: mbp at sourcefrog.net-20070513090229-zr8pjf4tw5vqvo4s
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Sat 2007-05-19 09:39:34 +0100
    message:
      Put test root directory (containing per-test directories) in TMPDIR
      rather than current directory, so it can be automatically scavenged,
      kept in ramdisk, etc.  Remove test root directory through atexit rather
      than from test runner.  Remove some code for managing them.
      
      More thoroughly remove --keep-output.
    ------------------------------------------------------------
    revno: 2485.6.5
    merged: mbp at sourcefrog.net-20070513090229-zr8pjf4tw5vqvo4s
    parent: mbp at sourcefrog.net-20070513072544-nqoezox04fjhtf1o
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Sun 2007-05-13 10:02:29 +0100
    message:
      Remove keep_output option
    ------------------------------------------------------------
    revno: 2485.6.4
    merged: mbp at sourcefrog.net-20070513072544-nqoezox04fjhtf1o
    parent: mbp at sourcefrog.net-20070513070524-l5v00s0uzue6ssha
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Sun 2007-05-13 08:25:44 +0100
    message:
      Move unicode handling code into _rmtree_temp_dir
    ------------------------------------------------------------
    revno: 2485.6.3
    merged: mbp at sourcefrog.net-20070513070524-l5v00s0uzue6ssha
    parent: mbp at sourcefrog.net-20070513070444-msb9c171zrqd3re3
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Sun 2007-05-13 08:05:24 +0100
    message:
      TestCaseInTempDir takes responsibility for cleaning up its own test dir
    ------------------------------------------------------------
    revno: 2485.6.2
    merged: mbp at sourcefrog.net-20070513070444-msb9c171zrqd3re3
    parent: mbp at sourcefrog.net-20070512191952-4317gkfcuz0jnbml
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Sun 2007-05-13 08:04:44 +0100
    message:
      Don't call makeAndChdirToTestDir from test cases, it's done automatically in the parent
    ------------------------------------------------------------
    revno: 2485.6.1
    merged: mbp at sourcefrog.net-20070512191952-4317gkfcuz0jnbml
    parent: pqm at pqm.ubuntu.com-20070510055501-w262sk5hl33vmd19
    committer: Martin Pool <mbp at sourcefrog.net>
    branch nick: test-cleanup
    timestamp: Sat 2007-05-12 20:19:52 +0100
    message:
      Remove duplication in TestCaseInTempDir.makeAndChdirToTestDir
=== modified file 'NEWS'
--- a/NEWS	2007-06-15 05:27:24 +0000
+++ b/NEWS	2007-06-15 07:28:49 +0000
@@ -16,6 +16,13 @@
     * ``bzr missing`` now has better option names ``--this`` and ``--other``.
       (Elliot Murphy)
 
+  TESTING:
+
+    * Removed the ``--keep-output`` option from selftest and clean up test
+      directories as they're used.  This reduces the IO load from 
+      running the test suite and cuts the time by about half.
+      (Andrew Bennetts, Martin Pool)
+
 bzr 0.17rc1  2007-06-12
 
   NOTES WHEN UPGRADING:

=== modified file 'bzr'
--- a/bzr	2007-06-12 16:21:40 +0000
+++ b/bzr	2007-06-15 07:01:24 +0000
@@ -101,6 +101,10 @@
     if profiling:
         profile_imports.log_stack_info(sys.stderr)
 
+    # run anything registered by atexit, because it won't be run in the normal
+    # way
+    sys.exitfunc()
+
     # By this point we really have completed everything we want to do, and
     # there's no point doing any additional cleanup.  Abruptly exiting here
     # stops any background threads getting into trouble as code is unloaded,

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2007-06-15 05:27:24 +0000
+++ b/bzrlib/builtins.py	2007-06-15 07:28:49 +0000
@@ -2359,11 +2359,6 @@
 class cmd_selftest(Command):
     """Run internal test suite.
     
-    This creates temporary test directories in the working directory, but no
-    existing data is affected.  These directories are deleted if the tests
-    pass, or left behind to help in debugging if they fail and --keep-output
-    is specified.
-    
     If arguments are given, they are regular expressions that say which tests
     should run.  Tests matching any expression are run, and other tests are
     not run.
@@ -2477,6 +2472,10 @@
             from bzrlib.tests import clean_selftest_output
             clean_selftest_output()
             return 0
+        if keep_output:
+            trace.warning("notice: selftest --keep-output "
+                          "is no longer supported; "
+                          "test output is always removed")
 
         if numbered_dirs is None and sys.platform == 'win32':
             numbered_dirs = True
@@ -2505,7 +2504,6 @@
             result = selftest(verbose=verbose, 
                               pattern=pattern,
                               stop_on_failure=one, 
-                              keep_output=keep_output,
                               transport=transport,
                               test_suite_factory=test_suite_factory,
                               lsprof_timed=lsprof_timed,

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2007-06-14 04:36:50 +0000
+++ b/bzrlib/tests/__init__.py	2007-06-15 07:01:24 +0000
@@ -26,6 +26,7 @@
 # general style of bzrlib.  Please continue that consistency when adding e.g.
 # new assertFoo() methods.
 
+import atexit
 import codecs
 from cStringIO import StringIO
 import difflib
@@ -42,6 +43,7 @@
 import tempfile
 import unittest
 import time
+import warnings
 
 
 from bzrlib import (
@@ -499,7 +501,6 @@
                  stream=sys.stderr,
                  descriptions=0,
                  verbosity=1,
-                 keep_output=False,
                  bench_history=None,
                  use_numbered_dirs=False,
                  list_only=False
@@ -507,7 +508,6 @@
         self.stream = unittest._WritelnDecorator(stream)
         self.descriptions = descriptions
         self.verbosity = verbosity
-        self.keep_output = keep_output
         self._bench_history = bench_history
         self.use_numbered_dirs = use_numbered_dirs
         self.list_only = list_only
@@ -574,29 +574,6 @@
             for feature, count in sorted(result.unsupported.items()):
                 self.stream.writeln("Missing feature '%s' skipped %d tests." %
                     (feature, count))
-        result.report_cleaning_up()
-        # This is still a little bogus, 
-        # but only a little. Folk not using our testrunner will
-        # have to delete their temp directories themselves.
-        test_root = TestCaseWithMemoryTransport.TEST_ROOT
-        if result.wasSuccessful() or not self.keep_output:
-            if test_root is not None:
-                # If LANG=C we probably have created some bogus paths
-                # which rmtree(unicode) will fail to delete
-                # so make sure we are using rmtree(str) to delete everything
-                # except on win32, where rmtree(str) will fail
-                # since it doesn't have the property of byte-stream paths
-                # (they are either ascii or mbcs)
-                if sys.platform == 'win32':
-                    # make sure we are using the unicode win32 api
-                    test_root = unicode(test_root)
-                else:
-                    test_root = test_root.encode(
-                        sys.getfilesystemencoding())
-                _rmtree_temp_dir(test_root)
-        else:
-            note("Failed tests working directories are in '%s'\n", test_root)
-        TestCaseWithMemoryTransport.TEST_ROOT = None
         result.finished()
         return result
 
@@ -1601,12 +1578,14 @@
     file defaults for the transport in tests, nor does it obey the command line
     override, so tests that accidentally write to the common directory should
     be rare.
+
+    :cvar TEST_ROOT: Directory containing all temporary directories, plus
+    a .bzr directory that stops us ascending higher into the filesystem.
     """
 
     TEST_ROOT = None
     _TEST_NAME = 'test'
 
-
     def __init__(self, methodName='runTest'):
         # allow test parameterisation after test construction and before test
         # execution. Variables that the parameteriser sets need to be 
@@ -1763,24 +1742,16 @@
     def _make_test_root(self):
         if TestCaseWithMemoryTransport.TEST_ROOT is not None:
             return
-        i = 0
-        while True:
-            root = u'test%04d.tmp' % i
-            try:
-                os.mkdir(root)
-            except OSError, e:
-                if e.errno == errno.EEXIST:
-                    i += 1
-                    continue
-                else:
-                    raise
-            # successfully created
-            TestCaseWithMemoryTransport.TEST_ROOT = osutils.abspath(root)
-            break
+        root = tempfile.mkdtemp(prefix='testbzr-', suffix='.tmp')
+        TestCaseWithMemoryTransport.TEST_ROOT = root
+        
         # make a fake bzr directory there to prevent any tests propagating
         # up onto the source directory's real branch
-        bzrdir.BzrDir.create_standalone_workingtree(
-            TestCaseWithMemoryTransport.TEST_ROOT)
+        bzrdir.BzrDir.create_standalone_workingtree(root)
+
+        # The same directory is used by all tests, and we're not specifically
+        # told when all tests are finished.  This will do.
+        atexit.register(_rmtree_temp_dir, root)
 
     def makeAndChdirToTestDir(self):
         """Create a temporary directories for this one test.
@@ -1860,7 +1831,14 @@
     All test cases create their own directory within that.  If the
     tests complete successfully, the directory is removed.
 
-    InTempDir is an old alias for FunctionalTestCase.
+    :ivar test_base_dir: The path of the top-level directory for this 
+    test, which contains a home directory and a work directory.
+
+    :ivar test_home_dir: An initially empty directory under test_base_dir
+    which is used as $HOME for this test.
+
+    :ivar test_dir: A directory under test_base_dir used as the current
+    directory when the test proper is run.
     """
 
     OVERRIDE_PYTHON = 'python'
@@ -1880,45 +1858,25 @@
         For TestCaseInTempDir we create a temporary directory based on the test
         name and then create two subdirs - test and home under it.
         """
-        if self.use_numbered_dirs:  # strongly recommended on Windows
-                                    # due the path length limitation (260 ch.)
-            candidate_dir = '%s/%dK/%05d' % (self.TEST_ROOT,
-                                             int(self.number/1000),
-                                             self.number)
-            os.makedirs(candidate_dir)
-            self.test_home_dir = candidate_dir + '/home'
-            os.mkdir(self.test_home_dir)
-            self.test_dir = candidate_dir + '/work'
-            os.mkdir(self.test_dir)
-            os.chdir(self.test_dir)
-            # put name of test inside
-            f = file(candidate_dir + '/name', 'w')
+        # create a directory within the top level test directory
+        candidate_dir = tempfile.mkdtemp(dir=self.TEST_ROOT)
+        # now create test and home directories within this dir
+        self.test_base_dir = candidate_dir
+        self.test_home_dir = self.test_base_dir + '/home'
+        os.mkdir(self.test_home_dir)
+        self.test_dir = self.test_base_dir + '/work'
+        os.mkdir(self.test_dir)
+        os.chdir(self.test_dir)
+        # put name of test inside
+        f = file(self.test_base_dir + '/name', 'w')
+        try:
             f.write(self.id())
+        finally:
             f.close()
-            return
-        # Else NAMED DIRS
-        # shorten the name, to avoid test failures due to path length
-        short_id = self.id().replace('bzrlib.tests.', '') \
-                   .replace('__main__.', '')[-100:]
-        # it's possible the same test class is run several times for
-        # parameterized tests, so make sure the names don't collide.  
-        i = 0
-        while True:
-            if i > 0:
-                candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
-            else:
-                candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
-            if os.path.exists(candidate_dir):
-                i = i + 1
-                continue
-            else:
-                os.mkdir(candidate_dir)
-                self.test_home_dir = candidate_dir + '/home'
-                os.mkdir(self.test_home_dir)
-                self.test_dir = candidate_dir + '/work'
-                os.mkdir(self.test_dir)
-                os.chdir(self.test_dir)
-                break
+        self.addCleanup(self.deleteTestDir)
+
+    def deleteTestDir(self):
+        _rmtree_temp_dir(self.test_base_dir)
 
     def build_tree(self, shape, line_endings='binary', transport=None):
         """Build a test tree according to a pattern.
@@ -2160,7 +2118,7 @@
 
 
 def run_suite(suite, name='test', verbose=False, pattern=".*",
-              stop_on_failure=False, keep_output=False,
+              stop_on_failure=False,
               transport=None, lsprof_timed=None, bench_history=None,
               matching_tests_first=None,
               numbered_dirs=None,
@@ -2180,7 +2138,6 @@
     runner = TextTestRunner(stream=sys.stdout,
                             descriptions=0,
                             verbosity=verbosity,
-                            keep_output=keep_output,
                             bench_history=bench_history,
                             use_numbered_dirs=use_numbered_dirs,
                             list_only=list_only,
@@ -2215,7 +2172,6 @@
 
 
 def selftest(verbose=False, pattern=".*", stop_on_failure=True,
-             keep_output=False,
              transport=None,
              test_suite_factory=None,
              lsprof_timed=None,
@@ -2243,7 +2199,7 @@
         else:
             suite = test_suite_factory()
         return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
-                     stop_on_failure=stop_on_failure, keep_output=keep_output,
+                     stop_on_failure=stop_on_failure,
                      transport=transport,
                      lsprof_timed=lsprof_timed,
                      bench_history=bench_history,
@@ -2421,6 +2377,17 @@
 
 
 def _rmtree_temp_dir(dirname):
+    # If LANG=C we probably have created some bogus paths
+    # which rmtree(unicode) will fail to delete
+    # so make sure we are using rmtree(str) to delete everything
+    # except on win32, where rmtree(str) will fail
+    # since it doesn't have the property of byte-stream paths
+    # (they are either ascii or mbcs)
+    if sys.platform == 'win32':
+        # make sure we are using the unicode win32 api
+        dirname = unicode(dirname)
+    else:
+        dirname = dirname.encode(sys.getfilesystemencoding())
     try:
         osutils.rmtree(dirname)
     except OSError, e:

=== modified file 'bzrlib/tests/test_selftest.py'
--- a/bzrlib/tests/test_selftest.py	2007-06-12 14:51:11 +0000
+++ b/bzrlib/tests/test_selftest.py	2007-06-15 07:01:24 +0000
@@ -970,7 +970,7 @@
         def skipping_test():
             raise TestSkipped('test intentionally skipped')
 
-        runner = TextTestRunner(stream=self._log_file, keep_output=True)
+        runner = TextTestRunner(stream=self._log_file)
         test = unittest.FunctionTestCase(skipping_test)
         result = self.run_test_runner(runner, test)
         self.assertTrue(result.wasSuccessful())
@@ -989,7 +989,7 @@
             def cleanup(self):
                 self.counter -= 1
 
-        runner = TextTestRunner(stream=self._log_file, keep_output=True)
+        runner = TextTestRunner(stream=self._log_file)
         test = SkippedSetupTest('test_skip')
         result = self.run_test_runner(runner, test)
         self.assertTrue(result.wasSuccessful())
@@ -1009,7 +1009,7 @@
             def cleanup(self):
                 self.counter -= 1
 
-        runner = TextTestRunner(stream=self._log_file, keep_output=True)
+        runner = TextTestRunner(stream=self._log_file)
         test = SkippedTest('test_skip')
         result = self.run_test_runner(runner, test)
         self.assertTrue(result.wasSuccessful())

=== modified file 'bzrlib/tests/workingtree_implementations/test_remove.py'
--- a/bzrlib/tests/workingtree_implementations/test_remove.py	2007-05-24 12:19:41 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_remove.py	2007-06-15 07:01:24 +0000
@@ -29,7 +29,6 @@
     b_c = ['b', 'b/c']
 
     def getTree(self):
-        self.makeAndChdirToTestDir()
         tree = self.make_branch_and_tree('.')
         self.build_tree(TestRemove.files)
         return tree




More information about the bazaar-commits mailing list