test_caching.py (10415B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\cherrypy\test\test_caching.py 2 import datetime 3 import gzip 4 from itertools import count 5 import os 6 curdir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 7 import sys 8 import threading 9 import time 10 import urllib 11 import cherrypy 12 from cherrypy._cpcompat import next, ntob, quote, xrange 13 from cherrypy.lib import httputil 14 gif_bytes = ntob('GIF89a\x01\x00\x01\x00\x82\x00\x01\x99"\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x02\x03\x02\x08\t\x00;') 15 from cherrypy.test import helper 16 17 class CacheTest(helper.CPWebCase): 18 19 def setup_server(): 20 21 class Root: 22 _cp_config = {'tools.caching.on': True} 23 24 def __init__(self): 25 self.counter = 0 26 self.control_counter = 0 27 self.longlock = threading.Lock() 28 29 def index(self): 30 self.counter += 1 31 msg = 'visit #%s' % self.counter 32 return msg 33 34 index.exposed = True 35 36 def control(self): 37 self.control_counter += 1 38 return 'visit #%s' % self.control_counter 39 40 control.exposed = True 41 42 def a_gif(self): 43 cherrypy.response.headers['Last-Modified'] = httputil.HTTPDate() 44 return gif_bytes 45 46 a_gif.exposed = True 47 48 def long_process(self, seconds = '1'): 49 try: 50 self.longlock.acquire() 51 time.sleep(float(seconds)) 52 finally: 53 self.longlock.release() 54 55 return 'success!' 56 57 long_process.exposed = True 58 59 def clear_cache(self, path): 60 cherrypy._cache.store[cherrypy.request.base + path].clear() 61 62 clear_cache.exposed = True 63 64 class VaryHeaderCachingServer(object): 65 _cp_config = {'tools.caching.on': True, 66 'tools.response_headers.on': True, 67 'tools.response_headers.headers': [('Vary', 'Our-Varying-Header')]} 68 69 def __init__(self): 70 self.counter = count(1) 71 72 def index(self): 73 return 'visit #%s' % next(self.counter) 74 75 index.exposed = True 76 77 class UnCached(object): 78 _cp_config = {'tools.expires.on': True, 79 'tools.expires.secs': 60, 80 'tools.staticdir.on': True, 81 'tools.staticdir.dir': 'static', 82 'tools.staticdir.root': curdir} 83 84 def force(self): 85 cherrypy.response.headers['Etag'] = 'bibbitybobbityboo' 86 self._cp_config['tools.expires.force'] = True 87 self._cp_config['tools.expires.secs'] = 0 88 return 'being forceful' 89 90 force.exposed = True 91 force._cp_config = {'tools.expires.secs': 0} 92 93 def dynamic(self): 94 cherrypy.response.headers['Etag'] = 'bibbitybobbityboo' 95 cherrypy.response.headers['Cache-Control'] = 'private' 96 return 'D-d-d-dynamic!' 97 98 dynamic.exposed = True 99 100 def cacheable(self): 101 cherrypy.response.headers['Etag'] = 'bibbitybobbityboo' 102 return "Hi, I'm cacheable." 103 104 cacheable.exposed = True 105 106 def specific(self): 107 cherrypy.response.headers['Etag'] = 'need_this_to_make_me_cacheable' 108 return 'I am being specific' 109 110 specific.exposed = True 111 specific._cp_config = {'tools.expires.secs': 86400} 112 113 class Foo(object): 114 pass 115 116 def wrongtype(self): 117 cherrypy.response.headers['Etag'] = 'need_this_to_make_me_cacheable' 118 return 'Woops' 119 120 wrongtype.exposed = True 121 wrongtype._cp_config = {'tools.expires.secs': Foo()} 122 123 cherrypy.tree.mount(Root()) 124 cherrypy.tree.mount(UnCached(), '/expires') 125 cherrypy.tree.mount(VaryHeaderCachingServer(), '/varying_headers') 126 cherrypy.config.update({'tools.gzip.on': True}) 127 128 setup_server = staticmethod(setup_server) 129 130 def testCaching(self): 131 elapsed = 0.0 132 for trial in range(10): 133 self.getPage('/') 134 self.assertBody('visit #1') 135 if trial != 0: 136 age = int(self.assertHeader('Age')) 137 self.assert_(age >= elapsed) 138 elapsed = age 139 140 self.getPage('/', method='POST') 141 self.assertBody('visit #2') 142 self.assertHeader('Vary', 'Accept-Encoding') 143 self.getPage('/', method='GET') 144 self.assertBody('visit #3') 145 self.getPage('/', method='GET') 146 self.assertBody('visit #3') 147 self.getPage('/', method='DELETE') 148 self.assertBody('visit #4') 149 self.getPage('/', method='GET', headers=[('Accept-Encoding', 'gzip')]) 150 self.assertHeader('Content-Encoding', 'gzip') 151 self.assertHeader('Vary') 152 self.assertEqual(cherrypy.lib.encoding.decompress(self.body), ntob('visit #5')) 153 self.getPage('/', method='GET', headers=[('Accept-Encoding', 'gzip')]) 154 self.assertHeader('Content-Encoding', 'gzip') 155 self.assertEqual(cherrypy.lib.encoding.decompress(self.body), ntob('visit #5')) 156 self.getPage('/', method='GET') 157 self.assertNoHeader('Content-Encoding') 158 self.assertBody('visit #6') 159 160 def testVaryHeader(self): 161 self.getPage('/varying_headers/') 162 self.assertStatus('200 OK') 163 self.assertHeaderItemValue('Vary', 'Our-Varying-Header') 164 self.assertBody('visit #1') 165 self.getPage('/varying_headers/', headers=[('Our-Varying-Header', 'request 2')]) 166 self.assertStatus('200 OK') 167 self.assertBody('visit #2') 168 self.getPage('/varying_headers/', headers=[('Our-Varying-Header', 'request 2')]) 169 self.assertStatus('200 OK') 170 self.assertBody('visit #2') 171 self.getPage('/varying_headers/') 172 self.assertStatus('200 OK') 173 self.assertBody('visit #1') 174 175 def testExpiresTool(self): 176 self.getPage('/expires/specific') 177 self.assertStatus('200 OK') 178 self.assertHeader('Expires') 179 self.getPage('/expires/wrongtype') 180 self.assertStatus(500) 181 self.assertInBody('TypeError') 182 self.getPage('/expires/index.html') 183 self.assertStatus('200 OK') 184 self.assertNoHeader('Pragma') 185 self.assertNoHeader('Cache-Control') 186 self.assertHeader('Expires') 187 self.getPage('/expires/cacheable') 188 self.assertStatus('200 OK') 189 self.assertNoHeader('Pragma') 190 self.assertNoHeader('Cache-Control') 191 self.assertHeader('Expires') 192 self.getPage('/expires/dynamic') 193 self.assertBody('D-d-d-dynamic!') 194 self.assertHeader('Cache-Control', 'private') 195 self.assertHeader('Expires') 196 self.getPage('/expires/force') 197 self.assertStatus('200 OK') 198 self.assertHeader('Pragma', 'no-cache') 199 if cherrypy.server.protocol_version == 'HTTP/1.1': 200 self.assertHeader('Cache-Control', 'no-cache, must-revalidate') 201 self.assertHeader('Expires', 'Sun, 28 Jan 2007 00:00:00 GMT') 202 self.getPage('/expires/index.html') 203 self.assertStatus('200 OK') 204 self.assertHeader('Pragma', 'no-cache') 205 if cherrypy.server.protocol_version == 'HTTP/1.1': 206 self.assertHeader('Cache-Control', 'no-cache, must-revalidate') 207 self.assertHeader('Expires', 'Sun, 28 Jan 2007 00:00:00 GMT') 208 self.getPage('/expires/cacheable') 209 self.assertStatus('200 OK') 210 self.assertHeader('Pragma', 'no-cache') 211 if cherrypy.server.protocol_version == 'HTTP/1.1': 212 self.assertHeader('Cache-Control', 'no-cache, must-revalidate') 213 self.assertHeader('Expires', 'Sun, 28 Jan 2007 00:00:00 GMT') 214 self.getPage('/expires/dynamic') 215 self.assertBody('D-d-d-dynamic!') 216 self.assertHeader('Pragma', 'no-cache') 217 if cherrypy.server.protocol_version == 'HTTP/1.1': 218 self.assertHeader('Cache-Control', 'no-cache, must-revalidate') 219 self.assertHeader('Expires', 'Sun, 28 Jan 2007 00:00:00 GMT') 220 221 def testLastModified(self): 222 self.getPage('/a.gif') 223 self.assertStatus(200) 224 self.assertBody(gif_bytes) 225 lm1 = self.assertHeader('Last-Modified') 226 self.getPage('/a.gif') 227 self.assertStatus(200) 228 self.assertBody(gif_bytes) 229 self.assertHeader('Age') 230 lm2 = self.assertHeader('Last-Modified') 231 self.assertEqual(lm1, lm2) 232 self.getPage('/a.gif', [('If-Modified-Since', lm1)]) 233 self.assertStatus(304) 234 self.assertNoHeader('Last-Modified') 235 if not getattr(cherrypy.server, 'using_apache', False): 236 self.assertHeader('Age') 237 238 def test_antistampede(self): 239 SECONDS = 4 240 self.getPage('/long_process?seconds=%d' % SECONDS) 241 self.assertBody('success!') 242 self.getPage('/clear_cache?path=' + quote('/long_process?seconds=%d' % SECONDS, safe='')) 243 self.assertStatus(200) 244 sys.stdout.write('prepped... ') 245 sys.stdout.flush() 246 start = datetime.datetime.now() 247 248 def run(): 249 self.getPage('/long_process?seconds=%d' % SECONDS) 250 self.assertBody('success!') 251 252 ts = [ threading.Thread(target=run) for i in xrange(100) ] 253 for t in ts: 254 t.start() 255 256 for t in ts: 257 t.join() 258 259 self.assertEqualDates(start, datetime.datetime.now(), seconds=SECONDS + 1.1) 260 261 def test_cache_control(self): 262 self.getPage('/control') 263 self.assertBody('visit #1') 264 self.getPage('/control') 265 self.assertBody('visit #1') 266 self.getPage('/control', headers=[('Cache-Control', 'no-cache')]) 267 self.assertBody('visit #2') 268 self.getPage('/control') 269 self.assertBody('visit #2') 270 self.getPage('/control', headers=[('Pragma', 'no-cache')]) 271 self.assertBody('visit #3') 272 self.getPage('/control') 273 self.assertBody('visit #3') 274 time.sleep(1) 275 self.getPage('/control', headers=[('Cache-Control', 'max-age=0')]) 276 self.assertBody('visit #4') 277 self.getPage('/control') 278 self.assertBody('visit #4')