Commits

Eric Larson committed 96831bf

Update tests. Switched webtest for CherryPy. Fixes for Requests > 1.x.

  • Participants
  • Parent commits 21c0083
  • Tags 0.5

Comments (0)

Files changed (7)

-import os
-import py.test
-import subprocess
-import requests
-import time
+import pytest
+from webtest.http import StopableWSGIServer
 
+from httpcache.tests import SimpleApp
 
-class TestServer(object):
 
-    def start(self):
-        base = os.path.abspath(os.path.dirname(__file__))
-        server_file = os.path.join(base, 'httpcache', 'tests', 'server.py')
-        cmd = ['python', server_file]
-
-        kw = {}
-        if not os.environ.get('TEST_SERVER_OUTPUT'):
-            kw = {'stdout': subprocess.PIPE,
-                  'stderr': subprocess.STDOUT}
-        self.proc = subprocess.Popen(cmd, **kw)
-        url = 'http://localhost:8080'
-        up = None
-        while not up:
-            try:
-                up = requests.get(url)
-            except requests.ConnectionError:
-                time.sleep(1)
-
-    def stop(self):
-        self.proc.terminate()
+@pytest.fixture(scope='session')
+def server():
+    return pytest.server
 
 
 def pytest_namespace():
-    return dict(server=TestServer())
-
-
-def pytest_configure(config):
-    py.test.server.start()
+    return dict(server=StopableWSGIServer.create(SimpleApp()))
 
 
 def pytest_unconfigure(config):
-    py.test.server.stop()
+    pytest.server.shutdown()

File httpcache/__init__.py

     for the different directives.
     """
     retval = {}
-    if 'cache-control' in headers:
-        parts = headers['cache-control'].split(',')
+
+    cc_header = 'cache-control'
+    if 'Cache-Control' in headers:
+        cc_header = 'Cache-Control'
+    
+    if cc_header in headers:
+        parts = headers[cc_header].split(',')
         parts_with_args = [
             tuple([x.strip().lower() for x in part.split("=", 1)])
             for part in parts if -1 != part.find("=")]
 
         cc = _parse_cache_control(req.headers)
 
+        print(req.url, req.headers)
+        print(cc)
+
         # non-caching states
         no_cache = True if 'no-cache' in cc else False
         if 'max-age' in cc and cc['max-age'] == 0:
             return resp
         return invalidating_handler
 
+    # Handler wrappers
+    # NOTE: We create a _verb method b/c we need the verb in order to
+    #       create the Request object and handle the caching
+    #       correctly.
     def get(self, url, headers=None, *args, **kw):
         return self._get('GET', url, headers, *args, **kw)
 
+    def put(self, url, headers=None, *args, **kw):
+        return self._put('PUT', url, headers, *args, **kw)
+
+    def delete(self, url, headers=None, *args, **kw):
+        return self._delete('DELETE', url, headers, *args, **kw)
+
     @from_cache
     def _get(self, verb, url, headers=None, *args, **kw):
         resp = self.session.request(verb, url, headers=headers, *args, **kw)
         return resp
 
     @invalidates_cache
-    def put(self, *args, **kw):
+    def _put(self, *args, **kw):
         return self.session.put(*args, **kw)
 
     @invalidates_cache
-    def delete(self, *args, **kw):
+    def _delete(self, *args, **kw):
         return self.session.delete(*args, **kw)

File httpcache/cache.py

 The cache object API for implementing caches. The default is just a
 dictionary, which in turns means it is not threadsafe for writing.
 """
-import os
-import re
-import time
 
-from contextlib import contextmanager
-from cPickle import dump, load
-from hashlib import md5
+from threading import Lock
 
 
 class BaseCache(object):
 class DictCache(BaseCache):
 
     def __init__(self, init_dict=None):
+        self.lock = Lock()
         self.data = init_dict or {}
 
     def get(self, key):
+        if key in self.data:
+            print('CACHE HIT: %s' % key)
+        else:
+            print('CACHE MISS: %s' % key)
         return self.data.get(key, None)
 
     def set(self, key, value):
-        self.data.update({key: value})
+        with self.lock:
+            self.data.update({key: value})
 
     def delete(self, key):
-        if key in self.data:
-            self.data.pop(key)
+        with self.lock:
+            if key in self.data:
+                self.data.pop(key)

File httpcache/tests/__init__.py

+class SimpleApp(object):
+
+    def __call__(self, env, start_response):
+        handler = filter(bool, env['PATH_INFO'].split('/'))[-1].lower()
+        return getattr(self, handler)(env, start_response)
+
+    def max_age(self, env, start_response):
+        headers = [
+            ('Cache-Control', 'max-age=5000')
+        ]
+        start_response('200 OK', headers)
+        return 'Hello World!'

File httpcache/tests/test_cache_control.py

 
     def req(self, headers=None):
         headers = headers or {}
