1 # -*- coding: utf-8 -*-
3 # Unit tests for cache framework
4 # Uses whatever cache backend is set in the test settings file.
5 from __future__
import with_statement
, absolute_import
15 from django
.conf
import settings
16 from django
.core
import management
17 from django
.core
.cache
import get_cache
, DEFAULT_CACHE_ALIAS
18 from django
.core
.cache
.backends
.base
import (CacheKeyWarning
,
19 InvalidCacheBackendError
)
20 from django
.db
import router
21 from django
.http
import HttpResponse
, HttpRequest
, QueryDict
22 from django
.middleware
.cache
import (FetchFromCacheMiddleware
,
23 UpdateCacheMiddleware
, CacheMiddleware
)
24 from django
.template
import Template
25 from django
.template
.response
import TemplateResponse
26 from django
.test
import TestCase
, TransactionTestCase
, RequestFactory
27 from django
.test
.utils
import (get_warnings_state
, restore_warnings_state
,
29 from django
.utils
import timezone
, translation
, unittest
30 from django
.utils
.cache
import (patch_vary_headers
, get_cache_key
,
31 learn_cache_key
, patch_cache_control
, patch_response_headers
)
32 from django
.utils
.encoding
import force_unicode
33 from django
.views
.decorators
.cache
import cache_page
35 from .models
import Poll
, expensive_calculation
37 # functions/classes for complex data type tests
46 class DummyCacheTests(unittest
.TestCase
):
47 # The Dummy cache backend doesn't really behave like a test backend,
48 # so it has different test requirements.
49 backend_name
= 'django.core.cache.backends.dummy.DummyCache'
52 self
.cache
= get_cache(self
.backend_name
)
54 def test_simple(self
):
55 "Dummy cache backend ignores cache set calls"
56 self
.cache
.set("key", "value")
57 self
.assertEqual(self
.cache
.get("key"), None)
60 "Add doesn't do anything in dummy cache backend"
61 self
.cache
.add("addkey1", "value")
62 result
= self
.cache
.add("addkey1", "newvalue")
63 self
.assertEqual(result
, True)
64 self
.assertEqual(self
.cache
.get("addkey1"), None)
66 def test_non_existent(self
):
67 "Non-existent keys aren't found in the dummy cache backend"
68 self
.assertEqual(self
.cache
.get("does_not_exist"), None)
69 self
.assertEqual(self
.cache
.get("does_not_exist", "bang!"), "bang!")
71 def test_get_many(self
):
72 "get_many returns nothing for the dummy cache backend"
73 self
.cache
.set('a', 'a')
74 self
.cache
.set('b', 'b')
75 self
.cache
.set('c', 'c')
76 self
.cache
.set('d', 'd')
77 self
.assertEqual(self
.cache
.get_many(['a', 'c', 'd']), {})
78 self
.assertEqual(self
.cache
.get_many(['a', 'b', 'e']), {})
80 def test_delete(self
):
81 "Cache deletion is transparently ignored on the dummy cache backend"
82 self
.cache
.set("key1", "spam")
83 self
.cache
.set("key2", "eggs")
84 self
.assertEqual(self
.cache
.get("key1"), None)
85 self
.cache
.delete("key1")
86 self
.assertEqual(self
.cache
.get("key1"), None)
87 self
.assertEqual(self
.cache
.get("key2"), None)
89 def test_has_key(self
):
90 "The has_key method doesn't ever return True for the dummy cache backend"
91 self
.cache
.set("hello1", "goodbye1")
92 self
.assertEqual(self
.cache
.has_key("hello1"), False)
93 self
.assertEqual(self
.cache
.has_key("goodbye1"), False)
96 "The in operator doesn't ever return True for the dummy cache backend"
97 self
.cache
.set("hello2", "goodbye2")
98 self
.assertEqual("hello2" in self
.cache
, False)
99 self
.assertEqual("goodbye2" in self
.cache
, False)
102 "Dummy cache values can't be incremented"
103 self
.cache
.set('answer', 42)
104 self
.assertRaises(ValueError, self
.cache
.incr
, 'answer')
105 self
.assertRaises(ValueError, self
.cache
.incr
, 'does_not_exist')
108 "Dummy cache values can't be decremented"
109 self
.cache
.set('answer', 42)
110 self
.assertRaises(ValueError, self
.cache
.decr
, 'answer')
111 self
.assertRaises(ValueError, self
.cache
.decr
, 'does_not_exist')
113 def test_data_types(self
):
114 "All data types are ignored equally by the dummy cache"
116 'string' : 'this is a string',
118 'list' : [1, 2, 3, 4],
119 'tuple' : (1, 2, 3, 4),
120 'dict' : {'A': 1, 'B' : 2},
124 self
.cache
.set("stuff", stuff
)
125 self
.assertEqual(self
.cache
.get("stuff"), None)
127 def test_expiration(self
):
128 "Expiration has no effect on the dummy cache"
129 self
.cache
.set('expire1', 'very quickly', 1)
130 self
.cache
.set('expire2', 'very quickly', 1)
131 self
.cache
.set('expire3', 'very quickly', 1)
134 self
.assertEqual(self
.cache
.get("expire1"), None)
136 self
.cache
.add("expire2", "newvalue")
137 self
.assertEqual(self
.cache
.get("expire2"), None)
138 self
.assertEqual(self
.cache
.has_key("expire3"), False)
140 def test_unicode(self
):
141 "Unicode values are ignored by the dummy cache"
143 u
'ascii': u
'ascii_value',
144 u
'unicode_ascii': u
'Iñtërnâtiônàlizætiøn1',
145 u
'Iñtërnâtiônàlizætiøn': u
'Iñtërnâtiônàlizætiøn2',
146 u
'ascii2': {u
'x' : 1 }
148 for (key
, value
) in stuff
.items():
149 self
.cache
.set(key
, value
)
150 self
.assertEqual(self
.cache
.get(key
), None)
152 def test_set_many(self
):
153 "set_many does nothing for the dummy cache backend"
154 self
.cache
.set_many({'a': 1, 'b': 2})
155 self
.cache
.set_many({'a': 1, 'b': 2}, timeout
=2, version
='1')
157 def test_delete_many(self
):
158 "delete_many does nothing for the dummy cache backend"
159 self
.cache
.delete_many(['a', 'b'])
161 def test_clear(self
):
162 "clear does nothing for the dummy cache backend"
165 def test_incr_version(self
):
166 "Dummy cache versions can't be incremented"
167 self
.cache
.set('answer', 42)
168 self
.assertRaises(ValueError, self
.cache
.incr_version
, 'answer')
169 self
.assertRaises(ValueError, self
.cache
.incr_version
, 'does_not_exist')
171 def test_decr_version(self
):
172 "Dummy cache versions can't be decremented"
173 self
.cache
.set('answer', 42)
174 self
.assertRaises(ValueError, self
.cache
.decr_version
, 'answer')
175 self
.assertRaises(ValueError, self
.cache
.decr_version
, 'does_not_exist')
178 class BaseCacheTests(object):
179 # A common set of tests to apply to all cache backends
181 def _get_request_cache(self
, path
):
182 request
= HttpRequest()
184 'SERVER_NAME': 'testserver',
187 request
.path
= request
.path_info
= path
188 request
._cache
_update
_cache
= True
189 request
.method
= 'GET'
192 def test_simple(self
):
193 # Simple cache set/get works
194 self
.cache
.set("key", "value")
195 self
.assertEqual(self
.cache
.get("key"), "value")
198 # A key can be added to a cache
199 self
.cache
.add("addkey1", "value")
200 result
= self
.cache
.add("addkey1", "newvalue")
201 self
.assertEqual(result
, False)
202 self
.assertEqual(self
.cache
.get("addkey1"), "value")
204 def test_prefix(self
):
205 # Test for same cache key conflicts between shared backend
206 self
.cache
.set('somekey', 'value')
208 # should not be set in the prefixed cache
209 self
.assertFalse(self
.prefix_cache
.has_key('somekey'))
211 self
.prefix_cache
.set('somekey', 'value2')
213 self
.assertEqual(self
.cache
.get('somekey'), 'value')
214 self
.assertEqual(self
.prefix_cache
.get('somekey'), 'value2')
216 def test_non_existent(self
):
217 # Non-existent cache keys return as None/default
218 # get with non-existent keys
219 self
.assertEqual(self
.cache
.get("does_not_exist"), None)
220 self
.assertEqual(self
.cache
.get("does_not_exist", "bang!"), "bang!")
222 def test_get_many(self
):
223 # Multiple cache keys can be returned using get_many
224 self
.cache
.set('a', 'a')
225 self
.cache
.set('b', 'b')
226 self
.cache
.set('c', 'c')
227 self
.cache
.set('d', 'd')
228 self
.assertEqual(self
.cache
.get_many(['a', 'c', 'd']), {'a' : 'a', 'c' : 'c', 'd' : 'd'})
229 self
.assertEqual(self
.cache
.get_many(['a', 'b', 'e']), {'a' : 'a', 'b' : 'b'})
231 def test_delete(self
):
232 # Cache keys can be deleted
233 self
.cache
.set("key1", "spam")
234 self
.cache
.set("key2", "eggs")
235 self
.assertEqual(self
.cache
.get("key1"), "spam")
236 self
.cache
.delete("key1")
237 self
.assertEqual(self
.cache
.get("key1"), None)
238 self
.assertEqual(self
.cache
.get("key2"), "eggs")
240 def test_has_key(self
):
241 # The cache can be inspected for cache keys
242 self
.cache
.set("hello1", "goodbye1")
243 self
.assertEqual(self
.cache
.has_key("hello1"), True)
244 self
.assertEqual(self
.cache
.has_key("goodbye1"), False)
247 # The in operator can be used to inspect cache contents
248 self
.cache
.set("hello2", "goodbye2")
249 self
.assertEqual("hello2" in self
.cache
, True)
250 self
.assertEqual("goodbye2" in self
.cache
, False)
253 # Cache values can be incremented
254 self
.cache
.set('answer', 41)
255 self
.assertEqual(self
.cache
.incr('answer'), 42)
256 self
.assertEqual(self
.cache
.get('answer'), 42)
257 self
.assertEqual(self
.cache
.incr('answer', 10), 52)
258 self
.assertEqual(self
.cache
.get('answer'), 52)
259 self
.assertRaises(ValueError, self
.cache
.incr
, 'does_not_exist')
262 # Cache values can be decremented
263 self
.cache
.set('answer', 43)
264 self
.assertEqual(self
.cache
.decr('answer'), 42)
265 self
.assertEqual(self
.cache
.get('answer'), 42)
266 self
.assertEqual(self
.cache
.decr('answer', 10), 32)
267 self
.assertEqual(self
.cache
.get('answer'), 32)
268 self
.assertRaises(ValueError, self
.cache
.decr
, 'does_not_exist')
270 def test_data_types(self
):
271 # Many different data types can be cached
273 'string' : 'this is a string',
275 'list' : [1, 2, 3, 4],
276 'tuple' : (1, 2, 3, 4),
277 'dict' : {'A': 1, 'B' : 2},
281 self
.cache
.set("stuff", stuff
)
282 self
.assertEqual(self
.cache
.get("stuff"), stuff
)
284 def test_cache_read_for_model_instance(self
):
285 # Don't want fields with callable as default to be called on cache read
286 expensive_calculation
.num_runs
= 0
287 Poll
.objects
.all().delete()
288 my_poll
= Poll
.objects
.create(question
="Well?")
289 self
.assertEqual(Poll
.objects
.count(), 1)
290 pub_date
= my_poll
.pub_date
291 self
.cache
.set('question', my_poll
)
292 cached_poll
= self
.cache
.get('question')
293 self
.assertEqual(cached_poll
.pub_date
, pub_date
)
294 # We only want the default expensive calculation run once
295 self
.assertEqual(expensive_calculation
.num_runs
, 1)
297 def test_cache_write_for_model_instance_with_deferred(self
):
298 # Don't want fields with callable as default to be called on cache write
299 expensive_calculation
.num_runs
= 0
300 Poll
.objects
.all().delete()
301 my_poll
= Poll
.objects
.create(question
="What?")
302 self
.assertEqual(expensive_calculation
.num_runs
, 1)
303 defer_qs
= Poll
.objects
.all().defer('question')
304 self
.assertEqual(defer_qs
.count(), 1)
305 self
.assertEqual(expensive_calculation
.num_runs
, 1)
306 self
.cache
.set('deferred_queryset', defer_qs
)
307 # cache set should not re-evaluate default functions
308 self
.assertEqual(expensive_calculation
.num_runs
, 1)
310 def test_cache_read_for_model_instance_with_deferred(self
):
311 # Don't want fields with callable as default to be called on cache read
312 expensive_calculation
.num_runs
= 0
313 Poll
.objects
.all().delete()
314 my_poll
= Poll
.objects
.create(question
="What?")
315 self
.assertEqual(expensive_calculation
.num_runs
, 1)
316 defer_qs
= Poll
.objects
.all().defer('question')
317 self
.assertEqual(defer_qs
.count(), 1)
318 self
.cache
.set('deferred_queryset', defer_qs
)
319 self
.assertEqual(expensive_calculation
.num_runs
, 1)
320 runs_before_cache_read
= expensive_calculation
.num_runs
321 cached_polls
= self
.cache
.get('deferred_queryset')
322 # We only want the default expensive calculation run on creation and set
323 self
.assertEqual(expensive_calculation
.num_runs
, runs_before_cache_read
)
325 def test_expiration(self
):
326 # Cache values can be set to expire
327 self
.cache
.set('expire1', 'very quickly', 1)
328 self
.cache
.set('expire2', 'very quickly', 1)
329 self
.cache
.set('expire3', 'very quickly', 1)
332 self
.assertEqual(self
.cache
.get("expire1"), None)
334 self
.cache
.add("expire2", "newvalue")
335 self
.assertEqual(self
.cache
.get("expire2"), "newvalue")
336 self
.assertEqual(self
.cache
.has_key("expire3"), False)
338 def test_unicode(self
):
339 # Unicode values can be cached
341 u
'ascii': u
'ascii_value',
342 u
'unicode_ascii': u
'Iñtërnâtiônàlizætiøn1',
343 u
'Iñtërnâtiônàlizætiøn': u
'Iñtërnâtiônàlizætiøn2',
344 u
'ascii2': {u
'x' : 1 }
347 for (key
, value
) in stuff
.items():
348 self
.cache
.set(key
, value
)
349 self
.assertEqual(self
.cache
.get(key
), value
)
352 for (key
, value
) in stuff
.items():
353 self
.cache
.delete(key
)
354 self
.cache
.add(key
, value
)
355 self
.assertEqual(self
.cache
.get(key
), value
)
358 for (key
, value
) in stuff
.items():
359 self
.cache
.delete(key
)
360 self
.cache
.set_many(stuff
)
361 for (key
, value
) in stuff
.items():
362 self
.assertEqual(self
.cache
.get(key
), value
)
364 def test_binary_string(self
):
365 # Binary strings should be cacheable
366 from zlib
import compress
, decompress
367 value
= 'value_to_be_compressed'
368 compressed_value
= compress(value
)
371 self
.cache
.set('binary1', compressed_value
)
372 compressed_result
= self
.cache
.get('binary1')
373 self
.assertEqual(compressed_value
, compressed_result
)
374 self
.assertEqual(value
, decompress(compressed_result
))
377 self
.cache
.add('binary1-add', compressed_value
)
378 compressed_result
= self
.cache
.get('binary1-add')
379 self
.assertEqual(compressed_value
, compressed_result
)
380 self
.assertEqual(value
, decompress(compressed_result
))
383 self
.cache
.set_many({'binary1-set_many': compressed_value
})
384 compressed_result
= self
.cache
.get('binary1-set_many')
385 self
.assertEqual(compressed_value
, compressed_result
)
386 self
.assertEqual(value
, decompress(compressed_result
))
388 def test_set_many(self
):
389 # Multiple keys can be set using set_many
390 self
.cache
.set_many({"key1": "spam", "key2": "eggs"})
391 self
.assertEqual(self
.cache
.get("key1"), "spam")
392 self
.assertEqual(self
.cache
.get("key2"), "eggs")
394 def test_set_many_expiration(self
):
395 # set_many takes a second ``timeout`` parameter
396 self
.cache
.set_many({"key1": "spam", "key2": "eggs"}, 1)
398 self
.assertEqual(self
.cache
.get("key1"), None)
399 self
.assertEqual(self
.cache
.get("key2"), None)
401 def test_delete_many(self
):
402 # Multiple keys can be deleted using delete_many
403 self
.cache
.set("key1", "spam")
404 self
.cache
.set("key2", "eggs")
405 self
.cache
.set("key3", "ham")
406 self
.cache
.delete_many(["key1", "key2"])
407 self
.assertEqual(self
.cache
.get("key1"), None)
408 self
.assertEqual(self
.cache
.get("key2"), None)
409 self
.assertEqual(self
.cache
.get("key3"), "ham")
411 def test_clear(self
):
412 # The cache can be emptied using clear
413 self
.cache
.set("key1", "spam")
414 self
.cache
.set("key2", "eggs")
416 self
.assertEqual(self
.cache
.get("key1"), None)
417 self
.assertEqual(self
.cache
.get("key2"), None)
419 def test_long_timeout(self
):
421 Using a timeout greater than 30 days makes memcached think
422 it is an absolute expiration timestamp instead of a relative
423 offset. Test that we honour this convention. Refs #12399.
425 self
.cache
.set('key1', 'eggs', 60*60*24*30 + 1) #30 days + 1 second
426 self
.assertEqual(self
.cache
.get('key1'), 'eggs')
428 self
.cache
.add('key2', 'ham', 60*60*24*30 + 1)
429 self
.assertEqual(self
.cache
.get('key2'), 'ham')
431 self
.cache
.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, 60*60*24*30 + 1)
432 self
.assertEqual(self
.cache
.get('key3'), 'sausage')
433 self
.assertEqual(self
.cache
.get('key4'), 'lobster bisque')
435 def test_float_timeout(self
):
436 # Make sure a timeout given as a float doesn't crash anything.
437 self
.cache
.set("key1", "spam", 100.2)
438 self
.assertEqual(self
.cache
.get("key1"), "spam")
440 def perform_cull_test(self
, initial_count
, final_count
):
441 """This is implemented as a utility method, because only some of the backends
442 implement culling. The culling algorithm also varies slightly, so the final
443 number of entries will vary between backends"""
444 # Create initial cache key entries. This will overflow the cache, causing a cull
445 for i
in range(1, initial_count
):
446 self
.cache
.set('cull%d' % i
, 'value', 1000)
448 # Count how many keys are left in the cache.
449 for i
in range(1, initial_count
):
450 if self
.cache
.has_key('cull%d' % i
):
452 self
.assertEqual(count
, final_count
)
454 def test_invalid_keys(self
):
456 All the builtin backends (except memcached, see below) should warn on
457 keys that would be refused by memcached. This encourages portable
458 caching code without making it too difficult to use production backends
459 with more liberal key rules. Refs #6447.
462 # mimic custom ``make_key`` method being defined since the default will
463 # never show the below warnings
464 def func(key
, *args
):
467 old_func
= self
.cache
.key_func
468 self
.cache
.key_func
= func
469 # On Python 2.6+ we could use the catch_warnings context
470 # manager to test this warning nicely. Since we can't do that
471 # yet, the cleanest option is to temporarily ask for
472 # CacheKeyWarning to be raised as an exception.
473 _warnings_state
= get_warnings_state()
474 warnings
.simplefilter("error", CacheKeyWarning
)
477 # memcached does not allow whitespace or control characters in keys
478 self
.assertRaises(CacheKeyWarning
, self
.cache
.set, 'key with spaces', 'value')
479 # memcached limits key length to 250
480 self
.assertRaises(CacheKeyWarning
, self
.cache
.set, 'a' * 251, 'value')
482 restore_warnings_state(_warnings_state
)
483 self
.cache
.key_func
= old_func
485 def test_cache_versioning_get_set(self
):
486 # set, using default version = 1
487 self
.cache
.set('answer1', 42)
488 self
.assertEqual(self
.cache
.get('answer1'), 42)
489 self
.assertEqual(self
.cache
.get('answer1', version
=1), 42)
490 self
.assertEqual(self
.cache
.get('answer1', version
=2), None)
492 self
.assertEqual(self
.v2_cache
.get('answer1'), None)
493 self
.assertEqual(self
.v2_cache
.get('answer1', version
=1), 42)
494 self
.assertEqual(self
.v2_cache
.get('answer1', version
=2), None)
496 # set, default version = 1, but manually override version = 2
497 self
.cache
.set('answer2', 42, version
=2)
498 self
.assertEqual(self
.cache
.get('answer2'), None)
499 self
.assertEqual(self
.cache
.get('answer2', version
=1), None)
500 self
.assertEqual(self
.cache
.get('answer2', version
=2), 42)
502 self
.assertEqual(self
.v2_cache
.get('answer2'), 42)
503 self
.assertEqual(self
.v2_cache
.get('answer2', version
=1), None)
504 self
.assertEqual(self
.v2_cache
.get('answer2', version
=2), 42)
506 # v2 set, using default version = 2
507 self
.v2_cache
.set('answer3', 42)
508 self
.assertEqual(self
.cache
.get('answer3'), None)
509 self
.assertEqual(self
.cache
.get('answer3', version
=1), None)
510 self
.assertEqual(self
.cache
.get('answer3', version
=2), 42)
512 self
.assertEqual(self
.v2_cache
.get('answer3'), 42)
513 self
.assertEqual(self
.v2_cache
.get('answer3', version
=1), None)
514 self
.assertEqual(self
.v2_cache
.get('answer3', version
=2), 42)
516 # v2 set, default version = 2, but manually override version = 1
517 self
.v2_cache
.set('answer4', 42, version
=1)
518 self
.assertEqual(self
.cache
.get('answer4'), 42)
519 self
.assertEqual(self
.cache
.get('answer4', version
=1), 42)
520 self
.assertEqual(self
.cache
.get('answer4', version
=2), None)
522 self
.assertEqual(self
.v2_cache
.get('answer4'), None)
523 self
.assertEqual(self
.v2_cache
.get('answer4', version
=1), 42)
524 self
.assertEqual(self
.v2_cache
.get('answer4', version
=2), None)
526 def test_cache_versioning_add(self
):
528 # add, default version = 1, but manually override version = 2
529 self
.cache
.add('answer1', 42, version
=2)
530 self
.assertEqual(self
.cache
.get('answer1', version
=1), None)
531 self
.assertEqual(self
.cache
.get('answer1', version
=2), 42)
533 self
.cache
.add('answer1', 37, version
=2)
534 self
.assertEqual(self
.cache
.get('answer1', version
=1), None)
535 self
.assertEqual(self
.cache
.get('answer1', version
=2), 42)
537 self
.cache
.add('answer1', 37, version
=1)
538 self
.assertEqual(self
.cache
.get('answer1', version
=1), 37)
539 self
.assertEqual(self
.cache
.get('answer1', version
=2), 42)
541 # v2 add, using default version = 2
542 self
.v2_cache
.add('answer2', 42)
543 self
.assertEqual(self
.cache
.get('answer2', version
=1), None)
544 self
.assertEqual(self
.cache
.get('answer2', version
=2), 42)
546 self
.v2_cache
.add('answer2', 37)
547 self
.assertEqual(self
.cache
.get('answer2', version
=1), None)
548 self
.assertEqual(self
.cache
.get('answer2', version
=2), 42)
550 self
.v2_cache
.add('answer2', 37, version
=1)
551 self
.assertEqual(self
.cache
.get('answer2', version
=1), 37)
552 self
.assertEqual(self
.cache
.get('answer2', version
=2), 42)
554 # v2 add, default version = 2, but manually override version = 1
555 self
.v2_cache
.add('answer3', 42, version
=1)
556 self
.assertEqual(self
.cache
.get('answer3', version
=1), 42)
557 self
.assertEqual(self
.cache
.get('answer3', version
=2), None)
559 self
.v2_cache
.add('answer3', 37, version
=1)
560 self
.assertEqual(self
.cache
.get('answer3', version
=1), 42)
561 self
.assertEqual(self
.cache
.get('answer3', version
=2), None)
563 self
.v2_cache
.add('answer3', 37)
564 self
.assertEqual(self
.cache
.get('answer3', version
=1), 42)
565 self
.assertEqual(self
.cache
.get('answer3', version
=2), 37)
567 def test_cache_versioning_has_key(self
):
568 self
.cache
.set('answer1', 42)
571 self
.assertTrue(self
.cache
.has_key('answer1'))
572 self
.assertTrue(self
.cache
.has_key('answer1', version
=1))
573 self
.assertFalse(self
.cache
.has_key('answer1', version
=2))
575 self
.assertFalse(self
.v2_cache
.has_key('answer1'))
576 self
.assertTrue(self
.v2_cache
.has_key('answer1', version
=1))
577 self
.assertFalse(self
.v2_cache
.has_key('answer1', version
=2))
579 def test_cache_versioning_delete(self
):
580 self
.cache
.set('answer1', 37, version
=1)
581 self
.cache
.set('answer1', 42, version
=2)
582 self
.cache
.delete('answer1')
583 self
.assertEqual(self
.cache
.get('answer1', version
=1), None)
584 self
.assertEqual(self
.cache
.get('answer1', version
=2), 42)
586 self
.cache
.set('answer2', 37, version
=1)
587 self
.cache
.set('answer2', 42, version
=2)
588 self
.cache
.delete('answer2', version
=2)
589 self
.assertEqual(self
.cache
.get('answer2', version
=1), 37)
590 self
.assertEqual(self
.cache
.get('answer2', version
=2), None)
592 self
.cache
.set('answer3', 37, version
=1)
593 self
.cache
.set('answer3', 42, version
=2)
594 self
.v2_cache
.delete('answer3')
595 self
.assertEqual(self
.cache
.get('answer3', version
=1), 37)
596 self
.assertEqual(self
.cache
.get('answer3', version
=2), None)
598 self
.cache
.set('answer4', 37, version
=1)
599 self
.cache
.set('answer4', 42, version
=2)
600 self
.v2_cache
.delete('answer4', version
=1)
601 self
.assertEqual(self
.cache
.get('answer4', version
=1), None)
602 self
.assertEqual(self
.cache
.get('answer4', version
=2), 42)
604 def test_cache_versioning_incr_decr(self
):
605 self
.cache
.set('answer1', 37, version
=1)
606 self
.cache
.set('answer1', 42, version
=2)
607 self
.cache
.incr('answer1')
608 self
.assertEqual(self
.cache
.get('answer1', version
=1), 38)
609 self
.assertEqual(self
.cache
.get('answer1', version
=2), 42)
610 self
.cache
.decr('answer1')
611 self
.assertEqual(self
.cache
.get('answer1', version
=1), 37)
612 self
.assertEqual(self
.cache
.get('answer1', version
=2), 42)
614 self
.cache
.set('answer2', 37, version
=1)
615 self
.cache
.set('answer2', 42, version
=2)
616 self
.cache
.incr('answer2', version
=2)
617 self
.assertEqual(self
.cache
.get('answer2', version
=1), 37)
618 self
.assertEqual(self
.cache
.get('answer2', version
=2), 43)
619 self
.cache
.decr('answer2', version
=2)
620 self
.assertEqual(self
.cache
.get('answer2', version
=1), 37)
621 self
.assertEqual(self
.cache
.get('answer2', version
=2), 42)
623 self
.cache
.set('answer3', 37, version
=1)
624 self
.cache
.set('answer3', 42, version
=2)
625 self
.v2_cache
.incr('answer3')
626 self
.assertEqual(self
.cache
.get('answer3', version
=1), 37)
627 self
.assertEqual(self
.cache
.get('answer3', version
=2), 43)
628 self
.v2_cache
.decr('answer3')
629 self
.assertEqual(self
.cache
.get('answer3', version
=1), 37)
630 self
.assertEqual(self
.cache
.get('answer3', version
=2), 42)
632 self
.cache
.set('answer4', 37, version
=1)
633 self
.cache
.set('answer4', 42, version
=2)
634 self
.v2_cache
.incr('answer4', version
=1)
635 self
.assertEqual(self
.cache
.get('answer4', version
=1), 38)
636 self
.assertEqual(self
.cache
.get('answer4', version
=2), 42)
637 self
.v2_cache
.decr('answer4', version
=1)
638 self
.assertEqual(self
.cache
.get('answer4', version
=1), 37)
639 self
.assertEqual(self
.cache
.get('answer4', version
=2), 42)
641 def test_cache_versioning_get_set_many(self
):
642 # set, using default version = 1
643 self
.cache
.set_many({'ford1': 37, 'arthur1': 42})
644 self
.assertEqual(self
.cache
.get_many(['ford1','arthur1']),
645 {'ford1': 37, 'arthur1': 42})
646 self
.assertEqual(self
.cache
.get_many(['ford1','arthur1'], version
=1),
647 {'ford1': 37, 'arthur1': 42})
648 self
.assertEqual(self
.cache
.get_many(['ford1','arthur1'], version
=2), {})
650 self
.assertEqual(self
.v2_cache
.get_many(['ford1','arthur1']), {})
651 self
.assertEqual(self
.v2_cache
.get_many(['ford1','arthur1'], version
=1),
652 {'ford1': 37, 'arthur1': 42})
653 self
.assertEqual(self
.v2_cache
.get_many(['ford1','arthur1'], version
=2), {})
655 # set, default version = 1, but manually override version = 2
656 self
.cache
.set_many({'ford2': 37, 'arthur2': 42}, version
=2)
657 self
.assertEqual(self
.cache
.get_many(['ford2','arthur2']), {})
658 self
.assertEqual(self
.cache
.get_many(['ford2','arthur2'], version
=1), {})
659 self
.assertEqual(self
.cache
.get_many(['ford2','arthur2'], version
=2),
660 {'ford2': 37, 'arthur2': 42})
662 self
.assertEqual(self
.v2_cache
.get_many(['ford2','arthur2']),
663 {'ford2': 37, 'arthur2': 42})
664 self
.assertEqual(self
.v2_cache
.get_many(['ford2','arthur2'], version
=1), {})
665 self
.assertEqual(self
.v2_cache
.get_many(['ford2','arthur2'], version
=2),
666 {'ford2': 37, 'arthur2': 42})
668 # v2 set, using default version = 2
669 self
.v2_cache
.set_many({'ford3': 37, 'arthur3': 42})
670 self
.assertEqual(self
.cache
.get_many(['ford3','arthur3']), {})
671 self
.assertEqual(self
.cache
.get_many(['ford3','arthur3'], version
=1), {})
672 self
.assertEqual(self
.cache
.get_many(['ford3','arthur3'], version
=2),
673 {'ford3': 37, 'arthur3': 42})
675 self
.assertEqual(self
.v2_cache
.get_many(['ford3','arthur3']),
676 {'ford3': 37, 'arthur3': 42})
677 self
.assertEqual(self
.v2_cache
.get_many(['ford3','arthur3'], version
=1), {})
678 self
.assertEqual(self
.v2_cache
.get_many(['ford3','arthur3'], version
=2),
679 {'ford3': 37, 'arthur3': 42})
681 # v2 set, default version = 2, but manually override version = 1
682 self
.v2_cache
.set_many({'ford4': 37, 'arthur4': 42}, version
=1)
683 self
.assertEqual(self
.cache
.get_many(['ford4','arthur4']),
684 {'ford4': 37, 'arthur4': 42})
685 self
.assertEqual(self
.cache
.get_many(['ford4','arthur4'], version
=1),
686 {'ford4': 37, 'arthur4': 42})
687 self
.assertEqual(self
.cache
.get_many(['ford4','arthur4'], version
=2), {})
689 self
.assertEqual(self
.v2_cache
.get_many(['ford4','arthur4']), {})
690 self
.assertEqual(self
.v2_cache
.get_many(['ford4','arthur4'], version
=1),
691 {'ford4': 37, 'arthur4': 42})
692 self
.assertEqual(self
.v2_cache
.get_many(['ford4','arthur4'], version
=2), {})
694 def test_incr_version(self
):
695 self
.cache
.set('answer', 42, version
=2)
696 self
.assertEqual(self
.cache
.get('answer'), None)
697 self
.assertEqual(self
.cache
.get('answer', version
=1), None)
698 self
.assertEqual(self
.cache
.get('answer', version
=2), 42)
699 self
.assertEqual(self
.cache
.get('answer', version
=3), None)
701 self
.assertEqual(self
.cache
.incr_version('answer', version
=2), 3)
702 self
.assertEqual(self
.cache
.get('answer'), None)
703 self
.assertEqual(self
.cache
.get('answer', version
=1), None)
704 self
.assertEqual(self
.cache
.get('answer', version
=2), None)
705 self
.assertEqual(self
.cache
.get('answer', version
=3), 42)
707 self
.v2_cache
.set('answer2', 42)
708 self
.assertEqual(self
.v2_cache
.get('answer2'), 42)
709 self
.assertEqual(self
.v2_cache
.get('answer2', version
=1), None)
710 self
.assertEqual(self
.v2_cache
.get('answer2', version
=2), 42)
711 self
.assertEqual(self
.v2_cache
.get('answer2', version
=3), None)
713 self
.assertEqual(self
.v2_cache
.incr_version('answer2'), 3)
714 self
.assertEqual(self
.v2_cache
.get('answer2'), None)
715 self
.assertEqual(self
.v2_cache
.get('answer2', version
=1), None)
716 self
.assertEqual(self
.v2_cache
.get('answer2', version
=2), None)
717 self
.assertEqual(self
.v2_cache
.get('answer2', version
=3), 42)
719 self
.assertRaises(ValueError, self
.cache
.incr_version
, 'does_not_exist')
721 def test_decr_version(self
):
722 self
.cache
.set('answer', 42, version
=2)
723 self
.assertEqual(self
.cache
.get('answer'), None)
724 self
.assertEqual(self
.cache
.get('answer', version
=1), None)
725 self
.assertEqual(self
.cache
.get('answer', version
=2), 42)
727 self
.assertEqual(self
.cache
.decr_version('answer', version
=2), 1)
728 self
.assertEqual(self
.cache
.get('answer'), 42)
729 self
.assertEqual(self
.cache
.get('answer', version
=1), 42)
730 self
.assertEqual(self
.cache
.get('answer', version
=2), None)
732 self
.v2_cache
.set('answer2', 42)
733 self
.assertEqual(self
.v2_cache
.get('answer2'), 42)
734 self
.assertEqual(self
.v2_cache
.get('answer2', version
=1), None)
735 self
.assertEqual(self
.v2_cache
.get('answer2', version
=2), 42)
737 self
.assertEqual(self
.v2_cache
.decr_version('answer2'), 1)
738 self
.assertEqual(self
.v2_cache
.get('answer2'), None)
739 self
.assertEqual(self
.v2_cache
.get('answer2', version
=1), 42)
740 self
.assertEqual(self
.v2_cache
.get('answer2', version
=2), None)
742 self
.assertRaises(ValueError, self
.cache
.decr_version
, 'does_not_exist', version
=2)
744 def test_custom_key_func(self
):
745 # Two caches with different key functions aren't visible to each other
746 self
.cache
.set('answer1', 42)
747 self
.assertEqual(self
.cache
.get('answer1'), 42)
748 self
.assertEqual(self
.custom_key_cache
.get('answer1'), None)
749 self
.assertEqual(self
.custom_key_cache2
.get('answer1'), None)
751 self
.custom_key_cache
.set('answer2', 42)
752 self
.assertEqual(self
.cache
.get('answer2'), None)
753 self
.assertEqual(self
.custom_key_cache
.get('answer2'), 42)
754 self
.assertEqual(self
.custom_key_cache2
.get('answer2'), 42)
757 def test_cache_write_unpickable_object(self
):
758 update_middleware
= UpdateCacheMiddleware()
759 update_middleware
.cache
= self
.cache
761 fetch_middleware
= FetchFromCacheMiddleware()
762 fetch_middleware
.cache
= self
.cache
764 request
= self
._get
_request
_cache
('/cache/test')
765 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
766 self
.assertEqual(get_cache_data
, None)
768 response
= HttpResponse()
769 content
= 'Testing cookie serialization.'
770 response
.content
= content
771 response
.set_cookie('foo', 'bar')
773 update_middleware
.process_response(request
, response
)
775 get_cache_data
= fetch_middleware
.process_request(request
)
776 self
.assertNotEqual(get_cache_data
, None)
777 self
.assertEqual(get_cache_data
.content
, content
)
778 self
.assertEqual(get_cache_data
.cookies
, response
.cookies
)
780 update_middleware
.process_response(request
, get_cache_data
)
781 get_cache_data
= fetch_middleware
.process_request(request
)
782 self
.assertNotEqual(get_cache_data
, None)
783 self
.assertEqual(get_cache_data
.content
, content
)
784 self
.assertEqual(get_cache_data
.cookies
, response
.cookies
)
786 def custom_key_func(key
, key_prefix
, version
):
787 "A customized cache key function"
788 return 'CUSTOM-' + '-'.join([key_prefix
, str(version
), key
])
791 class DBCacheTests(BaseCacheTests
, TransactionTestCase
):
792 backend_name
= 'django.core.cache.backends.db.DatabaseCache'
795 # Spaces are used in the table name to ensure quoting/escaping is working
796 self
._table
_name
= 'test cache table'
797 management
.call_command('createcachetable', self
._table
_name
, verbosity
=0, interactive
=False)
798 self
.cache
= get_cache(self
.backend_name
, LOCATION
=self
._table
_name
, OPTIONS
={'MAX_ENTRIES': 30})
799 self
.prefix_cache
= get_cache(self
.backend_name
, LOCATION
=self
._table
_name
, KEY_PREFIX
='cacheprefix')
800 self
.v2_cache
= get_cache(self
.backend_name
, LOCATION
=self
._table
_name
, VERSION
=2)
801 self
.custom_key_cache
= get_cache(self
.backend_name
, LOCATION
=self
._table
_name
, KEY_FUNCTION
=custom_key_func
)
802 self
.custom_key_cache2
= get_cache(self
.backend_name
, LOCATION
=self
._table
_name
, KEY_FUNCTION
='regressiontests.cache.tests.custom_key_func')
805 from django
.db
import connection
806 cursor
= connection
.cursor()
807 cursor
.execute('DROP TABLE %s' % connection
.ops
.quote_name(self
._table
_name
))
811 self
.perform_cull_test(50, 29)
813 def test_zero_cull(self
):
814 self
.cache
= get_cache(self
.backend_name
, LOCATION
=self
._table
_name
, OPTIONS
={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0})
815 self
.perform_cull_test(50, 18)
817 def test_old_initialization(self
):
818 self
.cache
= get_cache('db://%s?max_entries=30&cull_frequency=0' % self
._table
_name
)
819 self
.perform_cull_test(50, 18)
821 def test_second_call_doesnt_crash(self
):
822 err
= StringIO
.StringIO()
823 management
.call_command('createcachetable', self
._table
_name
, verbosity
=0, interactive
=False, stderr
=err
)
824 self
.assertTrue("Cache table 'test cache table' could not be created" in err
.getvalue())
827 DBCacheWithTimeZoneTests
= override_settings(USE_TZ
=True)(DBCacheTests
)
830 class DBCacheRouter(object):
831 """A router that puts the cache table on the 'other' database."""
833 def db_for_read(self
, model
, **hints
):
834 if model
._meta
.app_label
== 'django_cache':
837 def db_for_write(self
, model
, **hints
):
838 if model
._meta
.app_label
== 'django_cache':
841 def allow_syncdb(self
, db
, model
):
842 if model
._meta
.app_label
== 'django_cache':
846 class CreateCacheTableForDBCacheTests(TestCase
):
849 def test_createcachetable_observes_database_router(self
):
850 old_routers
= router
.routers
852 router
.routers
= [DBCacheRouter()]
853 # cache table should not be created on 'default'
854 with self
.assertNumQueries(0, using
='default'):
855 management
.call_command('createcachetable', 'cache_table',
857 verbosity
=0, interactive
=False)
858 # cache table should be created on 'other'
859 # one query is used to create the table and another one the index
860 with self
.assertNumQueries(2, using
='other'):
861 management
.call_command('createcachetable', 'cache_table',
863 verbosity
=0, interactive
=False)
865 router
.routers
= old_routers
868 class LocMemCacheTests(unittest
.TestCase
, BaseCacheTests
):
869 backend_name
= 'django.core.cache.backends.locmem.LocMemCache'
872 self
.cache
= get_cache(self
.backend_name
, OPTIONS
={'MAX_ENTRIES': 30})
873 self
.prefix_cache
= get_cache(self
.backend_name
, KEY_PREFIX
='cacheprefix')
874 self
.v2_cache
= get_cache(self
.backend_name
, VERSION
=2)
875 self
.custom_key_cache
= get_cache(self
.backend_name
, OPTIONS
={'MAX_ENTRIES': 30}, KEY_FUNCTION
=custom_key_func
)
876 self
.custom_key_cache2
= get_cache(self
.backend_name
, OPTIONS
={'MAX_ENTRIES': 30}, KEY_FUNCTION
='regressiontests.cache.tests.custom_key_func')
878 # LocMem requires a hack to make the other caches
879 # share a data store with the 'normal' cache.
880 self
.prefix_cache
._cache
= self
.cache
._cache
881 self
.prefix_cache
._expire
_info
= self
.cache
._expire
_info
883 self
.v2_cache
._cache
= self
.cache
._cache
884 self
.v2_cache
._expire
_info
= self
.cache
._expire
_info
886 self
.custom_key_cache
._cache
= self
.cache
._cache
887 self
.custom_key_cache
._expire
_info
= self
.cache
._expire
_info
889 self
.custom_key_cache2
._cache
= self
.cache
._cache
890 self
.custom_key_cache2
._expire_info
= self
.cache
._expire
_info
896 self
.perform_cull_test(50, 29)
898 def test_zero_cull(self
):
899 self
.cache
= get_cache(self
.backend_name
, OPTIONS
={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0})
900 self
.perform_cull_test(50, 19)
902 def test_old_initialization(self
):
903 self
.cache
= get_cache('locmem://?max_entries=30&cull_frequency=0')
904 self
.perform_cull_test(50, 19)
906 def test_multiple_caches(self
):
907 "Check that multiple locmem caches are isolated"
908 mirror_cache
= get_cache(self
.backend_name
)
909 other_cache
= get_cache(self
.backend_name
, LOCATION
='other')
911 self
.cache
.set('value1', 42)
912 self
.assertEqual(mirror_cache
.get('value1'), 42)
913 self
.assertEqual(other_cache
.get('value1'), None)
915 def test_incr_decr_timeout(self
):
916 """incr/decr does not modify expiry time (matches memcached behavior)"""
918 _key
= self
.cache
.make_key(key
)
919 self
.cache
.set(key
, 1, timeout
=self
.cache
.default_timeout
*10)
920 expire
= self
.cache
._expire
_info
[_key
]
922 self
.assertEqual(expire
, self
.cache
._expire
_info
[_key
])
924 self
.assertEqual(expire
, self
.cache
._expire
_info
[_key
])
926 # memcached backend isn't guaranteed to be available.
927 # To check the memcached backend, the test settings file will
928 # need to contain a cache backend setting that points at
929 # your memcache server.
930 class MemcachedCacheTests(unittest
.TestCase
, BaseCacheTests
):
931 backend_name
= 'django.core.cache.backends.memcached.MemcachedCache'
934 name
= settings
.CACHES
[DEFAULT_CACHE_ALIAS
]['LOCATION']
935 self
.cache
= get_cache(self
.backend_name
, LOCATION
=name
)
936 self
.prefix_cache
= get_cache(self
.backend_name
, LOCATION
=name
, KEY_PREFIX
='cacheprefix')
937 self
.v2_cache
= get_cache(self
.backend_name
, LOCATION
=name
, VERSION
=2)
938 self
.custom_key_cache
= get_cache(self
.backend_name
, LOCATION
=name
, KEY_FUNCTION
=custom_key_func
)
939 self
.custom_key_cache2
= get_cache(self
.backend_name
, LOCATION
=name
, KEY_FUNCTION
='regressiontests.cache.tests.custom_key_func')
944 def test_invalid_keys(self
):
946 On memcached, we don't introduce a duplicate key validation
947 step (for speed reasons), we just let the memcached API
948 library raise its own exception on bad keys. Refs #6447.
950 In order to be memcached-API-library agnostic, we only assert
951 that a generic exception of some kind is raised.
954 # memcached does not allow whitespace or control characters in keys
955 self
.assertRaises(Exception, self
.cache
.set, 'key with spaces', 'value')
956 # memcached limits key length to 250
957 self
.assertRaises(Exception, self
.cache
.set, 'a' * 251, 'value')
959 MemcachedCacheTests
= unittest
.skipUnless(settings
.CACHES
[DEFAULT_CACHE_ALIAS
]['BACKEND'].startswith('django.core.cache.backends.memcached.'), "memcached not available")(MemcachedCacheTests
)
962 class FileBasedCacheTests(unittest
.TestCase
, BaseCacheTests
):
964 Specific test cases for the file-based cache.
966 backend_name
= 'django.core.cache.backends.filebased.FileBasedCache'
969 self
.dirname
= tempfile
.mkdtemp()
970 self
.cache
= get_cache(self
.backend_name
, LOCATION
=self
.dirname
, OPTIONS
={'MAX_ENTRIES': 30})
971 self
.prefix_cache
= get_cache(self
.backend_name
, LOCATION
=self
.dirname
, KEY_PREFIX
='cacheprefix')
972 self
.v2_cache
= get_cache(self
.backend_name
, LOCATION
=self
.dirname
, VERSION
=2)
973 self
.custom_key_cache
= get_cache(self
.backend_name
, LOCATION
=self
.dirname
, KEY_FUNCTION
=custom_key_func
)
974 self
.custom_key_cache2
= get_cache(self
.backend_name
, LOCATION
=self
.dirname
, KEY_FUNCTION
='regressiontests.cache.tests.custom_key_func')
979 def test_hashing(self
):
980 """Test that keys are hashed into subdirectories correctly"""
981 self
.cache
.set("foo", "bar")
982 key
= self
.cache
.make_key("foo")
983 keyhash
= hashlib
.md5(key
).hexdigest()
984 keypath
= os
.path
.join(self
.dirname
, keyhash
[:2], keyhash
[2:4], keyhash
[4:])
985 self
.assertTrue(os
.path
.exists(keypath
))
987 def test_subdirectory_removal(self
):
989 Make sure that the created subdirectories are correctly removed when empty.
991 self
.cache
.set("foo", "bar")
992 key
= self
.cache
.make_key("foo")
993 keyhash
= hashlib
.md5(key
).hexdigest()
994 keypath
= os
.path
.join(self
.dirname
, keyhash
[:2], keyhash
[2:4], keyhash
[4:])
995 self
.assertTrue(os
.path
.exists(keypath
))
997 self
.cache
.delete("foo")
998 self
.assertTrue(not os
.path
.exists(keypath
))
999 self
.assertTrue(not os
.path
.exists(os
.path
.dirname(keypath
)))
1000 self
.assertTrue(not os
.path
.exists(os
.path
.dirname(os
.path
.dirname(keypath
))))
1002 def test_cull(self
):
1003 self
.perform_cull_test(50, 29)
1005 def test_old_initialization(self
):
1006 self
.cache
= get_cache('file://%s?max_entries=30' % self
.dirname
)
1007 self
.perform_cull_test(50, 29)
1010 class CustomCacheKeyValidationTests(unittest
.TestCase
):
1012 Tests for the ability to mixin a custom ``validate_key`` method to
1013 a custom cache backend that otherwise inherits from a builtin
1014 backend, and override the default key validation. Refs #6447.
1017 def test_custom_key_validation(self
):
1018 cache
= get_cache('regressiontests.cache.liberal_backend://')
1020 # this key is both longer than 250 characters, and has spaces
1021 key
= 'some key with spaces' * 15
1024 self
.assertEqual(cache
.get(key
), val
)
1027 class GetCacheTests(unittest
.TestCase
):
1029 def test_simple(self
):
1030 cache
= get_cache('locmem://')
1031 from django
.core
.cache
.backends
.locmem
import LocMemCache
1032 self
.assertTrue(isinstance(cache
, LocMemCache
))
1034 from django
.core
.cache
import cache
1035 self
.assertTrue(isinstance(cache
, get_cache('default').__class
__))
1038 'django.core.cache.backends.dummy.DummyCache', **{'TIMEOUT': 120})
1039 self
.assertEqual(cache
.default_timeout
, 120)
1041 self
.assertRaises(InvalidCacheBackendError
, get_cache
, 'does_not_exist')
1043 def test_close(self
):
1044 from django
.core
import signals
1045 cache
= get_cache('regressiontests.cache.closeable_cache.CacheClass')
1046 self
.assertFalse(cache
.closed
)
1047 signals
.request_finished
.send(self
.__class
__)
1048 self
.assertTrue(cache
.closed
)
1051 class CacheUtils(TestCase
):
1052 """TestCase for django.utils.cache functions."""
1055 self
.path
= '/cache/test/'
1056 self
.cache
= get_cache('default')
1061 def _get_request(self
, path
, method
='GET'):
1062 request
= HttpRequest()
1064 'SERVER_NAME': 'testserver',
1067 request
.method
= method
1068 request
.path
= request
.path_info
= "/cache/%s" % path
1071 def test_patch_vary_headers(self
):
1073 # Initial vary, new headers, resulting vary.
1074 (None, ('Accept-Encoding',), 'Accept-Encoding'),
1075 ('Accept-Encoding', ('accept-encoding',), 'Accept-Encoding'),
1076 ('Accept-Encoding', ('ACCEPT-ENCODING',), 'Accept-Encoding'),
1077 ('Cookie', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
1078 ('Cookie, Accept-Encoding', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
1079 ('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
1080 (None, ('Accept-Encoding', 'COOKIE'), 'Accept-Encoding, COOKIE'),
1081 ('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
1082 ('Cookie , Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
1084 for initial_vary
, newheaders
, resulting_vary
in headers
:
1085 response
= HttpResponse()
1086 if initial_vary
is not None:
1087 response
['Vary'] = initial_vary
1088 patch_vary_headers(response
, newheaders
)
1089 self
.assertEqual(response
['Vary'], resulting_vary
)
1091 def test_get_cache_key(self
):
1092 request
= self
._get
_request
(self
.path
)
1093 response
= HttpResponse()
1094 key_prefix
= 'localprefix'
1095 # Expect None if no headers have been set yet.
1096 self
.assertEqual(get_cache_key(request
), None)
1097 # Set headers to an empty list.
1098 learn_cache_key(request
, response
)
1099 self
.assertEqual(get_cache_key(request
), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
1100 # Verify that a specified key_prefix is taken into account.
1101 learn_cache_key(request
, response
, key_prefix
=key_prefix
)
1102 self
.assertEqual(get_cache_key(request
, key_prefix
=key_prefix
), 'views.decorators.cache.cache_page.localprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
1104 def test_get_cache_key_with_query(self
):
1105 request
= self
._get
_request
(self
.path
+ '?test=1')
1106 response
= HttpResponse()
1107 # Expect None if no headers have been set yet.
1108 self
.assertEqual(get_cache_key(request
), None)
1109 # Set headers to an empty list.
1110 learn_cache_key(request
, response
)
1111 # Verify that the querystring is taken into account.
1112 self
.assertEqual(get_cache_key(request
), 'views.decorators.cache.cache_page.settingsprefix.GET.bd889c5a59603af44333ed21504db3cd.d41d8cd98f00b204e9800998ecf8427e')
1114 def test_learn_cache_key(self
):
1115 request
= self
._get
_request
(self
.path
, 'HEAD')
1116 response
= HttpResponse()
1117 response
['Vary'] = 'Pony'
1118 # Make sure that the Vary header is added to the key hash
1119 learn_cache_key(request
, response
)
1120 self
.assertEqual(get_cache_key(request
), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
1122 def test_patch_cache_control(self
):
1124 # Initial Cache-Control, kwargs to patch_cache_control, expected Cache-Control parts
1125 (None, {'private' : True}, set(['private'])),
1127 # Test whether private/public attributes are mutually exclusive
1128 ('private', {'private' : True}, set(['private'])),
1129 ('private', {'public' : True}, set(['public'])),
1130 ('public', {'public' : True}, set(['public'])),
1131 ('public', {'private' : True}, set(['private'])),
1132 ('must-revalidate,max-age=60,private', {'public' : True}, set(['must-revalidate', 'max-age=60', 'public'])),
1133 ('must-revalidate,max-age=60,public', {'private' : True}, set(['must-revalidate', 'max-age=60', 'private'])),
1134 ('must-revalidate,max-age=60', {'public' : True}, set(['must-revalidate', 'max-age=60', 'public'])),
1137 cc_delim_re
= re
.compile(r
'\s*,\s*')
1139 for initial_cc
, newheaders
, expected_cc
in tests
:
1140 response
= HttpResponse()
1141 if initial_cc
is not None:
1142 response
['Cache-Control'] = initial_cc
1143 patch_cache_control(response
, **newheaders
)
1144 parts
= set(cc_delim_re
.split(response
['Cache-Control']))
1145 self
.assertEqual(parts
, expected_cc
)
1147 CacheUtils
= override_settings(
1148 CACHE_MIDDLEWARE_KEY_PREFIX
='settingsprefix',
1149 CACHE_MIDDLEWARE_SECONDS
=1,
1152 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1158 PrefixedCacheUtils
= override_settings(
1161 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1162 'KEY_PREFIX': 'cacheprefix',
1168 class CacheHEADTest(TestCase
):
1171 self
.path
= '/cache/test/'
1172 self
.cache
= get_cache('default')
1177 def _get_request(self
, method
):
1178 request
= HttpRequest()
1180 'SERVER_NAME': 'testserver',
1183 request
.method
= method
1184 request
.path
= request
.path_info
= self
.path
1187 def _get_request_cache(self
, method
):
1188 request
= self
._get
_request
(method
)
1189 request
._cache
_update
_cache
= True
1192 def _set_cache(self
, request
, msg
):
1193 response
= HttpResponse()
1194 response
.content
= msg
1195 return UpdateCacheMiddleware().process_response(request
, response
)
1197 def test_head_caches_correctly(self
):
1198 test_content
= 'test content'
1200 request
= self
._get
_request
_cache
('HEAD')
1201 self
._set
_cache
(request
, test_content
)
1203 request
= self
._get
_request
('HEAD')
1204 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1205 self
.assertNotEqual(get_cache_data
, None)
1206 self
.assertEqual(test_content
, get_cache_data
.content
)
1208 def test_head_with_cached_get(self
):
1209 test_content
= 'test content'
1211 request
= self
._get
_request
_cache
('GET')
1212 self
._set
_cache
(request
, test_content
)
1214 request
= self
._get
_request
('HEAD')
1215 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1216 self
.assertNotEqual(get_cache_data
, None)
1217 self
.assertEqual(test_content
, get_cache_data
.content
)
1219 CacheHEADTest
= override_settings(
1220 CACHE_MIDDLEWARE_SECONDS
=60,
1221 CACHE_MIDDLEWARE_KEY_PREFIX
='test',
1224 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1230 class CacheI18nTest(TestCase
):
1233 self
.path
= '/cache/test/'
1234 self
.cache
= get_cache('default')
1239 def _get_request(self
, method
='GET'):
1240 request
= HttpRequest()
1242 'SERVER_NAME': 'testserver',
1245 request
.method
= method
1246 request
.path
= request
.path_info
= self
.path
1249 def _get_request_cache(self
, query_string
=None):
1250 request
= HttpRequest()
1252 'SERVER_NAME': 'testserver',
1256 request
.META
['QUERY_STRING'] = query_string
1257 request
.GET
= QueryDict(query_string
)
1258 request
.path
= request
.path_info
= self
.path
1259 request
._cache
_update
_cache
= True
1260 request
.method
= 'GET'
1261 request
.session
= {}
1264 @override_settings(USE_I18N
=True, USE_L10N
=False, USE_TZ
=False)
1265 def test_cache_key_i18n_translation(self
):
1266 request
= self
._get
_request
()
1267 lang
= translation
.get_language()
1268 response
= HttpResponse()
1269 key
= learn_cache_key(request
, response
)
1270 self
.assertIn(lang
, key
, "Cache keys should include the language name when translation is active")
1271 key2
= get_cache_key(request
)
1272 self
.assertEqual(key
, key2
)
1274 @override_settings(USE_I18N
=False, USE_L10N
=True, USE_TZ
=False)
1275 def test_cache_key_i18n_formatting(self
):
1276 request
= self
._get
_request
()
1277 lang
= translation
.get_language()
1278 response
= HttpResponse()
1279 key
= learn_cache_key(request
, response
)
1280 self
.assertIn(lang
, key
, "Cache keys should include the language name when formatting is active")
1281 key2
= get_cache_key(request
)
1282 self
.assertEqual(key
, key2
)
1284 @override_settings(USE_I18N
=False, USE_L10N
=False, USE_TZ
=True)
1285 def test_cache_key_i18n_timezone(self
):
1286 request
= self
._get
_request
()
1287 # This is tightly coupled to the implementation,
1288 # but it's the most straightforward way to test the key.
1289 tz
= force_unicode(timezone
.get_current_timezone_name(), errors
='ignore')
1290 tz
= tz
.encode('ascii', 'ignore').replace(' ', '_')
1291 response
= HttpResponse()
1292 key
= learn_cache_key(request
, response
)
1293 self
.assertIn(tz
, key
, "Cache keys should include the time zone name when time zones are active")
1294 key2
= get_cache_key(request
)
1295 self
.assertEqual(key
, key2
)
1297 @override_settings(USE_I18N
=False, USE_L10N
=False)
1298 def test_cache_key_no_i18n (self
):
1299 request
= self
._get
_request
()
1300 lang
= translation
.get_language()
1301 tz
= force_unicode(timezone
.get_current_timezone_name(), errors
='ignore')
1302 tz
= tz
.encode('ascii', 'ignore').replace(' ', '_')
1303 response
= HttpResponse()
1304 key
= learn_cache_key(request
, response
)
1305 self
.assertNotIn(lang
, key
, "Cache keys shouldn't include the language name when i18n isn't active")
1306 self
.assertNotIn(tz
, key
, "Cache keys shouldn't include the time zone name when i18n isn't active")
1308 @override_settings(USE_I18N
=False, USE_L10N
=False, USE_TZ
=True)
1309 def test_cache_key_with_non_ascii_tzname(self
):
1310 # Regression test for #17476
1311 class CustomTzName(timezone
.UTC
):
1313 def tzname(self
, dt
):
1316 request
= self
._get
_request
()
1317 response
= HttpResponse()
1318 with timezone
.override(CustomTzName()):
1319 CustomTzName
.name
= 'Hora estándar de Argentina' # UTF-8 string
1320 sanitized_name
= 'Hora_estndar_de_Argentina'
1321 self
.assertIn(sanitized_name
, learn_cache_key(request
, response
),
1322 "Cache keys should include the time zone name when time zones are active")
1324 CustomTzName
.name
= u
'Hora estándar de Argentina' # unicode
1325 sanitized_name
= 'Hora_estndar_de_Argentina'
1326 self
.assertIn(sanitized_name
, learn_cache_key(request
, response
),
1327 "Cache keys should include the time zone name when time zones are active")
1331 CACHE_MIDDLEWARE_KEY_PREFIX
="test",
1332 CACHE_MIDDLEWARE_SECONDS
=60,
1336 def test_middleware(self
):
1337 def set_cache(request
, lang
, msg
):
1338 translation
.activate(lang
)
1339 response
= HttpResponse()
1340 response
.content
= msg
1341 return UpdateCacheMiddleware().process_response(request
, response
)
1343 # cache with non empty request.GET
1344 request
= self
._get
_request
_cache
(query_string
='foo=bar&other=true')
1345 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1346 # first access, cache must return None
1347 self
.assertEqual(get_cache_data
, None)
1348 response
= HttpResponse()
1349 content
= 'Check for cache with QUERY_STRING'
1350 response
.content
= content
1351 UpdateCacheMiddleware().process_response(request
, response
)
1352 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1353 # cache must return content
1354 self
.assertNotEqual(get_cache_data
, None)
1355 self
.assertEqual(get_cache_data
.content
, content
)
1356 # different QUERY_STRING, cache must be empty
1357 request
= self
._get
_request
_cache
(query_string
='foo=bar&somethingelse=true')
1358 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1359 self
.assertEqual(get_cache_data
, None)
1362 en_message
="Hello world!"
1363 es_message
="Hola mundo!"
1365 request
= self
._get
_request
_cache
()
1366 set_cache(request
, 'en', en_message
)
1367 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1368 # Check that we can recover the cache
1369 self
.assertNotEqual(get_cache_data
, None)
1370 self
.assertEqual(get_cache_data
.content
, en_message
)
1371 # Check that we use etags
1372 self
.assertTrue(get_cache_data
.has_header('ETag'))
1373 # Check that we can disable etags
1374 with self
.settings(USE_ETAGS
=False):
1375 request
._cache
_update
_cache
= True
1376 set_cache(request
, 'en', en_message
)
1377 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1378 self
.assertFalse(get_cache_data
.has_header('ETag'))
1379 # change the session language and set content
1380 request
= self
._get
_request
_cache
()
1381 set_cache(request
, 'es', es_message
)
1382 # change again the language
1383 translation
.activate('en')
1384 # retrieve the content from cache
1385 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1386 self
.assertEqual(get_cache_data
.content
, en_message
)
1387 # change again the language
1388 translation
.activate('es')
1389 get_cache_data
= FetchFromCacheMiddleware().process_request(request
)
1390 self
.assertEqual(get_cache_data
.content
, es_message
)
1391 # reset the language
1392 translation
.deactivate()
1394 CacheI18nTest
= override_settings(
1395 CACHE_MIDDLEWARE_KEY_PREFIX
='settingsprefix',
1398 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1407 PrefixedCacheI18nTest
= override_settings(
1410 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1411 'KEY_PREFIX': 'cacheprefix'
1417 def hello_world_view(request
, value
):
1418 return HttpResponse('Hello World %s' % value
)
1421 class CacheMiddlewareTest(TestCase
):
1424 self
.factory
= RequestFactory()
1425 self
.default_cache
= get_cache('default')
1426 self
.other_cache
= get_cache('other')
1429 self
.default_cache
.clear()
1430 self
.other_cache
.clear()
1432 def test_constructor(self
):
1434 Ensure the constructor is correctly distinguishing between usage of CacheMiddleware as
1435 Middleware vs. usage of CacheMiddleware as view decorator and setting attributes
1438 # If no arguments are passed in construction, it's being used as middleware.
1439 middleware
= CacheMiddleware()
1441 # Now test object attributes against values defined in setUp above
1442 self
.assertEqual(middleware
.cache_timeout
, 30)
1443 self
.assertEqual(middleware
.key_prefix
, 'middlewareprefix')
1444 self
.assertEqual(middleware
.cache_alias
, 'other')
1445 self
.assertEqual(middleware
.cache_anonymous_only
, False)
1447 # If arguments are being passed in construction, it's being used as a decorator.
1448 # First, test with "defaults":
1449 as_view_decorator
= CacheMiddleware(cache_alias
=None, key_prefix
=None)
1451 self
.assertEqual(as_view_decorator
.cache_timeout
, 300) # Timeout value for 'default' cache, i.e. 300
1452 self
.assertEqual(as_view_decorator
.key_prefix
, '')
1453 self
.assertEqual(as_view_decorator
.cache_alias
, 'default') # Value of DEFAULT_CACHE_ALIAS from django.core.cache
1454 self
.assertEqual(as_view_decorator
.cache_anonymous_only
, False)
1456 # Next, test with custom values:
1457 as_view_decorator_with_custom
= CacheMiddleware(cache_anonymous_only
=True, cache_timeout
=60, cache_alias
='other', key_prefix
='foo')
1459 self
.assertEqual(as_view_decorator_with_custom
.cache_timeout
, 60)
1460 self
.assertEqual(as_view_decorator_with_custom
.key_prefix
, 'foo')
1461 self
.assertEqual(as_view_decorator_with_custom
.cache_alias
, 'other')
1462 self
.assertEqual(as_view_decorator_with_custom
.cache_anonymous_only
, True)
1464 def test_middleware(self
):
1465 middleware
= CacheMiddleware()
1466 prefix_middleware
= CacheMiddleware(key_prefix
='prefix1')
1467 timeout_middleware
= CacheMiddleware(cache_timeout
=1)
1469 request
= self
.factory
.get('/view/')
1471 # Put the request through the request middleware
1472 result
= middleware
.process_request(request
)
1473 self
.assertEqual(result
, None)
1475 response
= hello_world_view(request
, '1')
1477 # Now put the response through the response middleware
1478 response
= middleware
.process_response(request
, response
)
1480 # Repeating the request should result in a cache hit
1481 result
= middleware
.process_request(request
)
1482 self
.assertNotEquals(result
, None)
1483 self
.assertEqual(result
.content
, 'Hello World 1')
1485 # The same request through a different middleware won't hit
1486 result
= prefix_middleware
.process_request(request
)
1487 self
.assertEqual(result
, None)
1489 # The same request with a timeout _will_ hit
1490 result
= timeout_middleware
.process_request(request
)
1491 self
.assertNotEquals(result
, None)
1492 self
.assertEqual(result
.content
, 'Hello World 1')
1494 @override_settings(CACHE_MIDDLEWARE_ANONYMOUS_ONLY
=True)
1495 def test_cache_middleware_anonymous_only_wont_cause_session_access(self
):
1496 """ The cache middleware shouldn't cause a session access due to
1497 CACHE_MIDDLEWARE_ANONYMOUS_ONLY if nothing else has accessed the
1498 session. Refs 13283 """
1500 from django
.contrib
.sessions
.middleware
import SessionMiddleware
1501 from django
.contrib
.auth
.middleware
import AuthenticationMiddleware
1503 middleware
= CacheMiddleware()
1504 session_middleware
= SessionMiddleware()
1505 auth_middleware
= AuthenticationMiddleware()
1507 request
= self
.factory
.get('/view_anon/')
1509 # Put the request through the request middleware
1510 session_middleware
.process_request(request
)
1511 auth_middleware
.process_request(request
)
1512 result
= middleware
.process_request(request
)
1513 self
.assertEqual(result
, None)
1515 response
= hello_world_view(request
, '1')
1517 # Now put the response through the response middleware
1518 session_middleware
.process_response(request
, response
)
1519 response
= middleware
.process_response(request
, response
)
1521 self
.assertEqual(request
.session
.accessed
, False)
1523 @override_settings(CACHE_MIDDLEWARE_ANONYMOUS_ONLY
=True)
1524 def test_cache_middleware_anonymous_only_with_cache_page(self
):
1525 """CACHE_MIDDLEWARE_ANONYMOUS_ONLY should still be effective when used
1526 with the cache_page decorator: the response to a request from an
1527 authenticated user should not be cached."""
1529 request
= self
.factory
.get('/view_anon/')
1531 class MockAuthenticatedUser(object):
1532 def is_authenticated(self
):
1535 class MockAccessedSession(object):
1538 request
.user
= MockAuthenticatedUser()
1539 request
.session
= MockAccessedSession()
1541 response
= cache_page(hello_world_view
)(request
, '1')
1543 self
.assertFalse("Cache-Control" in response
)
1545 def test_view_decorator(self
):
1546 # decorate the same view with different cache decorators
1547 default_view
= cache_page(hello_world_view
)
1548 default_with_prefix_view
= cache_page(key_prefix
='prefix1')(hello_world_view
)
1550 explicit_default_view
= cache_page(cache
='default')(hello_world_view
)
1551 explicit_default_with_prefix_view
= cache_page(cache
='default', key_prefix
='prefix1')(hello_world_view
)
1553 other_view
= cache_page(cache
='other')(hello_world_view
)
1554 other_with_prefix_view
= cache_page(cache
='other', key_prefix
='prefix2')(hello_world_view
)
1555 other_with_timeout_view
= cache_page(3, cache
='other', key_prefix
='prefix3')(hello_world_view
)
1557 request
= self
.factory
.get('/view/')
1559 # Request the view once
1560 response
= default_view(request
, '1')
1561 self
.assertEqual(response
.content
, 'Hello World 1')
1563 # Request again -- hit the cache
1564 response
= default_view(request
, '2')
1565 self
.assertEqual(response
.content
, 'Hello World 1')
1567 # Requesting the same view with the explicit cache should yield the same result
1568 response
= explicit_default_view(request
, '3')
1569 self
.assertEqual(response
.content
, 'Hello World 1')
1571 # Requesting with a prefix will hit a different cache key
1572 response
= explicit_default_with_prefix_view(request
, '4')
1573 self
.assertEqual(response
.content
, 'Hello World 4')
1575 # Hitting the same view again gives a cache hit
1576 response
= explicit_default_with_prefix_view(request
, '5')
1577 self
.assertEqual(response
.content
, 'Hello World 4')
1579 # And going back to the implicit cache will hit the same cache
1580 response
= default_with_prefix_view(request
, '6')
1581 self
.assertEqual(response
.content
, 'Hello World 4')
1583 # Requesting from an alternate cache won't hit cache
1584 response
= other_view(request
, '7')
1585 self
.assertEqual(response
.content
, 'Hello World 7')
1587 # But a repeated hit will hit cache
1588 response
= other_view(request
, '8')
1589 self
.assertEqual(response
.content
, 'Hello World 7')
1591 # And prefixing the alternate cache yields yet another cache entry
1592 response
= other_with_prefix_view(request
, '9')
1593 self
.assertEqual(response
.content
, 'Hello World 9')
1595 # Request from the alternate cache with a new prefix and a custom timeout
1596 response
= other_with_timeout_view(request
, '10')
1597 self
.assertEqual(response
.content
, 'Hello World 10')
1599 # But if we wait a couple of seconds...
1602 # ... the default cache will still hit
1603 cache
= get_cache('default')
1604 response
= default_view(request
, '11')
1605 self
.assertEqual(response
.content
, 'Hello World 1')
1607 # ... the default cache with a prefix will still hit
1608 response
= default_with_prefix_view(request
, '12')
1609 self
.assertEqual(response
.content
, 'Hello World 4')
1611 # ... the explicit default cache will still hit
1612 response
= explicit_default_view(request
, '13')
1613 self
.assertEqual(response
.content
, 'Hello World 1')
1615 # ... the explicit default cache with a prefix will still hit
1616 response
= explicit_default_with_prefix_view(request
, '14')
1617 self
.assertEqual(response
.content
, 'Hello World 4')
1619 # .. but a rapidly expiring cache won't hit
1620 response
= other_view(request
, '15')
1621 self
.assertEqual(response
.content
, 'Hello World 15')
1623 # .. even if it has a prefix
1624 response
= other_with_prefix_view(request
, '16')
1625 self
.assertEqual(response
.content
, 'Hello World 16')
1627 # ... but a view with a custom timeout will still hit
1628 response
= other_with_timeout_view(request
, '17')
1629 self
.assertEqual(response
.content
, 'Hello World 10')
1631 # And if we wait a few more seconds
1634 # the custom timeouot cache will miss
1635 response
= other_with_timeout_view(request
, '18')
1636 self
.assertEqual(response
.content
, 'Hello World 18')
1638 CacheMiddlewareTest
= override_settings(
1639 CACHE_MIDDLEWARE_ALIAS
='other',
1640 CACHE_MIDDLEWARE_KEY_PREFIX
='middlewareprefix',
1641 CACHE_MIDDLEWARE_SECONDS
=30,
1642 CACHE_MIDDLEWARE_ANONYMOUS_ONLY
=False,
1645 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1648 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1649 'LOCATION': 'other',
1653 )(CacheMiddlewareTest
)
1656 class TestWithTemplateResponse(TestCase
):
1658 Tests various headers w/ TemplateResponse.
1660 Most are probably redundant since they manipulate the same object
1661 anyway but the Etag header is 'special' because it relies on the
1662 content being complete (which is not necessarily always the case
1663 with a TemplateResponse)
1666 self
.path
= '/cache/test/'
1667 self
.cache
= get_cache('default')
1672 def _get_request(self
, path
, method
='GET'):
1673 request
= HttpRequest()
1675 'SERVER_NAME': 'testserver',
1678 request
.method
= method
1679 request
.path
= request
.path_info
= "/cache/%s" % path
1682 def test_patch_vary_headers(self
):
1684 # Initial vary, new headers, resulting vary.
1685 (None, ('Accept-Encoding',), 'Accept-Encoding'),
1686 ('Accept-Encoding', ('accept-encoding',), 'Accept-Encoding'),
1687 ('Accept-Encoding', ('ACCEPT-ENCODING',), 'Accept-Encoding'),
1688 ('Cookie', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
1689 ('Cookie, Accept-Encoding', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
1690 ('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
1691 (None, ('Accept-Encoding', 'COOKIE'), 'Accept-Encoding, COOKIE'),
1692 ('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
1693 ('Cookie , Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
1695 for initial_vary
, newheaders
, resulting_vary
in headers
:
1696 response
= TemplateResponse(HttpResponse(), Template("This is a test"))
1697 if initial_vary
is not None:
1698 response
['Vary'] = initial_vary
1699 patch_vary_headers(response
, newheaders
)
1700 self
.assertEqual(response
['Vary'], resulting_vary
)
1702 def test_get_cache_key(self
):
1703 request
= self
._get
_request
(self
.path
)
1704 response
= TemplateResponse(HttpResponse(), Template("This is a test"))
1705 key_prefix
= 'localprefix'
1706 # Expect None if no headers have been set yet.
1707 self
.assertEqual(get_cache_key(request
), None)
1708 # Set headers to an empty list.
1709 learn_cache_key(request
, response
)
1710 self
.assertEqual(get_cache_key(request
), 'views.decorators.cache.cache_page.settingsprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
1711 # Verify that a specified key_prefix is taken into account.
1712 learn_cache_key(request
, response
, key_prefix
=key_prefix
)
1713 self
.assertEqual(get_cache_key(request
, key_prefix
=key_prefix
), 'views.decorators.cache.cache_page.localprefix.GET.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
1715 def test_get_cache_key_with_query(self
):
1716 request
= self
._get
_request
(self
.path
+ '?test=1')
1717 response
= TemplateResponse(HttpResponse(), Template("This is a test"))
1718 # Expect None if no headers have been set yet.
1719 self
.assertEqual(get_cache_key(request
), None)
1720 # Set headers to an empty list.
1721 learn_cache_key(request
, response
)
1722 # Verify that the querystring is taken into account.
1723 self
.assertEqual(get_cache_key(request
), 'views.decorators.cache.cache_page.settingsprefix.GET.bd889c5a59603af44333ed21504db3cd.d41d8cd98f00b204e9800998ecf8427e')
1725 @override_settings(USE_ETAGS
=False)
1726 def test_without_etag(self
):
1727 response
= TemplateResponse(HttpResponse(), Template("This is a test"))
1728 self
.assertFalse(response
.has_header('ETag'))
1729 patch_response_headers(response
)
1730 self
.assertFalse(response
.has_header('ETag'))
1731 response
= response
.render()
1732 self
.assertFalse(response
.has_header('ETag'))
1734 @override_settings(USE_ETAGS
=True)
1735 def test_with_etag(self
):
1736 response
= TemplateResponse(HttpResponse(), Template("This is a test"))
1737 self
.assertFalse(response
.has_header('ETag'))
1738 patch_response_headers(response
)
1739 self
.assertFalse(response
.has_header('ETag'))
1740 response
= response
.render()
1741 self
.assertTrue(response
.has_header('ETag'))
1743 TestWithTemplateResponse
= override_settings(
1744 CACHE_MIDDLEWARE_KEY_PREFIX
='settingsprefix',
1745 CACHE_MIDDLEWARE_SECONDS
=1,
1748 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
1752 )(TestWithTemplateResponse
)
1755 class TestEtagWithAdmin(TestCase
):
1756 # See https://code.djangoproject.com/ticket/16003
1757 urls
= "regressiontests.admin_views.urls"
1759 def test_admin(self
):
1760 with self
.settings(USE_ETAGS
=False):
1761 response
= self
.client
.get('/test_admin/admin/')
1762 self
.assertEqual(response
.status_code
, 200)
1763 self
.assertFalse(response
.has_header('ETag'))
1765 with self
.settings(USE_ETAGS
=True):
1766 response
= self
.client
.get('/test_admin/admin/')
1767 self
.assertEqual(response
.status_code
, 200)
1768 self
.assertTrue(response
.has_header('ETag'))