--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/unittest_http.py Thu Mar 15 17:59:27 2012 +0100
@@ -0,0 +1,282 @@
+from logilab.common.testlib import TestCase, unittest_main, tag, Tags
+
+from cubicweb.web import StatusResponse
+from cubicweb.devtools.fake import FakeRequest
+
+
+def _test_cache(hin, hout, method='GET'):
+ """forge and process a request
+
+ return status code and the request object
+
+ status is None is no cache is involved
+ """
+ # forge request
+ req = FakeRequest(method=method)
+ for key, value in hin:
+ req._headers_in.addRawHeader(key, str(value))
+ for key, value in hout:
+ req.headers_out.addRawHeader(key, str(value))
+ # process
+ status = None
+ try:
+ req.validate_cache()
+ except StatusResponse, ex:
+ status = ex.status
+ return status, req
+
+class HTTPCache(TestCase):
+ """Check that the http cache logiac work as expected
+ (as far as we understood the RFC)
+
+ """
+ tags = TestCase.tags | Tags('http', 'cache')
+
+
+ def assertCache(self, expected, status, situation=''):
+ """simple assert for nicer message"""
+ if expected != status:
+ if expected is None:
+ expected = "MODIFIED"
+ if status is None:
+ status = "MODIFIED"
+ msg = 'expected %r got %r' % (expected, status)
+ if situation:
+ msg = "%s - when: %s" % (msg, situation)
+ self.fail(msg)
+
+ def test_IN_none_OUT_none(self):
+ #: test that no caching is requested when not data is available
+ #: on any side
+ status, req =_test_cache((),())
+ self.assertIsNone(status)
+
+ def test_IN_Some_OUT_none(self):
+ #: test that no caching is requested when no data is available
+ #: server (origin) side
+ hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, ())
+ self.assertIsNone(status)
+ hin = [('if-none-match','babar/huitre'),
+ ]
+ status, req = _test_cache(hin, ())
+ self.assertIsNone(status)
+ hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
+ ('if-none-match','babar/huitre'),
+ ]
+ status, req = _test_cache(hin, ())
+ self.assertIsNone(status)
+
+ def test_IN_none_OUT_Some(self):
+ #: test that no caching is requested when no data is provided
+ #: by the client
+ hout = [('last-modified','Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache((), hout)
+ self.assertIsNone(status)
+ hout = [('etag','babar/huitre'),
+ ]
+ status, req = _test_cache((), hout)
+ self.assertIsNone(status)
+ hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ('etag','babar/huitre'),
+ ]
+ status, req = _test_cache((), hout)
+ self.assertIsNone(status)
+
+ @tag('last_modified')
+ def test_last_modified_newer(self):
+ #: test the proper behavior of modification date only
+ # newer
+ hin = [('if-modified-since', 'Sat, 13 Apr 2012 14:39:32 GM'),
+ ]
+ hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(None, status, 'origin is newer than client')
+
+ @tag('last_modified')
+ def test_last_modified_older(self):
+ # older
+ hin = [('if-modified-since', 'Sat, 15 Apr 2012 14:39:32 GM'),
+ ]
+ hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(304, status, 'origin is older than client')
+
+ @tag('last_modified')
+ def test_last_modified_same(self):
+ # same
+ hin = [('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(304, status, 'origin is equal to client')
+
+ @tag('etag')
+ def test_etag_mismatch(self):
+ #: test the proper behavior of etag only
+ # etag mismatch
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'celestine'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(None, status, 'etag mismatch')
+
+ @tag('etag')
+ def test_etag_match(self):
+ # etag match
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'babar'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(304, status, 'etag match')
+ # etag match in multiple
+ hin = [('if-none-match', 'loutre'),
+ ('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'babar'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(304, status, 'etag match in multiple')
+ # client use "*" as etag
+ hin = [('if-none-match', '*'),
+ ]
+ hout = [('etag', 'babar'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(304, status, 'client use "*" as etag')
+
+ @tag('etag', 'last_modified')
+ def test_both(self):
+ #: test the proper behavior of etag only
+ # both wrong
+ hin = [('if-none-match', 'babar'),
+ ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ hout = [('etag', 'loutre'),
+ ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(None, status, 'both wrong')
+
+ @tag('etag', 'last_modified')
+ def test_both_etag_mismatch(self):
+ # both etag mismatch
+ hin = [('if-none-match', 'babar'),
+ ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ hout = [('etag', 'loutre'),
+ ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(None, status, 'both but etag mismatch')
+
+ @tag('etag', 'last_modified')
+ def test_both_but_modified(self):
+ # both but modified
+ hin = [('if-none-match', 'babar'),
+ ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ hout = [('etag', 'babar'),
+ ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(None, status, 'both but modified')
+
+ @tag('etag', 'last_modified')
+ def test_both_ok(self):
+ # both ok
+ hin = [('if-none-match', 'babar'),
+ ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
+ ]
+ hout = [('etag', 'babar'),
+ ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(304, status, 'both ok')
+
+ @tag('etag', 'HEAD')
+ def test_head_verb(self):
+ #: check than FOUND 200 is properly raise without content on HEAD request
+ #: This logic does not really belong here :-/
+ # modified
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'rhino/really-not-babar'),
+ ]
+ status, req = _test_cache(hin, hout, method='HEAD')
+ self.assertCache(200, status, 'modifier HEAD verb')
+ # not modified
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'babar'),
+ ]
+ status, req = _test_cache(hin, hout, method='HEAD')
+ self.assertCache(304, status, 'not modifier HEAD verb')
+
+ @tag('etag', 'POST')
+ def test_post_verb(self):
+ # modified
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'rhino/really-not-babar'),
+ ]
+ status, req = _test_cache(hin, hout, method='POST')
+ self.assertCache(None, status, 'modifier HEAD verb')
+ # not modified
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'babar'),
+ ]
+ status, req = _test_cache(hin, hout, method='POST')
+ self.assertCache(412, status, 'not modifier HEAD verb')
+
+ @tag('expires')
+ def test_expires_added(self):
+ #: Check that Expires header is added:
+ #: - when the page is modified
+ #: - when none was already present
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'rhino/really-not-babar'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(None, status, 'modifier HEAD verb')
+ value = req.headers_out.getHeader('expires')
+ self.assertIsNotNone(value)
+
+ @tag('expires')
+ def test_expires_not_added(self):
+ #: Check that Expires header is not added if NOT-MODIFIED
+ hin = [('if-none-match', 'babar'),
+ ]
+ hout = [('etag', 'babar'),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(304, status, 'not modifier HEAD verb')
+ value = req.headers_out.getHeader('expires')
+ self.assertIsNone(value)
+
+ @tag('expires')
+ def test_expires_no_overwrite(self):
+ #: Check that cache does not overwrite existing Expires header
+ hin = [('if-none-match', 'babar'),
+ ]
+ DATE = 'Sat, 13 Apr 2012 14:39:32 GM'
+ hout = [('etag', 'rhino/really-not-babar'),
+ ('expires', DATE),
+ ]
+ status, req = _test_cache(hin, hout)
+ self.assertCache(None, status, 'not modifier HEAD verb')
+ value = req.headers_out.getRawHeaders('expires')
+ self.assertEqual(value, [DATE])
+
+
+if __name__ == '__main__':
+ unittest_main()