~ubuntu-branches/ubuntu/quantal/python-django/quantal

« back to all changes in this revision

Viewing changes to tests/regressiontests/cache/tests.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2009-07-29 11:26:28 UTC
  • mfrom: (1.1.8 upstream) (4.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20090729112628-pg09ino8sz0sj21t
Tags: 1.1-1
* New upstream release.
* Merge from experimental:
  - Ship FastCGI initscript and /etc/default file in python-django's examples
    directory (Closes: #538863)
  - Drop "05_10539-sphinx06-compatibility.diff"; it has been applied
    upstream.
  - Bump Standards-Version to 3.8.2.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
# Unit tests for cache framework
 
4
# Uses whatever cache backend is set in the test settings file.
 
5
 
 
6
import os
 
7
import shutil
 
8
import tempfile
 
9
import time
 
10
import unittest
 
11
 
 
12
from django.conf import settings
 
13
from django.core import management
 
14
from django.core.cache import get_cache
 
15
from django.core.cache.backends.base import InvalidCacheBackendError
 
16
from django.http import HttpResponse, HttpRequest
 
17
from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
 
18
from django.utils.hashcompat import md5_constructor
 
19
 
 
20
# functions/classes for complex data type tests
 
21
def f():
 
22
    return 42
 
23
class C:
 
24
    def m(n):
 
25
        return 24
 
26
 
 
27
class DummyCacheTests(unittest.TestCase):
 
28
    # The Dummy cache backend doesn't really behave like a test backend,
 
29
    # so it has different test requirements.
 
30
    def setUp(self):
 
31
        self.cache = get_cache('dummy://')
 
32
 
 
33
    def test_simple(self):
 
34
        "Dummy cache backend ignores cache set calls"
 
35
        self.cache.set("key", "value")
 
36
        self.assertEqual(self.cache.get("key"), None)
 
37
 
 
38
    def test_add(self):
 
39
        "Add doesn't do anything in dummy cache backend"
 
40
        self.cache.add("addkey1", "value")
 
41
        result = self.cache.add("addkey1", "newvalue")
 
42
        self.assertEqual(result, True)
 
43
        self.assertEqual(self.cache.get("addkey1"), None)
 
44
 
 
45
    def test_non_existent(self):
 
46
        "Non-existent keys aren't found in the dummy cache backend"
 
47
        self.assertEqual(self.cache.get("does_not_exist"), None)
 
48
        self.assertEqual(self.cache.get("does_not_exist", "bang!"), "bang!")
 
49
 
 
50
    def test_get_many(self):
 
51
        "get_many returns nothing for the dummy cache backend"
 
52
        self.cache.set('a', 'a')
 
53
        self.cache.set('b', 'b')
 
54
        self.cache.set('c', 'c')
 
55
        self.cache.set('d', 'd')
 
56
        self.assertEqual(self.cache.get_many(['a', 'c', 'd']), {})
 
57
        self.assertEqual(self.cache.get_many(['a', 'b', 'e']), {})
 
58
 
 
59
    def test_delete(self):
 
60
        "Cache deletion is transparently ignored on the dummy cache backend"
 
61
        self.cache.set("key1", "spam")
 
62
        self.cache.set("key2", "eggs")
 
63
        self.assertEqual(self.cache.get("key1"), None)
 
64
        self.cache.delete("key1")
 
65
        self.assertEqual(self.cache.get("key1"), None)
 
66
        self.assertEqual(self.cache.get("key2"), None)
 
67
 
 
68
    def test_has_key(self):
 
69
        "The has_key method doesn't ever return True for the dummy cache backend"
 
70
        self.cache.set("hello1", "goodbye1")
 
71
        self.assertEqual(self.cache.has_key("hello1"), False)
 
72
        self.assertEqual(self.cache.has_key("goodbye1"), False)
 
73
 
 
74
    def test_in(self):
 
75
        "The in operator doesn't ever return True for the dummy cache backend"
 
76
        self.cache.set("hello2", "goodbye2")
 
77
        self.assertEqual("hello2" in self.cache, False)
 
78
        self.assertEqual("goodbye2" in self.cache, False)
 
79
 
 
80
    def test_incr(self):
 
81
        "Dummy cache values can't be incremented"
 
82
        self.cache.set('answer', 42)
 
83
        self.assertRaises(ValueError, self.cache.incr, 'answer')
 
84
        self.assertRaises(ValueError, self.cache.incr, 'does_not_exist')
 
85
 
 
86
    def test_decr(self):
 
87
        "Dummy cache values can't be decremented"
 
88
        self.cache.set('answer', 42)
 
89
        self.assertRaises(ValueError, self.cache.decr, 'answer')
 
90
        self.assertRaises(ValueError, self.cache.decr, 'does_not_exist')
 
91
 
 
92
    def test_data_types(self):
 
93
        "All data types are ignored equally by the dummy cache"
 
94
        stuff = {
 
95
            'string'    : 'this is a string',
 
96
            'int'       : 42,
 
97
            'list'      : [1, 2, 3, 4],
 
98
            'tuple'     : (1, 2, 3, 4),
 
99
            'dict'      : {'A': 1, 'B' : 2},
 
100
            'function'  : f,
 
101
            'class'     : C,
 
102
        }
 
103
        self.cache.set("stuff", stuff)
 
104
        self.assertEqual(self.cache.get("stuff"), None)
 
105
 
 
106
    def test_expiration(self):
 
107
        "Expiration has no effect on the dummy cache"
 
108
        self.cache.set('expire1', 'very quickly', 1)
 
109
        self.cache.set('expire2', 'very quickly', 1)
 
110
        self.cache.set('expire3', 'very quickly', 1)
 
111
 
 
112
        time.sleep(2)
 
113
        self.assertEqual(self.cache.get("expire1"), None)
 
114
 
 
115
        self.cache.add("expire2", "newvalue")
 
116
        self.assertEqual(self.cache.get("expire2"), None)
 
117
        self.assertEqual(self.cache.has_key("expire3"), False)
 
118
 
 
119
    def test_unicode(self):
 
120
        "Unicode values are ignored by the dummy cache"
 
121
        stuff = {
 
122
            u'ascii': u'ascii_value',
 
123
            u'unicode_ascii': u'Iñtërnâtiônàlizætiøn1',
 
124
            u'Iñtërnâtiônàlizætiøn': u'Iñtërnâtiônàlizætiøn2',
 
125
            u'ascii': {u'x' : 1 }
 
126
            }
 
127
        for (key, value) in stuff.items():
 
128
            self.cache.set(key, value)
 
129
            self.assertEqual(self.cache.get(key), None)
 
130
 
 
131
 
 
132
class BaseCacheTests(object):
 
133
    # A common set of tests to apply to all cache backends
 
134
    def test_simple(self):
 
135
        # Simple cache set/get works
 
136
        self.cache.set("key", "value")
 
137
        self.assertEqual(self.cache.get("key"), "value")
 
138
 
 
139
    def test_add(self):
 
140
        # A key can be added to a cache
 
141
        self.cache.add("addkey1", "value")
 
142
        result = self.cache.add("addkey1", "newvalue")
 
143
        self.assertEqual(result, False)
 
144
        self.assertEqual(self.cache.get("addkey1"), "value")
 
145
 
 
146
    def test_non_existent(self):
 
147
        # Non-existent cache keys return as None/default
 
148
        # get with non-existent keys
 
149
        self.assertEqual(self.cache.get("does_not_exist"), None)
 
150
        self.assertEqual(self.cache.get("does_not_exist", "bang!"), "bang!")
 
151
 
 
152
    def test_get_many(self):
 
153
        # Multiple cache keys can be returned using get_many
 
154
        self.cache.set('a', 'a')
 
155
        self.cache.set('b', 'b')
 
156
        self.cache.set('c', 'c')
 
157
        self.cache.set('d', 'd')
 
158
        self.assertEqual(self.cache.get_many(['a', 'c', 'd']), {'a' : 'a', 'c' : 'c', 'd' : 'd'})
 
159
        self.assertEqual(self.cache.get_many(['a', 'b', 'e']), {'a' : 'a', 'b' : 'b'})
 
160
 
 
161
    def test_delete(self):
 
162
        # Cache keys can be deleted
 
163
        self.cache.set("key1", "spam")
 
164
        self.cache.set("key2", "eggs")
 
165
        self.assertEqual(self.cache.get("key1"), "spam")
 
166
        self.cache.delete("key1")
 
167
        self.assertEqual(self.cache.get("key1"), None)
 
168
        self.assertEqual(self.cache.get("key2"), "eggs")
 
169
 
 
170
    def test_has_key(self):
 
171
        # The cache can be inspected for cache keys
 
172
        self.cache.set("hello1", "goodbye1")
 
173
        self.assertEqual(self.cache.has_key("hello1"), True)
 
174
        self.assertEqual(self.cache.has_key("goodbye1"), False)
 
175
 
 
176
    def test_in(self):
 
177
        # The in operator can be used to inspet cache contents
 
178
        self.cache.set("hello2", "goodbye2")
 
179
        self.assertEqual("hello2" in self.cache, True)
 
180
        self.assertEqual("goodbye2" in self.cache, False)
 
181
 
 
182
    def test_incr(self):
 
183
        # Cache values can be incremented
 
184
        self.cache.set('answer', 41)
 
185
        self.assertEqual(self.cache.incr('answer'), 42)
 
186
        self.assertEqual(self.cache.get('answer'), 42)
 
187
        self.assertEqual(self.cache.incr('answer', 10), 52)
 
188
        self.assertEqual(self.cache.get('answer'), 52)
 
189
        self.assertRaises(ValueError, self.cache.incr, 'does_not_exist')
 
190
 
 
191
    def test_decr(self):
 
192
        # Cache values can be decremented
 
193
        self.cache.set('answer', 43)
 
194
        self.assertEqual(self.cache.decr('answer'), 42)
 
195
        self.assertEqual(self.cache.get('answer'), 42)
 
196
        self.assertEqual(self.cache.decr('answer', 10), 32)
 
197
        self.assertEqual(self.cache.get('answer'), 32)
 
198
        self.assertRaises(ValueError, self.cache.decr, 'does_not_exist')
 
199
 
 
200
    def test_data_types(self):
 
201
        # Many different data types can be cached
 
202
        stuff = {
 
203
            'string'    : 'this is a string',
 
204
            'int'       : 42,
 
205
            'list'      : [1, 2, 3, 4],
 
206
            'tuple'     : (1, 2, 3, 4),
 
207
            'dict'      : {'A': 1, 'B' : 2},
 
208
            'function'  : f,
 
209
            'class'     : C,
 
210
        }
 
211
        self.cache.set("stuff", stuff)
 
212
        self.assertEqual(self.cache.get("stuff"), stuff)
 
213
 
 
214
    def test_expiration(self):
 
215
        # Cache values can be set to expire
 
216
        self.cache.set('expire1', 'very quickly', 1)
 
217
        self.cache.set('expire2', 'very quickly', 1)
 
218
        self.cache.set('expire3', 'very quickly', 1)
 
219
 
 
220
        time.sleep(2)
 
221
        self.assertEqual(self.cache.get("expire1"), None)
 
222
 
 
223
        self.cache.add("expire2", "newvalue")
 
224
        self.assertEqual(self.cache.get("expire2"), "newvalue")
 
225
        self.assertEqual(self.cache.has_key("expire3"), False)
 
226
 
 
227
    def test_unicode(self):
 
228
        # Unicode values can be cached
 
229
        stuff = {
 
230
            u'ascii': u'ascii_value',
 
231
            u'unicode_ascii': u'Iñtërnâtiônàlizætiøn1',
 
232
            u'Iñtërnâtiônàlizætiøn': u'Iñtërnâtiônàlizætiøn2',
 
233
            u'ascii': {u'x' : 1 }
 
234
            }
 
235
        for (key, value) in stuff.items():
 
236
            self.cache.set(key, value)
 
237
            self.assertEqual(self.cache.get(key), value)
 
238
 
 
239
class DBCacheTests(unittest.TestCase, BaseCacheTests):
 
240
    def setUp(self):
 
241
        management.call_command('createcachetable', 'test_cache_table', verbosity=0, interactive=False)
 
242
        self.cache = get_cache('db://test_cache_table')
 
243
 
 
244
    def tearDown(self):
 
245
        from django.db import connection
 
246
        cursor = connection.cursor()
 
247
        cursor.execute('DROP TABLE test_cache_table');
 
248
 
 
249
class LocMemCacheTests(unittest.TestCase, BaseCacheTests):
 
250
    def setUp(self):
 
251
        self.cache = get_cache('locmem://')
 
252
 
 
253
# memcached backend isn't guaranteed to be available.
 
254
# To check the memcached backend, the test settings file will
 
255
# need to contain a CACHE_BACKEND setting that points at
 
256
# your memcache server.
 
257
if settings.CACHE_BACKEND.startswith('memcached://'):
 
258
    class MemcachedCacheTests(unittest.TestCase, BaseCacheTests):
 
259
        def setUp(self):
 
260
            self.cache = get_cache(settings.CACHE_BACKEND)
 
261
 
 
262
class FileBasedCacheTests(unittest.TestCase, BaseCacheTests):
 
263
    """
 
264
    Specific test cases for the file-based cache.
 
265
    """
 
266
    def setUp(self):
 
267
        self.dirname = tempfile.mkdtemp()
 
268
        self.cache = get_cache('file://%s' % self.dirname)
 
269
 
 
270
    def tearDown(self):
 
271
        shutil.rmtree(self.dirname)
 
272
 
 
273
    def test_hashing(self):
 
274
        """Test that keys are hashed into subdirectories correctly"""
 
275
        self.cache.set("foo", "bar")
 
276
        keyhash = md5_constructor("foo").hexdigest()
 
277
        keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
 
278
        self.assert_(os.path.exists(keypath))
 
279
 
 
280
    def test_subdirectory_removal(self):
 
281
        """
 
282
        Make sure that the created subdirectories are correctly removed when empty.
 
283
        """
 
284
        self.cache.set("foo", "bar")
 
285
        keyhash = md5_constructor("foo").hexdigest()
 
286
        keypath = os.path.join(self.dirname, keyhash[:2], keyhash[2:4], keyhash[4:])
 
287
        self.assert_(os.path.exists(keypath))
 
288
 
 
289
        self.cache.delete("foo")
 
290
        self.assert_(not os.path.exists(keypath))
 
291
        self.assert_(not os.path.exists(os.path.dirname(keypath)))
 
292
        self.assert_(not os.path.exists(os.path.dirname(os.path.dirname(keypath))))
 
293
 
 
294
class CacheUtils(unittest.TestCase):
 
295
    """TestCase for django.utils.cache functions."""
 
296
 
 
297
    def setUp(self):
 
298
        self.path = '/cache/test/'
 
299
        self.old_settings_key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
 
300
        self.old_middleware_seconds = settings.CACHE_MIDDLEWARE_SECONDS
 
301
        settings.CACHE_MIDDLEWARE_KEY_PREFIX = 'settingsprefix'
 
302
        settings.CACHE_MIDDLEWARE_SECONDS = 1
 
303
 
 
304
    def tearDown(self):
 
305
        settings.CACHE_MIDDLEWARE_KEY_PREFIX = self.old_settings_key_prefix
 
306
        settings.CACHE_MIDDLEWARE_SECONDS = self.old_middleware_seconds
 
307
 
 
308
    def _get_request(self, path):
 
309
        request = HttpRequest()
 
310
        request.META = {
 
311
            'SERVER_NAME': 'testserver',
 
312
            'SERVER_PORT': 80,
 
313
        }
 
314
        request.path = request.path_info = "/cache/%s" % path
 
315
        return request
 
316
 
 
317
    def test_patch_vary_headers(self):
 
318
        headers = (
 
319
            # Initial vary, new headers, resulting vary.
 
320
            (None, ('Accept-Encoding',), 'Accept-Encoding'),
 
321
            ('Accept-Encoding', ('accept-encoding',), 'Accept-Encoding'),
 
322
            ('Accept-Encoding', ('ACCEPT-ENCODING',), 'Accept-Encoding'),
 
323
            ('Cookie', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
 
324
            ('Cookie, Accept-Encoding', ('Accept-Encoding',), 'Cookie, Accept-Encoding'),
 
325
            ('Cookie, Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
 
326
            (None, ('Accept-Encoding', 'COOKIE'), 'Accept-Encoding, COOKIE'),
 
327
            ('Cookie,     Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
 
328
            ('Cookie    ,     Accept-Encoding', ('Accept-Encoding', 'cookie'), 'Cookie, Accept-Encoding'),
 
329
        )
 
330
        for initial_vary, newheaders, resulting_vary in headers:
 
331
            response = HttpResponse()
 
332
            if initial_vary is not None:
 
333
                response['Vary'] = initial_vary
 
334
            patch_vary_headers(response, newheaders)
 
335
            self.assertEqual(response['Vary'], resulting_vary)
 
336
 
 
337
    def test_get_cache_key(self):
 
338
        request = self._get_request(self.path)
 
339
        response = HttpResponse()
 
340
        key_prefix = 'localprefix'
 
341
        # Expect None if no headers have been set yet.
 
342
        self.assertEqual(get_cache_key(request), None)
 
343
        # Set headers to an empty list.
 
344
        learn_cache_key(request, response)
 
345
        self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
 
346
        # Verify that a specified key_prefix is taken in to account.
 
347
        learn_cache_key(request, response, key_prefix=key_prefix)
 
348
        self.assertEqual(get_cache_key(request, key_prefix=key_prefix), 'views.decorators.cache.cache_page.localprefix.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
 
349
 
 
350
    def test_learn_cache_key(self):
 
351
        request = self._get_request(self.path)
 
352
        response = HttpResponse()
 
353
        response['Vary'] = 'Pony'
 
354
        # Make sure that the Vary header is added to the key hash
 
355
        learn_cache_key(request, response)
 
356
        self.assertEqual(get_cache_key(request), 'views.decorators.cache.cache_page.settingsprefix.a8c87a3d8c44853d7f79474f7ffe4ad5.d41d8cd98f00b204e9800998ecf8427e')
 
357
 
 
358
if __name__ == '__main__':
 
359
    unittest.main()