Changeset 21138

Show
Ignore:
Timestamp:
08/21/2007 12:42:40 PM (2 years ago)
Author:
therve
Message:
Merge trial-memory-2275 Author: therve Reviewers: jml, exarkun Fixes #2275 Add two optmizations to trial to reduce its memory footprint: add a new DestructiveTestSuite, used by default, that don't keep a reference to test instances after run, and replace the storage of successfull result by a counter. This allows the garbage collector to clean a lot of objects, and also speed up the whole suite.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/twisted/scripts/trial.py

    r19065 r21138  
    11# -*- test-case-name: twisted.trial.test.test_script -*- 
    22 
    3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. 
     3# Copyright (c) 2001-2007 Twisted Matrix Laboratories. 
    44# See LICENSE for details. 
    55 
     
    311311    if config['force-gc']: 
    312312        loader.forceGarbageCollection = True 
     313    if not config['until-failure']: 
     314        loader.suiteFactory = runner.DestructiveTestSuite 
    313315    return loader 
    314316 
  • trunk/twisted/trial/reporter.py

    r19711 r21138  
    11# -*- test-case-name: twisted.trial.test.test_reporter -*- 
    22# 
    3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. 
     3# Copyright (c) 2001-2007 Twisted Matrix Laboratories. 
    44# See LICENSE for details. 
    55# 
    66# Maintainer: Jonathan Lange <jml@twistedmatrix.com> 
    77 
    8 """Defines classes that handle the results of tests. 
     8""" 
     9Defines classes that handle the results of tests. 
    910 
    1011API Stability: Unstable 
     
    4546 
    4647class TestResult(pyunit.TestResult, object): 
    47     """Accumulates the results of several L{twisted.trial.unittest.TestCase}s. 
     48    """ 
     49    Accumulates the results of several L{twisted.trial.unittest.TestCase}s. 
     50 
     51    @ivar successes: count the number of successes achieved by the test run. 
     52    @type successes: C{int} 
    4853    """ 
    4954 
     
    5358        self.expectedFailures = [] 
    5459        self.unexpectedSuccesses = [] 
    55         self.successes = [] 
     60        self.successes = 0 
    5661        self._timings = [] 
    5762 
     
    145150        @type test: L{pyunit.TestCase} 
    146151        """ 
    147         self.successes.append((test,)) 
     152        self.successes += 1 
    148153 
    149154    def upDownError(self, method, error, warn, printStatus): 
     
    311316        summaries = [] 
    312317        for stat in ("skips", "expectedFailures", "failures", "errors", 
    313                      "unexpectedSuccesses", "successes"): 
     318                     "unexpectedSuccesses"): 
    314319            num = len(getattr(self, stat)) 
    315320            if num: 
    316321                summaries.append('%s=%d' % (stat, num)) 
     322        if self.successes: 
     323           summaries.append('successes=%d' % (self.successes,)) 
    317324        summary = (summaries and ' ('+', '.join(summaries)+')') or '' 
    318325        if not self.wasSuccessful(): 
  • trunk/twisted/trial/runner.py

    r19961 r21138  
    1212 
    1313 
    14 from __future__ import generators 
    1514import pdb, shutil, sets 
    1615import os, types, warnings, sys, inspect, imp 
     
    127126 
    128127 
     128 
    129129class TestSuite(pyunit.TestSuite): 
    130130    """ 
     
    147147            if result.shouldStop: 
    148148                break 
     149            test(result) 
     150        return result 
     151 
     152 
     153 
     154class DestructiveTestSuite(TestSuite): 
     155    """ 
     156    A test suite which remove the tests once run, to minimize memory usage. 
     157    """ 
     158 
     159    def run(self, result): 
     160        """ 
     161        Almost the same as L{TestSuite.run}, but with C{self._tests} being 
     162        empty at the end. 
     163        """ 
     164        while self._tests: 
     165            if result.shouldStop: 
     166                break 
     167            test = self._tests.pop(0) 
    149168            test(result) 
    150169        return result 
     
    820839                break 
    821840        return result 
     841 
  • trunk/twisted/trial/test/test_doctest.py

    r17672 r21138  
    3535        result = reporter.TestResult() 
    3636        suite.run(result) 
    37         self.assertEqual(5, len(result.successes)) 
     37        self.assertEqual(5, result.successes) 
    3838        # doctest reports failures as errors in 2.3 
    3939        self.assertEqual(2, len(result.errors) + len(result.failures)) 
  • trunk/twisted/trial/test/test_runner.py

    r20293 r21138  
    1 # -*- test-case-name: twisted.trial.test.test_runner -*- 
    2  
    31# Copyright (c) 2005-2007 Twisted Matrix Laboratories. 
    42# See LICENSE for details. 
     
    464462        self.holder = runner.ErrorHolder(self.description, error) 
    465463 
     464 
     465 
    466466class TestMalformedMethod(unittest.TestCase): 
    467467    """ 
     
    508508        self._test('test_spam') 
    509509 
     510 
     511 
     512class DestructiveTestSuiteTestCase(unittest.TestCase): 
     513    """ 
     514    Test for L{runner.DestructiveTestSuite}. 
     515    """ 
     516 
     517    def test_basic(self): 
     518        """ 
     519        Thes destructive test suite should run the tests normally. 
     520        """ 
     521        called = [] 
     522        class MockTest(unittest.TestCase): 
     523            def test_foo(test): 
     524                called.append(True) 
     525        test = MockTest('test_foo') 
     526        result = reporter.TestResult() 
     527        suite = runner.DestructiveTestSuite([test]) 
     528        self.assertEquals(called, []) 
     529        suite.run(result) 
     530        self.assertEquals(called, [True]) 
     531        self.assertEquals(suite.countTestCases(), 0) 
     532 
     533 
     534    def test_shouldStop(self): 
     535        """ 
     536        Test the C{shouldStop} management: raising a C{KeyboardInterrupt} must 
     537        interrupt the suite. 
     538        """ 
     539        called = [] 
     540        class MockTest(unittest.TestCase): 
     541            def test_foo1(test): 
     542                called.append(1) 
     543            def test_foo2(test): 
     544                raise KeyboardInterrupt() 
     545            def test_foo3(test): 
     546                called.append(2) 
     547        result = reporter.TestResult() 
     548        loader = runner.TestLoader() 
     549        loader.suiteFactory = runner.DestructiveTestSuite 
     550        suite = loader.loadClass(MockTest) 
     551        self.assertEquals(called, []) 
     552        suite.run(result) 
     553        self.assertEquals(called, [1]) 
     554        # The last test shouldn't have been run 
     555        self.assertEquals(suite.countTestCases(), 1) 
     556 
     557 
     558    def test_cleanup(self): 
     559        """ 
     560        Checks that the test suite cleanups its tests during the run, so that 
     561        it ends empty. 
     562        """ 
     563        class MockTest(unittest.TestCase): 
     564            def test_foo(test): 
     565                pass 
     566        test = MockTest('test_foo') 
     567        result = reporter.TestResult() 
     568        suite = runner.DestructiveTestSuite([test]) 
     569        self.assertEquals(suite.countTestCases(), 1) 
     570        suite.run(result) 
     571        self.assertEquals(suite.countTestCases(), 0) 
     572 
  • trunk/twisted/trial/test/test_script.py

    r18983 r21138  
     1# Copyright (c) 2001-2007 Twisted Matrix Laboratories. 
     2# See LICENSE for details. 
     3 
    14import StringIO, sys, sets 
    25from twisted.trial import unittest, runner 
     
    3336        loader = trial._getLoader(self.config) 
    3437        self.assertEqual(False, loader.forceGarbageCollection) 
     38 
     39 
     40 
     41class TestSuiteUsed(unittest.TestCase): 
     42    """ 
     43    Check the category of tests suite used by the loader. 
     44    """ 
     45 
     46    def setUp(self): 
     47        """ 
     48        Create a trial configuration object. 
     49        """ 
     50        self.config = trial.Options() 
     51 
     52 
     53    def test_defaultSuite(self): 
     54        """ 
     55        By default, the loader should use L{runner.DestructiveTestSuite} 
     56        """ 
     57        loader = trial._getLoader(self.config) 
     58        self.assertEquals(loader.suiteFactory, runner.DestructiveTestSuite) 
     59 
     60 
     61    def test_untilFailureSuite(self): 
     62        """ 
     63        The C{until-failure} configuration uses the L{runner.TestSuite} to keep 
     64        instances alive across runs. 
     65        """ 
     66        self.config['until-failure'] = True 
     67        loader = trial._getLoader(self.config) 
     68        self.assertEquals(loader.suiteFactory, runner.TestSuite) 
     69 
    3570 
    3671 
     
    162197                              'twisted.trial.test.test_tests'}, 
    163198                             localVars) 
    164          
     199 
    165200    def test_parseLocalVariables(self): 
    166         declaration = ('-*- test-case-name: twisted.trial.test.test_tests; '  
     201        declaration = ('-*- test-case-name: twisted.trial.test.test_tests; ' 
    167202                       'foo: bar -*-') 
    168203        localVars = trial._parseLocalVariables(declaration) 
     
    197232                              'twisted.trial.test.test_test_visitor'}, 
    198233                             localVars) 
    199          
     234 
    200235    def test_noVariablesInFile(self): 
    201236        localVars = trial.loadLocalVariables(sibpath('novars.py')) 
  • trunk/twisted/trial/test/test_tests.py

    r20293 r21138  
    66""" 
    77 
    8 import gc, StringIO, sys 
     8import gc, StringIO, sys, weakref 
    99 
    1010from twisted.internet import defer, reactor 
     
    4848 
    4949    def assertSuccessful(self, test, result): 
    50         self.assertEqual(result.successes, [(test,)]) 
     50        self.assertEqual(result.successes, 1) 
    5151        self.assertEqual(result.failures, []) 
    5252        self.assertEqual(result.errors, []) 
     
    7474        test.run(self.result) 
    7575        self.assertSuccessful(test, self.result) 
     76 
     77 
     78    def test_noReference(self): 
     79        """ 
     80        Test that no reference is kept on a successful test. 
     81        """ 
     82        test = TestSuccess('test_successful') 
     83        ref = weakref.ref(test) 
     84        test.run(self.result) 
     85        self.assertSuccessful(test, self.result) 
     86        del test 
     87        gc.collect() 
     88        self.assertIdentical(ref(), None) 
    7689 
    7790