Ticket #16401: restore_cache_during_tests.diff
File restore_cache_during_tests.diff, 14.8 KB (added by , 13 years ago) |
---|
-
django/core/cache/backends/dummy.py
diff --git a/django/core/cache/backends/dummy.py b/django/core/cache/backends/dummy.py index af8b62c..ca09547 100644
a b class DummyCache(BaseCache): 32 32 self.validate_key(key) 33 33 return False 34 34 35 def set_many(self, data, version=None):35 def set_many(self, data, timeout=None, version=None): 36 36 pass 37 37 38 38 def delete_many(self, keys, version=None): -
django/test/testcases.py
diff --git a/django/test/testcases.py b/django/test/testcases.py index 02717ff..634fb09 100644
a b from django.db import (transaction, connection, connections, DEFAULT_DB_ALIAS, 16 16 from django.http import QueryDict 17 17 from django.test import _doctest as doctest 18 18 from django.test.client import Client 19 from django.test.utils import get_warnings_state, restore_warnings_state, override_settings 19 from django.test.utils import get_warnings_state, restore_warnings_state, override_settings, _caches_used_during_test 20 20 from django.utils import simplejson, unittest as ut2 21 21 from django.utils.encoding import smart_str 22 22 … … class TransactionTestCase(ut2.TestCase): 251 251 ROOT_URLCONF with it. 252 252 * Clearing the mail test outbox. 253 253 """ 254 self._cache_setup() 254 255 self._fixture_setup() 255 256 self._urlconf_setup() 256 257 mail.outbox = [] … … class TransactionTestCase(ut2.TestCase): 276 277 settings.ROOT_URLCONF = self.urls 277 278 clear_url_caches() 278 279 280 def _cache_setup(self): 281 """ 282 Resets the list of caches used in preparation for test 283 """ 284 global _caches_used_during_test 285 _caches_used_during_test.clear() 286 279 287 def __call__(self, result=None): 280 288 """ 281 289 Wrapper around default __call__ method to perform common Django test … … class TransactionTestCase(ut2.TestCase): 315 323 """ 316 324 self._fixture_teardown() 317 325 self._urlconf_teardown() 326 self._cache_teardown() 318 327 # Some DB cursors include SQL statements as part of cursor 319 328 # creation. If you have a test that does rollback, the effect 320 329 # of these statements is lost, which can effect the operation … … class TransactionTestCase(ut2.TestCase): 332 341 if hasattr(self, '_old_root_urlconf'): 333 342 settings.ROOT_URLCONF = self._old_root_urlconf 334 343 clear_url_caches() 344 345 def _cache_teardown(self): 346 """ 347 Clears values set in cache during test 348 """ 349 for cache in _caches_used_during_test: 350 cache.delete_many(list(cache._keys_set_during_test)) 335 351 336 352 def save_warnings_state(self): 337 353 """ -
django/test/utils.py
diff --git a/django/test/utils.py b/django/test/utils.py index 19a3190..47ce559 100644
a b from __future__ import with_statement 2 2 3 3 import sys 4 4 import time 5 import types 5 6 import os 6 7 import warnings 7 8 from django.conf import settings, UserSettingsHolder 8 from django.core import mail 9 from django.core import mail, cache 9 10 from django.core.mail.backends import locmem 10 11 from django.test.signals import template_rendered, setting_changed 11 12 from django.template import Template, loader, TemplateDoesNotExist … … def instrumented_test_render(self, context): 66 67 return self.nodelist.render(context) 67 68 68 69 70 _caches_used_during_test = set() 71 72 def modified_get_cache(backend, **kwargs): 73 """ 74 Modifies the original get_cache so that we can track any keys set during a cache run and reset 75 them at the end. 76 """ 77 requested_cache = cache.original_get_cache(backend, **kwargs) 78 79 # Add '_test_' to key_prefix to ensure pre-existing cache values don't get touched 80 requested_cache.original_key_prefix = requested_cache.key_prefix 81 requested_cache.key_prefix = '_test_%s' % requested_cache.original_key_prefix 82 83 # Keep track of which caches we use during a test 84 global _caches_used_during_test 85 _caches_used_during_test.add(requested_cache) 86 87 requested_cache._keys_set_during_test = set() 88 89 # Modify cache.set() to collect keys in _keys_set_during_test 90 requested_cache.original_set = requested_cache.set 91 def modified_set(self, key, value, timeout=None, version=None): 92 requested_cache._keys_set_during_test.add(key) 93 requested_cache.original_set(key, value, timeout, version) 94 requested_cache.set = types.MethodType(modified_set, requested_cache) 95 96 # Modify cache.add() to collect keys in _keys_set_during_test 97 requested_cache.original_add = requested_cache.add 98 def modified_add(self, key, value, timeout=None, version=None): 99 requested_cache._keys_set_during_test.add(key) 100 return requested_cache.original_add(key, value, timeout, version) 101 requested_cache.add = types.MethodType(modified_add, requested_cache) 102 103 # Modify cache.incr() to collect keys in _keys_set_during_test 104 requested_cache.original_incr = requested_cache.incr 105 def modified_incr(self, key, delta=1, version=None): 106 requested_cache._keys_set_during_test.add(key) 107 return requested_cache.original_incr(key, delta, version) 108 requested_cache.incr = types.MethodType(modified_incr, requested_cache) 109 110 # Modify cache.decr() to collect keys in _keys_set_during_test 111 requested_cache.original_decr = requested_cache.decr 112 def modified_decr(self, key, delta=1, version=None): 113 requested_cache._keys_set_during_test.add(key) 114 return requested_cache.original_decr(key, delta, version) 115 requested_cache.decr = types.MethodType(modified_decr, requested_cache) 116 117 # Modify cache.set_many() to collect keys in _keys_set_during_test 118 requested_cache.original_set_many = requested_cache.set_many 119 def modified_set_many(self, data, timeout=None, version=None): 120 requested_cache._keys_set_during_test.update(data.keys()) 121 requested_cache.original_set_many(data, timeout, version) 122 requested_cache.set_many = types.MethodType(modified_set_many, requested_cache) 123 124 return requested_cache 125 126 69 127 def setup_test_environment(): 70 128 """Perform any global pre-test setup. This involves: 71 129 … … def setup_test_environment(): 78 136 79 137 mail.original_email_backend = settings.EMAIL_BACKEND 80 138 settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' 81 82 139 mail.outbox = [] 140 141 cache.original_get_cache = cache.get_cache 142 cache.get_cache = modified_get_cache 143 144 # Make sure django.core.cache.cache also uses the modified cache 145 cache.original_cache = cache.cache 146 cache.cache = cache.get_cache(cache.DEFAULT_CACHE_ALIAS) 83 147 84 148 deactivate() 85 149 … … def teardown_test_environment(): 96 160 97 161 settings.EMAIL_BACKEND = mail.original_email_backend 98 162 del mail.original_email_backend 99 100 163 del mail.outbox 164 165 cache.cache = cache.original_cache 166 del cache.original_cache 167 cache.get_cache = cache.original_get_cache 168 del cache.original_get_cache 101 169 102 170 103 171 def get_warnings_state(): -
tests/regressiontests/test_utils/tests.py
diff --git a/tests/regressiontests/test_utils/tests.py b/tests/regressiontests/test_utils/tests.py index 673295b..6734cad 100644
a b 1 1 from __future__ import with_statement 2 2 3 3 import sys 4 import tempfile 4 5 5 6 from django.test import TestCase, skipUnlessDBFeature, skipIfDBFeature 6 from django.utils.unittest import skip 7 from django.utils.unittest import skip, skipUnless 8 from django.conf import settings 9 from django.core import management 10 from django.core.cache import get_cache, DEFAULT_CACHE_ALIAS 7 11 8 12 from models import Person 9 13 … … class SkippingExtraTests(TestCase): 131 135 pass 132 136 133 137 138 # We must set this via a function to confirm that cache set test has run 139 # before cache get test 140 _cache_set_test_has_run = False 141 142 def cache_set_test_run(): 143 global _cache_set_test_has_run 144 _cache_set_test_has_run = True 145 146 def cache_get_test_finished(): 147 global _cache_set_test_has_run 148 _cache_set_test_has_run = False 149 150 151 class BaseCacheReset(TestCase): 152 @classmethod 153 def setUpClass(cls): 154 # Setup everything here, because setupClass is guaranteed to run first 155 cache = cls.original_cache() 156 157 # Add a "pre-existing" value to cache to ensure it gets reset properly 158 cache.set('salt', 'pepper') # We won't touch this one 159 cache.set('sweet', 'sour') # We will touch a key with this name and check if it's restored at the end 160 161 # Sanity checks 162 assert cache.get('salt') == 'pepper' 163 assert cache.get('sweet') == 'sour' 164 165 # We manually prefix the test_ here because we are not trying to pretend these are part 166 # of the original cache. We're just making sure the values exist so that we can call incr/decr 167 # without using cache.set() first 168 cache.orig_key_prefix = cache.key_prefix 169 cache.key_prefix = '_test_%s' % cache.orig_key_prefix 170 try: 171 cache.set('going_up', 1) 172 cache.set('going_down', 2) 173 finally: 174 cache.key_prefix = cache.orig_key_prefix 175 176 def setUp(self): 177 # Set up cache again at the instance level. This one will get reset 178 self.cache = self.modified_cache() 179 180 181 class CacheResetTestsMixin(object): 182 # Note test names start with a/b. This ensures test order is correct (which we're normally 183 # not supposed to worry about) 184 def test_a_set_cache_in_various_ways_in_one_test_method(self): 185 """ 186 Set some cache stuff in this method, and then we'll sure it doesn't carry over to the next 187 """ 188 sweet_result = self.cache.set('sweet', 'bitter') 189 left_result = self.cache.set('left', 'right') 190 loud_result = self.cache.add('loud', 'quiet') 191 192 assert self.cache.get('going_up') == 1 193 going_up_result = self.cache.incr('going_up') 194 195 assert self.cache.get('going_down') == 2 196 going_down_result = self.cache.decr('going_down') 197 198 over_above_result = self.cache.set_many({'over': 'under', 'above': 'below'}) 199 200 # Sanity checks 201 self.assertEqual(self.cache.get('sweet'), 'bitter') 202 self.assertEqual(sweet_result, None) 203 204 self.assertEqual(self.cache.get('left'), 'right') 205 self.assertEqual(left_result, None) 206 207 self.assertEqual(self.cache.get('loud'), 'quiet') 208 self.assertEqual(loud_result, True) 209 210 self.assertEqual(self.cache.get('going_up'), 2) 211 self.assertEqual(going_up_result, 2) 212 213 self.assertEqual(self.cache.get('going_down'), 1) 214 self.assertEqual(going_down_result, 1) 215 216 self.assertEqual(self.cache.get('over'), 'under') 217 self.assertEqual(self.cache.get('above'), 'below') 218 self.assertEqual(over_above_result, None) 219 220 # Mark that set_cache tests have run 221 cache_set_test_run() 222 223 def test_b_get_cache_in_another_test_method(self): 224 # Confirm that set tests has already run 225 if not _cache_set_test_has_run: 226 self.skipTest("set_cache test did not run first!") 227 228 try: 229 self.assertEqual(self.cache.get('left'), None) 230 self.assertEqual(self.cache.get('loud'), None) 231 self.assertEqual(self.cache.get('going_up'), None) 232 self.assertEqual(self.cache.get('going_down'), None) 233 self.assertEqual(self.cache.get('over'), None) 234 self.assertEqual(self.cache.get('above'), None) 235 236 # Make sure pre-existing values are still correct 237 original_cache = self.__class__.original_cache() 238 self.assertEqual(original_cache.get('sweet'), 'sour') 239 self.assertEqual(original_cache.get('salt'), 'pepper') 240 finally: 241 # Mark get_cache tests finished 242 cache_get_test_finished() 243 244 245 class LocMemCacheResetTests(BaseCacheReset, CacheResetTestsMixin): 246 backend_name = 'django.core.cache.backends.locmem.LocMemCache' 247 248 @classmethod 249 def original_cache(cls): 250 if not hasattr(cls, '_original_cache'): 251 from django.core.cache import original_get_cache 252 cls._original_cache = original_get_cache(cls.backend_name, LOCATION='test') 253 return cls._original_cache 254 255 def modified_cache(self): 256 return get_cache(self.backend_name, LOCATION='test') 257 258 259 class FileBasedCacheResetTests(BaseCacheReset, CacheResetTestsMixin): 260 backend_name = 'django.core.cache.backends.filebased.FileBasedCache' 261 262 @classmethod 263 def original_cache(cls): 264 if not hasattr(cls, '_original_cache'): 265 cls.cache_dirname = tempfile.mkdtemp() 266 from django.core.cache import original_get_cache 267 cls._original_cache = original_get_cache(cls.backend_name, LOCATION=cls.cache_dirname) 268 return cls._original_cache 269 270 def modified_cache(self): 271 return get_cache(self.backend_name, LOCATION=self.cache_dirname) 272 273 274 class DBCacheResetTests(BaseCacheReset, CacheResetTestsMixin): 275 backend_name = 'django.core.cache.backends.db.DatabaseCache' 276 277 @classmethod 278 def original_cache(cls): 279 if not hasattr(cls, '_original_cache'): 280 cls.cache_table_name = 'test_cache_table' 281 management.call_command('createcachetable', cls.cache_table_name, verbosity=0, interactive=False) 282 from django.core.cache import original_get_cache 283 cls._original_cache = original_get_cache(cls.backend_name, LOCATION=cls.cache_table_name) 284 return cls._original_cache 285 286 def modified_cache(self): 287 return get_cache(self.backend_name, LOCATION=self.cache_table_name) 288 289 @classmethod 290 def tearDownClass(cls): 291 from django.db import connection 292 cursor = connection.cursor() 293 cursor.execute('DROP TABLE %s' % connection.ops.quote_name(cls.cache_table_name)) 294 295 296 @skipUnless(settings.CACHES[DEFAULT_CACHE_ALIAS]['BACKEND'].startswith('django.core.cache.backends.memcached.'), "memcached not available") 297 class MemcachedCacheResetTests(BaseCacheReset, CacheResetTestsMixin): 298 backend_name = 'django.core.cache.backends.memcached.MemcachedCache' 299 300 @classmethod 301 def original_cache(cls): 302 if not hasattr(cls, '_original_cache'): 303 cls.memcached_location = settings.CACHES[DEFAULT_CACHE_ALIAS]['LOCATION'] 304 from django.core.cache import original_get_cache 305 cls._original_cache = original_get_cache(cls.backend_name, LOCATION=cls.memcached_location) 306 return cls._original_cache 307 308 def modified_cache(self): 309 return get_cache(self.backend_name, LOCATION=self.memcached_location) 310 311 134 312 __test__ = {"API_TEST": r""" 135 313 # Some checks of the doctest output normalizer. 136 314 # Standard doctests do fairly