-        return mock.Mock(full_url=self.url, headers=headers)
+        return mock.Mock(full_url=self.url,  # < 1.x support
+                         url=self.url,
+                         headers=headers)
 
     def resp(self, headers=None):
         headers = headers or {}
 class TestCacheControlRequest(object):
 
     url = 'http://foo.com'
+    verb = 'GET'
 
     def test_cache_request_no_cache(self):
         c = CacheControl(mock.Mock())
         hdrs = {'cache-control': 'no-cache'}
-        resp = c.cached_request(self.url, headers=hdrs)
+        resp = c.cached_request(self.verb, self.url, headers=hdrs)
         assert not resp
 
     def test_cache_request_pragma_no_cache(self):
         c = CacheControl(mock.Mock())
         hdrs = {'pragma': 'no-cache'}
-        resp = c.cached_request(self.url, headers=hdrs)
+        resp = c.cached_request(self.verb, self.url, headers=hdrs)
         assert not resp
 
     def test_cache_request_no_store(self):
         c = CacheControl(mock.Mock())
         hdrs = {'cache-control': 'no-store'}
-        resp = c.cached_request(self.url, headers=hdrs)
+        resp = c.cached_request(self.verb, self.url, headers=hdrs)
         assert not resp
 
     def test_cache_request_max_age_0(self):
         c = CacheControl(mock.Mock())
         hdrs = {'cache-control': 'max-age=0'}
-        resp = c.cached_request(self.url, headers=hdrs)
+        resp = c.cached_request(self.verb, self.url, headers=hdrs)
         assert not resp
 
     def test_cache_request_not_in_cache(self):
         c = CacheControl(mock.Mock())
-        resp = c.cached_request(self.url)
+        resp = c.cached_request(self.verb, self.url)
         assert not resp
 
     def test_cache_request_fresh_max_age(self):
         # b/c of the auto directory rules. I'm trusting it is correct.
         cache = DictCache({self.url + '/': resp})
         c = CacheControl(mock.Mock(), cache)
-        r = c.cached_request(self.url)
+        r = c.cached_request(self.verb, self.url)
         assert r == resp
 
     def test_cache_request_unfresh_max_age(self):
                                   'date': now})
         cache = DictCache({self.url: resp})
         c = CacheControl(mock.Mock(), cache)
-        r = c.cached_request(self.url)
+        r = c.cached_request(self.verb, self.url)
         assert not r
 
     def test_cache_request_fresh_expires(self):
                                   'date': now})
         cache = DictCache({self.url + '/': resp})
         c = CacheControl(mock.Mock, cache)
-        r = c.cached_request(self.url)
+        r = c.cached_request(self.verb, self.url)
         assert r == resp
 
     def test_cache_request_unfresh_expires(self):
                                   'date': now})
         cache = DictCache({self.url: resp})
         c = CacheControl(mock.Mock, cache)
-        r = c.cached_request(self.url)
+        r = c.cached_request(self.verb, self.url)
         assert not r

File httpcache/tests/test_cache_invalidation.py

     url = 'http://foo.com/bar/'
 
     def resp(self):
-        req = mock.Mock(full_url=self.url)
+        req = mock.Mock(full_url=self.url, url=self.url)
         return mock.Mock(request=req)
 
     def test_put_invalidates_cache(self):

File httpcache/tests/test_max_age.py

 
 class TestMaxAge(object):
 
-    def test_client_max_age_0(self):
+    def test_client_max_age_0(self, server):
         """
         Making sure when the client uses max-age=0 we don't get a
         cached copy even though we're still fresh.
         """
-        url = 'http://localhost:8080/max_age/'
+        url = server.application_url + 'max_age'
         s = requests.Session()
         c = CacheControl(s, {})
         print('first request')
 
         # don't remove from the cache
         assert c.cache.get(cache_url)
-        assert r.from_cache == False
+        assert r.from_cache is False
 
-    def test_client_max_age_3600(self):
+    def test_client_max_age_3600(self, server):
         """
         Verify we get a cached value when the client has a
         reasonable max-age value.
         """
         # prep our cache
-        url = 'http://localhost:8080/max_age/'
+        url = server.application_url + 'max_age'
         s = requests.Session()
         c = CacheControl(s, {})
         r = c.get(url)
 
         # request that we don't want a new one unless
         r = c.get(url, headers={'Cache-Control': 'max-age=3600'})
-        assert r.from_cache == True
+        assert r.from_cache is True
 
         # now lets grab one that forces a new request b/c the cache
         # has expired. To do that we'll inject a new time value.
         resp = c.cache.get(cache_url)
         resp.headers['date'] = 'Tue, 15 Nov 1994 08:12:31 GMT'
         r = c.get(url)
-        assert r.from_cache == False
+        assert r.from_cache is False