Ticket #8138: 8138reorder-suite.diff

File 8138reorder-suite.diff, 22.1 KB (added by kmtracey, 6 years ago)
  • django/test/simple.py

     
    33from django.db.models import get_app, get_apps
    44from django.test import _doctest as doctest
    55from django.test.utils import setup_test_environment, teardown_test_environment
    6 from django.test.testcases import OutputChecker, DocTestRunner
     6from django.test.testcases import OutputChecker, DocTestRunner, TestCase
    77
    88# The module name for tests outside models.py
    99TEST_MODULE = 'tests'
     
    9999    else: # label is app.TestClass.test_method
    100100        return TestClass(parts[2])
    101101
     102def partition_suite(suite, classes, bins):
     103    """
     104    Partitions a test suite by test type.
     105   
     106    classes is a sequence of types
     107    bins is a sequence of TestSuites, one more than classes
     108   
     109    Tests of type classes[i] are added to bins[i],
     110    tests with no match found in classes are place in bins[-1]
     111    """
     112    for test in suite:
     113        if isinstance(test, unittest.TestSuite):
     114            partition_suite(test, classes, bins)
     115        else:
     116            for i in range(len(classes)):
     117                if isinstance(test, classes[i]):
     118                    bins[i].addTest(test)
     119                    break
     120            else:
     121                bins[-1].addTest(test)
     122           
     123def reorder_suite(suite, classes):
     124    """
     125    Reorders a test suite by test type.
     126   
     127    classes is a sequence of types
     128   
     129    All tests of type clases[0] are placed first, then tests of type classes[1], etc.
     130    Tests with no match in classes are placed last.
     131    """
     132    class_count = len(classes)
     133    bins = [unittest.TestSuite() for i in range(class_count+1)]
     134    partition_suite(suite, classes, bins)
     135    for i in range(class_count):
     136        bins[0].addTests(bins[i+1])
     137    return bins[0]
     138
    102139def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
    103140    """
    104141    Run the unit tests for all the test labels in the provided list.
     
    137174    for test in extra_tests:
    138175        suite.addTest(test)
    139176
     177    suite = reorder_suite(suite, (TestCase,))
     178
    140179    old_name = settings.DATABASE_NAME
    141180    from django.db import connection
    142181    connection.creation.create_test_db(verbosity, autoclobber=not interactive)
  • django/test/client.py

     
    1919from django.utils.encoding import smart_str
    2020from django.utils.http import urlencode
    2121from django.utils.itercompat import is_iterable
     22from django.db import transaction, close_connection
    2223
    2324BOUNDARY = 'BoUnDaRyStRiNg'
    2425MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
     
    6970                response = middleware_method(request, response)
    7071            response = self.apply_response_fixes(request, response)
    7172        finally:
     73            signals.request_finished.disconnect(close_connection)           
    7274            signals.request_finished.send(sender=self.__class__)
     75            signals.request_finished.connect(close_connection)
    7376
    7477        return response
    7578
  • django/test/testcases.py

     
    77from django.core import mail
    88from django.core.management import call_command
    99from django.core.urlresolvers import clear_url_caches
    10 from django.db import transaction
     10from django.db import transaction, connection
    1111from django.http import QueryDict
    1212from django.test import _doctest as doctest
    1313from django.test.client import Client
     
    2626        value = [value]
    2727    return value
    2828
     29real_commit = transaction.commit
     30real_rollback = transaction.rollback
     31real_enter_transaction_management = transaction.enter_transaction_management
     32real_leave_transaction_management = transaction.leave_transaction_management
     33real_savepoint_commit = transaction.savepoint_commit
     34real_savepoint_rollback = transaction.savepoint_rollback
    2935
     36def nop(x=None):
     37    return
     38
     39def disable_transaction_methods():
     40    transaction.commit = nop
     41    transaction.rollback = nop
     42    transaction.savepoint_commit = nop
     43    transaction.savepoint_rollback = nop
     44    transaction.enter_transaction_management = nop
     45    transaction.leave_transaction_management = nop       
     46
     47def restore_transaction_methods():
     48    transaction.commit = real_commit
     49    transaction.rollback = real_rollback
     50    transaction.savepoint_commit = real_savepoint_commit
     51    transaction.savepoint_rollback = real_savepoint_rollback
     52    transaction.enter_transaction_management = real_enter_transaction_management
     53    transaction.leave_transaction_management = real_leave_transaction_management
     54
    3055class OutputChecker(doctest.OutputChecker):
    3156    def check_output(self, want, got, optionflags):
    3257        "The entry method for doctest output checking. Defers to a sequence of child checkers"
     
    168193        # Rollback, in case of database errors. Otherwise they'd have
    169194        # side effects on other tests.
    170195        transaction.rollback_unless_managed()
    171 
    172 class TestCase(unittest.TestCase):
     196       
     197class TransactionTestCase(unittest.TestCase):
    173198    def _pre_setup(self):
    174199        """Performs any pre-test setup. This includes:
    175200
     
    180205              ROOT_URLCONF with it.
    181206            * Clearing the mail test outbox.
    182207        """
     208        self._fixture_setup()
     209        self._urlconf_setup()
     210        mail.outbox = []
     211
     212    def _fixture_setup(self):
    183213        call_command('flush', verbosity=0, interactive=False)
    184214        if hasattr(self, 'fixtures'):
    185215            # We have to use this slightly awkward syntax due to the fact
    186216            # that we're using *args and **kwargs together.
    187217            call_command('loaddata', *self.fixtures, **{'verbosity': 0})
     218
     219    def _urlconf_setup(self):
    188220        if hasattr(self, 'urls'):
    189221            self._old_root_urlconf = settings.ROOT_URLCONF
    190222            settings.ROOT_URLCONF = self.urls
    191223            clear_url_caches()
    192         mail.outbox = []
    193224
    194225    def __call__(self, result=None):
    195226        """
     
    206237            import sys
    207238            result.addError(self, sys.exc_info())
    208239            return
    209         super(TestCase, self).__call__(result)
     240        super(TransactionTestCase, self).__call__(result)       
    210241        try:
    211242            self._post_teardown()
    212243        except (KeyboardInterrupt, SystemExit):
     
    221252
    222253            * Putting back the original ROOT_URLCONF if it was changed.
    223254        """
     255        self._fixture_teardown()
     256        self._urlconf_teardown()
     257
     258    def _fixture_teardown(self):
     259        pass
     260
     261    def _urlconf_teardown(self):       
    224262        if hasattr(self, '_old_root_urlconf'):
    225263            settings.ROOT_URLCONF = self._old_root_urlconf
    226264            clear_url_caches()
     
    354392        self.failIf(template_name in template_names,
    355393            (u"Template '%s' was used unexpectedly in rendering the"
    356394             u" response") % template_name)
     395
     396class TestCase(TransactionTestCase):
     397    """
     398    Does basically the same as TransactionTestCase, but surrounds every test
     399    with a transaction, monkey-patches the real transaction management routines to
     400    do nothing, and rollsback the test transaction at the end of the test. You have
     401    to use TransactionTestCase, if you need transaction management inside a test.
     402    """
     403
     404    def _fixture_setup(self):
     405        if not settings.DATABASE_SUPPORTS_TRANSACTIONS:
     406            return super(TestCase, self)._fixture_setup()
     407       
     408        transaction.enter_transaction_management()
     409        transaction.managed(True)
     410        disable_transaction_methods()
     411
     412        from django.contrib.sites.models import Site
     413        Site.objects.clear_cache()
     414
     415        if hasattr(self, 'fixtures'):
     416            call_command('loaddata', *self.fixtures, **{
     417                                                        'verbosity': 0,
     418                                                        'commit': False
     419                                                        })
     420
     421    def _fixture_teardown(self):
     422        if not settings.DATABASE_SUPPORTS_TRANSACTIONS:
     423            return super(TestCase, self)._fixture_teardown()
     424               
     425        restore_transaction_methods()
     426        transaction.rollback()
     427        transaction.leave_transaction_management()
     428 No newline at end of file
  • django/test/__init__.py

     
    33"""
    44
    55from django.test.client import Client
    6 from django.test.testcases import TestCase
     6from django.test.testcases import TestCase, TransactionTestCase
  • django/db/backends/creation.py

     
    311311
    312312        self.connection.close()
    313313        settings.DATABASE_NAME = test_database_name
    314 
     314        settings.DATABASE_SUPPORTS_TRANSACTIONS = self._rollback_works()
     315       
    315316        call_command('syncdb', verbosity=verbosity, interactive=False)
    316317
    317318        if settings.CACHE_BACKEND.startswith('db://'):
     
    362363                sys.exit(1)
    363364
    364365        return test_database_name
    365 
     366   
     367    def _rollback_works(self):
     368        cursor = self.connection.cursor()
     369        cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
     370        self.connection._commit()
     371        cursor.execute('INSERT INTO ROLLBACK_TEST (X) VALUES (8)')
     372        self.connection._rollback()
     373        cursor.execute('SELECT COUNT(X) FROM ROLLBACK_TEST')
     374        count, = cursor.fetchone()
     375        cursor.execute('DROP TABLE ROLLBACK_TEST')
     376        self.connection._commit()
     377        return count == 0
     378       
    366379    def destroy_test_db(self, old_database_name, verbosity=1):
    367380        """
    368381        Destroy a test database, prompting the user for confirmation if the
  • tests/regressiontests/file_uploads/tests.py

     
    238238        self.obj = FileModel()
    239239        if not os.path.isdir(temp_storage.location):
    240240            os.makedirs(temp_storage.location)
     241        if os.path.isdir(UPLOAD_TO):
     242            os.chmod(UPLOAD_TO, 0700)
     243            shutil.rmtree(UPLOAD_TO)
    241244
    242245    def tearDown(self):
    243246        os.chmod(temp_storage.location, 0700)
  • tests/regressiontests/generic_inline_admin/tests.py

     
    2121        # relies on content type IDs, which will vary depending on what
    2222        # other tests have been run), thus we do it here.
    2323        e = Episode.objects.create(name='This Week in Django')
     24        self.episode_pk = e.pk
    2425        m = Media(content_object=e, url='http://example.com/podcast.mp3')
    2526        m.save()
     27        self.media_pk = m.pk
    2628   
    2729    def tearDown(self):
    2830        self.client.logout()
     
    3941        """
    4042        A smoke test to ensure GET on the change_view works.
    4143        """
    42         response = self.client.get('/generic_inline_admin/admin/generic_inline_admin/episode/1/')
     44        response = self.client.get('/generic_inline_admin/admin/generic_inline_admin/episode/%d/' % self.episode_pk)
    4345        self.failUnlessEqual(response.status_code, 200)
    4446   
    4547    def testBasicAddPost(self):
     
    6466            # inline data
    6567            "generic_inline_admin-media-content_type-object_id-TOTAL_FORMS": u"2",
    6668            "generic_inline_admin-media-content_type-object_id-INITIAL_FORMS": u"1",
    67             "generic_inline_admin-media-content_type-object_id-0-id": u"1",
     69            "generic_inline_admin-media-content_type-object_id-0-id": u"%d" % self.media_pk,
    6870            "generic_inline_admin-media-content_type-object_id-0-url": u"http://example.com/podcast.mp3",
    6971            "generic_inline_admin-media-content_type-object_id-1-id": u"",
    7072            "generic_inline_admin-media-content_type-object_id-1-url": u"",
    7173        }
    72         response = self.client.post('/generic_inline_admin/admin/generic_inline_admin/episode/1/', post_data)
     74        url = '/generic_inline_admin/admin/generic_inline_admin/episode/%d/' % self.episode_pk
     75        response = self.client.post(url, post_data)
    7376        self.failUnlessEqual(response.status_code, 302) # redirect somewhere
  • tests/regressiontests/comment_tests/tests/moderation_view_tests.py

     
    88
    99    def testFlagGet(self):
    1010        """GET the flag view: render a confirmation page."""
    11         self.createSomeComments()
     11        comments = self.createSomeComments()
     12        pk = comments[0].pk
    1213        self.client.login(username="normaluser", password="normaluser")
    13         response = self.client.get("/flag/1/")
     14        response = self.client.get("/flag/%d/" % pk)
    1415        self.assertTemplateUsed(response, "comments/flag.html")
    1516
    1617    def testFlagPost(self):
    1718        """POST the flag view: actually flag the view (nice for XHR)"""
    18         self.createSomeComments()
     19        comments = self.createSomeComments()
     20        pk = comments[0].pk
    1921        self.client.login(username="normaluser", password="normaluser")
    20         response = self.client.post("/flag/1/")
    21         self.assertEqual(response["Location"], "http://testserver/flagged/?c=1")
    22         c = Comment.objects.get(pk=1)
     22        response = self.client.post("/flag/%d/" % pk)
     23        self.assertEqual(response["Location"], "http://testserver/flagged/?c=%d" % pk)
     24        c = Comment.objects.get(pk=pk)
    2325        self.assertEqual(c.flags.filter(flag=CommentFlag.SUGGEST_REMOVAL).count(), 1)
    2426        return c
    2527
    2628    def testFlagPostTwice(self):
    2729        """Users don't get to flag comments more than once."""
    2830        c = self.testFlagPost()
    29         self.client.post("/flag/1/")
    30         self.client.post("/flag/1/")
     31        self.client.post("/flag/%d/" % c.pk)
     32        self.client.post("/flag/%d/" % c.pk)
    3133        self.assertEqual(c.flags.filter(flag=CommentFlag.SUGGEST_REMOVAL).count(), 1)
    3234
    3335    def testFlagAnon(self):
    3436        """GET/POST the flag view while not logged in: redirect to log in."""
    35         self.createSomeComments()
    36         response = self.client.get("/flag/1/")
    37         self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/flag/1/")
    38         response = self.client.post("/flag/1/")
    39         self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/flag/1/")
     37        comments = self.createSomeComments()
     38        pk = comments[0].pk       
     39        response = self.client.get("/flag/%d/" % pk)
     40        self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/flag/%d/" % pk)
     41        response = self.client.post("/flag/%d/" % pk)
     42        self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/flag/%d/" % pk)
    4043
    4144    def testFlaggedView(self):
    42         self.createSomeComments()
    43         response = self.client.get("/flagged/", data={"c":1})
     45        comments = self.createSomeComments()
     46        pk = comments[0].pk       
     47        response = self.client.get("/flagged/", data={"c":pk})
    4448        self.assertTemplateUsed(response, "comments/flagged.html")
    4549
    4650    def testFlagSignals(self):
     
    7074
    7175    def testDeletePermissions(self):
    7276        """The delete view should only be accessible to 'moderators'"""
    73         self.createSomeComments()
     77        comments = self.createSomeComments()
     78        pk = comments[0].pk       
    7479        self.client.login(username="normaluser", password="normaluser")
    75         response = self.client.get("/delete/1/")
    76         self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/delete/1/")
     80        response = self.client.get("/delete/%d/" % pk)
     81        self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/delete/%d/" % pk)
    7782
    7883        makeModerator("normaluser")
    79         response = self.client.get("/delete/1/")
     84        response = self.client.get("/delete/%d/" % pk)
    8085        self.assertEqual(response.status_code, 200)
    8186
    8287    def testDeletePost(self):
    8388        """POSTing the delete view should mark the comment as removed"""
    84         self.createSomeComments()
     89        comments = self.createSomeComments()
     90        pk = comments[0].pk
    8591        makeModerator("normaluser")
    8692        self.client.login(username="normaluser", password="normaluser")
    87         response = self.client.post("/delete/1/")
    88         self.assertEqual(response["Location"], "http://testserver/deleted/?c=1")
    89         c = Comment.objects.get(pk=1)
     93        response = self.client.post("/delete/%d/" % pk)
     94        self.assertEqual(response["Location"], "http://testserver/deleted/?c=%d" % pk)
     95        c = Comment.objects.get(pk=pk)
    9096        self.failUnless(c.is_removed)
    9197        self.assertEqual(c.flags.filter(flag=CommentFlag.MODERATOR_DELETION, user__username="normaluser").count(), 1)
    9298
     
    103109        self.assertEqual(received_signals, [signals.comment_was_flagged])
    104110
    105111    def testDeletedView(self):
    106         self.createSomeComments()
    107         response = self.client.get("/deleted/", data={"c":1})
     112        comments = self.createSomeComments()
     113        pk = comments[0].pk       
     114        response = self.client.get("/deleted/", data={"c":pk})
    108115        self.assertTemplateUsed(response, "comments/deleted.html")
    109116
    110117class ApproveViewTests(CommentTestCase):
    111118
    112119    def testApprovePermissions(self):
    113120        """The delete view should only be accessible to 'moderators'"""
    114         self.createSomeComments()
     121        comments = self.createSomeComments()
     122        pk = comments[0].pk       
    115123        self.client.login(username="normaluser", password="normaluser")
    116         response = self.client.get("/approve/1/")
    117         self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/approve/1/")
     124        response = self.client.get("/approve/%d/" % pk)
     125        self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/approve/%d/" % pk)
    118126
    119127        makeModerator("normaluser")
    120         response = self.client.get("/approve/1/")
     128        response = self.client.get("/approve/%d/" % pk)
    121129        self.assertEqual(response.status_code, 200)
    122130
    123131    def testApprovePost(self):
     
    127135
    128136        makeModerator("normaluser")
    129137        self.client.login(username="normaluser", password="normaluser")
    130         response = self.client.post("/approve/1/")
    131         self.assertEqual(response["Location"], "http://testserver/approved/?c=1")
    132         c = Comment.objects.get(pk=1)
     138        response = self.client.post("/approve/%d/" % c1.pk)
     139        self.assertEqual(response["Location"], "http://testserver/approved/?c=%d" % c1.pk)
     140        c = Comment.objects.get(pk=c1.pk)
    133141        self.failUnless(c.is_public)
    134142        self.assertEqual(c.flags.filter(flag=CommentFlag.MODERATOR_APPROVAL, user__username="normaluser").count(), 1)
    135143
     
    146154        self.assertEqual(received_signals, [signals.comment_was_flagged])
    147155
    148156    def testApprovedView(self):
    149         self.createSomeComments()
    150         response = self.client.get("/approved/", data={"c":1})
     157        comments = self.createSomeComments()
     158        pk = comments[0].pk       
     159        response = self.client.get("/approved/", data={"c":pk})
    151160        self.assertTemplateUsed(response, "comments/approved.html")
    152161
    153162
  • tests/regressiontests/comment_tests/tests/comment_view_tests.py

     
     1import re
    12from django.conf import settings
    23from django.contrib.auth.models import User
    34from django.contrib.comments import signals
     
    56from regressiontests.comment_tests.models import Article
    67from regressiontests.comment_tests.tests import CommentTestCase
    78
     9post_redirect_re = re.compile(r'^http://testserver/posted/\?c=(?P<pk>\d+$)')
     10
    811class CommentViewTests(CommentTestCase):
    912
    1013    def testPostCommentHTTPMethods(self):
     
    181184        a = Article.objects.get(pk=1)
    182185        data = self.getValidData(a)
    183186        response = self.client.post("/post/", data)
    184         self.assertEqual(response["Location"], "http://testserver/posted/?c=1")
    185 
     187        location = response["Location"]
     188        match = post_redirect_re.match(location)
     189        self.failUnless(match != None, "Unexpected redirect location: %s" % location)
     190       
    186191        data["next"] = "/somewhere/else/"
    187192        data["comment"] = "This is another comment"
    188193        response = self.client.post("/post/", data)
    189         self.assertEqual(response["Location"], "http://testserver/somewhere/else/?c=2")
     194        location = response["Location"]       
     195        match = re.search(r"^http://testserver/somewhere/else/\?c=\d+$", location)
     196        self.failUnless(match != None, "Unexpected redirect location: %s" % location)
    190197
    191198    def testCommentDoneView(self):
    192199        a = Article.objects.get(pk=1)
    193200        data = self.getValidData(a)
    194201        response = self.client.post("/post/", data)
    195         response = self.client.get("/posted/", {'c':1})
     202        location = response["Location"]       
     203        match = post_redirect_re.match(location)
     204        self.failUnless(match != None, "Unexpected redirect location: %s" % location)
     205        pk = int(match.group('pk'))
     206        response = self.client.get(location)
    196207        self.assertTemplateUsed(response, "comments/posted.html")
    197         self.assertEqual(response.context[0]["comment"], Comment.objects.get(pk=1))
     208        self.assertEqual(response.context[0]["comment"], Comment.objects.get(pk=pk))
    198209
Back to Top