Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/trunk/cherrypy/test/test_caching.py

Revision 1797 (checked in by fumanchu, 1 year ago)

Forward port to trunk from 3.0.x [1704]. Responses were being gzipped twice when served from cache.

  • Property svn:eol-style set to native
Line 
1 from cherrypy.test import test
2 test.prefer_parent_path()
3
4 import gzip
5 import os
6 curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
7 import StringIO
8
9 import cherrypy
10 from cherrypy.lib import http
11
12 gif_bytes = ('GIF89a\x01\x00\x01\x00\x82\x00\x01\x99"\x1e\x00\x00\x00\x00\x00'
13              '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
14              '\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x02\x03\x02\x08\t\x00;')
15
16
17 def setup_server():
18    
19     class Root:
20        
21         _cp_config = {'tools.caching.on': True}
22        
23         def __init__(self):
24             cherrypy.counter = 0
25        
26         def index(self):
27             cherrypy.counter += 1
28             msg = "visit #%s" % cherrypy.counter
29             return msg
30         index.exposed = True
31        
32         def a_gif(self):
33             cherrypy.response.headers['Last-Modified'] = http.HTTPDate()
34             return gif_bytes
35         a_gif.exposed = True
36    
37     class UnCached(object):
38         _cp_config = {'tools.expires.on': True,
39                       'tools.staticdir.on': True,
40                       'tools.staticdir.dir': 'static',
41                       'tools.staticdir.root': curdir,
42                       }
43
44         def force(self):
45             self._cp_config['tools.expires.force'] = True
46             return "being forceful"
47         force.exposed = True
48
49         def dynamic(self):
50             cherrypy.response.headers['Cache-Control'] = 'private'
51             return "D-d-d-dynamic!"
52         dynamic.exposed = True
53
54         def cacheable(self):
55             cherrypy.response.headers['Etag'] = 'bibbitybobbityboo'
56             return "Hi, I'm cacheable."
57         cacheable.exposed = True
58
59         def specific(self):
60             return "I am being specific"
61         specific.exposed = True
62         specific._cp_config = {'tools.expires.secs': 86400}
63
64         class Foo(object):pass
65        
66         def wrongtype(self):
67             return "Woops"
68         wrongtype.exposed = True
69         wrongtype._cp_config = {'tools.expires.secs': Foo()}
70    
71     cherrypy.tree.mount(Root())
72     cherrypy.tree.mount(UnCached(), "/expires")
73     cherrypy.config.update({'environment': 'test_suite',
74                             'tools.gzip.on': True})
75
76
77 from cherrypy.test import helper
78
79 class CacheTest(helper.CPWebCase):
80
81     def testCaching(self):
82         elapsed = 0.0
83         for trial in xrange(10):
84             self.getPage("/")
85             # The response should be the same every time,
86             # except for the Age response header.
87             self.assertBody('visit #1')
88             if trial != 0:
89                 age = int(self.assertHeader("Age"))
90                 self.assert_(age >= elapsed)
91                 elapsed = age
92        
93         # POST, PUT, DELETE should not be cached.
94         self.getPage("/", method="POST")
95         self.assertBody('visit #2')
96         # The previous request should have invalidated the cache,
97         # so this request will recalc the response.
98         self.getPage("/", method="GET")
99         self.assertBody('visit #3')
100         # ...but this request should get the cached copy.
101         self.getPage("/", method="GET")
102         self.assertBody('visit #3')
103         self.getPage("/", method="DELETE")
104         self.assertBody('visit #4')
105        
106         # The previous request should have invalidated the cache,
107         # so this request will recalc the response.
108         self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')])
109         self.assertHeader('Content-Encoding', 'gzip')
110         self.assertEqual(cherrypy.lib.encoding.decompress(self.body), "visit #5")
111        
112         # Now check that a second request gets the gzip header and gzipped body
113         # This also tests a bug in 3.0 to 3.0.2 whereby the cached, gzipped
114         # response body was being gzipped a second time.
115         self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')])
116         self.assertHeader('Content-Encoding', 'gzip')
117         self.assertEqual(cherrypy.lib.encoding.decompress(self.body), "visit #5")
118        
119         # Now check that a third request that doesn't accept gzip
120         # skips the cache (because the 'Vary' header denies it).
121         self.getPage("/", method="GET")
122         self.assertNoHeader('Content-Encoding')
123         self.assertBody('visit #6')
124    
125     def testExpiresTool(self):
126        
127         # test setting an expires header
128         self.getPage("/expires/specific")
129         self.assertStatus("200 OK")
130         self.assertHeader("Expires")
131        
132         # test exceptions for bad time values
133         self.getPage("/expires/wrongtype")
134         self.assertStatus(500)
135         self.assertInBody("TypeError")
136        
137         # static content should not have "cache prevention" headers
138         self.getPage("/expires/index.html")
139         self.assertStatus("200 OK")
140         self.assertNoHeader("Pragma")
141         self.assertNoHeader("Cache-Control")
142        
143         # dynamic content that sets indicators should not have
144         # "cache prevention" headers
145         self.getPage("/expires/cacheable")
146         self.assertStatus("200 OK")
147         self.assertNoHeader("Pragma")
148         self.assertNoHeader("Cache-Control")
149        
150         self.getPage('/expires/dynamic')
151         self.assertBody("D-d-d-dynamic!")
152         # the Cache-Control header should be untouched
153         self.assertHeader("Cache-Control", "private")
154        
155         # configure the tool to ignore indicators and replace existing headers
156         self.getPage("/expires/force")
157         self.assertStatus("200 OK")
158         # This also gives us a chance to test 0 expiry with no other headers
159         self.assertHeader("Pragma", "no-cache")
160         if cherrypy.server.protocol_version == "HTTP/1.1":
161             self.assertHeader("Cache-Control", "no-cache, must-revalidate")
162         self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
163        
164         # static content should now have "cache prevention" headers
165         self.getPage("/expires/index.html")
166         self.assertStatus("200 OK")
167         self.assertHeader("Pragma", "no-cache")
168         if cherrypy.server.protocol_version == "HTTP/1.1":
169             self.assertHeader("Cache-Control", "no-cache, must-revalidate")
170         self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
171        
172         # the cacheable handler should now have "cache prevention" headers
173         self.getPage("/expires/cacheable")
174         self.assertStatus("200 OK")
175         self.assertHeader("Pragma", "no-cache")
176         if cherrypy.server.protocol_version == "HTTP/1.1":
177             self.assertHeader("Cache-Control", "no-cache, must-revalidate")
178         self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
179        
180         self.getPage('/expires/dynamic')
181         self.assertBody("D-d-d-dynamic!")
182         # dynamic sets Cache-Control to private but it should  be
183         # overwritten here ...
184         self.assertHeader("Pragma", "no-cache")
185         if cherrypy.server.protocol_version == "HTTP/1.1":
186             self.assertHeader("Cache-Control", "no-cache, must-revalidate")
187         self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
188    
189     def testLastModified(self):
190         self.getPage("/a.gif")
191         self.assertStatus(200)
192         self.assertBody(gif_bytes)
193         lm1 = self.assertHeader("Last-Modified")
194        
195         # this request should get the cached copy.
196         self.getPage("/a.gif")
197         self.assertStatus(200)
198         self.assertBody(gif_bytes)
199         self.assertHeader("Age")
200         lm2 = self.assertHeader("Last-Modified")
201         self.assertEqual(lm1, lm2)
202        
203         # this request should match the cached copy, but raise 304.
204         self.getPage("/a.gif", [('If-Modified-Since', lm1)])
205         self.assertStatus(304)
206         self.assertNoHeader("Last-Modified")
207         self.assertHeader("Age")
208
209
210 if __name__ == '__main__':
211     setup_server()
212     helper.testmain()
213
Note: See TracBrowser for help on using the browser.

Hosted by WebFaction

Log in as guest/cpguest to create tickets