web/test/unittest_http.py
changeset 8316 d5b1b75805dd
child 8695 358d8bed9626
equal deleted inserted replaced
8315:166e6d5d8e17 8316:d5b1b75805dd
       
     1 from logilab.common.testlib import TestCase, unittest_main, tag, Tags
       
     2 
       
     3 from cubicweb.web import StatusResponse
       
     4 from cubicweb.devtools.fake import FakeRequest
       
     5 
       
     6 
       
     7 def _test_cache(hin, hout, method='GET'):
       
     8     """forge and process a request
       
     9 
       
    10     return status code and the request object
       
    11 
       
    12     status is None is no cache is involved
       
    13     """
       
    14     # forge request
       
    15     req = FakeRequest(method=method)
       
    16     for key, value in hin:
       
    17         req._headers_in.addRawHeader(key, str(value))
       
    18     for key, value in hout:
       
    19         req.headers_out.addRawHeader(key, str(value))
       
    20     # process
       
    21     status = None
       
    22     try:
       
    23         req.validate_cache()
       
    24     except StatusResponse, ex:
       
    25         status = ex.status
       
    26     return status, req
       
    27 
       
    28 class HTTPCache(TestCase):
       
    29     """Check that the http cache logiac work as expected
       
    30     (as far as we understood the RFC)
       
    31 
       
    32     """
       
    33     tags = TestCase.tags | Tags('http', 'cache')
       
    34 
       
    35 
       
    36     def assertCache(self, expected, status, situation=''):
       
    37         """simple assert for nicer message"""
       
    38         if expected != status:
       
    39             if expected is None:
       
    40                 expected = "MODIFIED"
       
    41             if status is None:
       
    42                 status = "MODIFIED"
       
    43             msg = 'expected %r got %r' % (expected, status)
       
    44             if situation:
       
    45                 msg = "%s - when: %s" % (msg, situation)
       
    46             self.fail(msg)
       
    47 
       
    48     def test_IN_none_OUT_none(self):
       
    49         #: test that no caching is requested when not data is available
       
    50         #: on any side
       
    51         status, req =_test_cache((),())
       
    52         self.assertIsNone(status)
       
    53 
       
    54     def test_IN_Some_OUT_none(self):
       
    55         #: test that no caching is requested when no data is available
       
    56         #: server (origin) side
       
    57         hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
       
    58               ]
       
    59         status, req = _test_cache(hin, ())
       
    60         self.assertIsNone(status)
       
    61         hin = [('if-none-match','babar/huitre'),
       
    62               ]
       
    63         status, req = _test_cache(hin, ())
       
    64         self.assertIsNone(status)
       
    65         hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
       
    66                ('if-none-match','babar/huitre'),
       
    67               ]
       
    68         status, req = _test_cache(hin, ())
       
    69         self.assertIsNone(status)
       
    70 
       
    71     def test_IN_none_OUT_Some(self):
       
    72         #: test that no caching is requested when no data is provided
       
    73         #: by the client
       
    74         hout = [('last-modified','Sat, 14 Apr 2012 14:39:32 GM'),
       
    75                ]
       
    76         status, req = _test_cache((), hout)
       
    77         self.assertIsNone(status)
       
    78         hout = [('etag','babar/huitre'),
       
    79                ]
       
    80         status, req = _test_cache((), hout)
       
    81         self.assertIsNone(status)
       
    82         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
    83                 ('etag','babar/huitre'),
       
    84                ]
       
    85         status, req = _test_cache((), hout)
       
    86         self.assertIsNone(status)
       
    87 
       
    88     @tag('last_modified')
       
    89     def test_last_modified_newer(self):
       
    90         #: test the proper behavior of modification date only
       
    91         # newer
       
    92         hin  = [('if-modified-since', 'Sat, 13 Apr 2012 14:39:32 GM'),
       
    93                ]
       
    94         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
    95                ]
       
    96         status, req = _test_cache(hin, hout)
       
    97         self.assertCache(None, status, 'origin is newer than client')
       
    98 
       
    99     @tag('last_modified')
       
   100     def test_last_modified_older(self):
       
   101         # older
       
   102         hin  = [('if-modified-since', 'Sat, 15 Apr 2012 14:39:32 GM'),
       
   103                ]
       
   104         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
   105                ]
       
   106         status, req = _test_cache(hin, hout)
       
   107         self.assertCache(304, status, 'origin is older than client')
       
   108 
       
   109     @tag('last_modified')
       
   110     def test_last_modified_same(self):
       
   111         # same
       
   112         hin  = [('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
   113                ]
       
   114         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
   115                ]
       
   116         status, req = _test_cache(hin, hout)
       
   117         self.assertCache(304, status, 'origin is equal to client')
       
   118 
       
   119     @tag('etag')
       
   120     def test_etag_mismatch(self):
       
   121         #: test the proper behavior of etag only
       
   122         # etag mismatch
       
   123         hin  = [('if-none-match', 'babar'),
       
   124                ]
       
   125         hout = [('etag', 'celestine'),
       
   126                ]
       
   127         status, req = _test_cache(hin, hout)
       
   128         self.assertCache(None, status, 'etag mismatch')
       
   129 
       
   130     @tag('etag')
       
   131     def test_etag_match(self):
       
   132         # etag match
       
   133         hin  = [('if-none-match', 'babar'),
       
   134                ]
       
   135         hout = [('etag', 'babar'),
       
   136                ]
       
   137         status, req = _test_cache(hin, hout)
       
   138         self.assertCache(304, status, 'etag match')
       
   139         # etag match in multiple
       
   140         hin  = [('if-none-match', 'loutre'),
       
   141                 ('if-none-match', 'babar'),
       
   142                ]
       
   143         hout = [('etag', 'babar'),
       
   144                ]
       
   145         status, req = _test_cache(hin, hout)
       
   146         self.assertCache(304, status, 'etag match in multiple')
       
   147         # client use "*" as etag
       
   148         hin  = [('if-none-match', '*'),
       
   149                ]
       
   150         hout = [('etag', 'babar'),
       
   151                ]
       
   152         status, req = _test_cache(hin, hout)
       
   153         self.assertCache(304, status, 'client use "*" as etag')
       
   154 
       
   155     @tag('etag', 'last_modified')
       
   156     def test_both(self):
       
   157         #: test the proper behavior of etag only
       
   158         # both wrong
       
   159         hin  = [('if-none-match', 'babar'),
       
   160                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
   161                ]
       
   162         hout = [('etag', 'loutre'),
       
   163                 ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
       
   164                ]
       
   165         status, req = _test_cache(hin, hout)
       
   166         self.assertCache(None, status, 'both wrong')
       
   167 
       
   168     @tag('etag', 'last_modified')
       
   169     def test_both_etag_mismatch(self):
       
   170         # both etag mismatch
       
   171         hin  = [('if-none-match', 'babar'),
       
   172                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
   173                ]
       
   174         hout = [('etag', 'loutre'),
       
   175                 ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
       
   176                ]
       
   177         status, req = _test_cache(hin, hout)
       
   178         self.assertCache(None, status, 'both  but etag mismatch')
       
   179 
       
   180     @tag('etag', 'last_modified')
       
   181     def test_both_but_modified(self):
       
   182         # both but modified
       
   183         hin  = [('if-none-match', 'babar'),
       
   184                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
   185                ]
       
   186         hout = [('etag', 'babar'),
       
   187                 ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
       
   188                ]
       
   189         status, req = _test_cache(hin, hout)
       
   190         self.assertCache(None, status, 'both  but modified')
       
   191 
       
   192     @tag('etag', 'last_modified')
       
   193     def test_both_ok(self):
       
   194         # both ok
       
   195         hin  = [('if-none-match', 'babar'),
       
   196                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
       
   197                ]
       
   198         hout = [('etag', 'babar'),
       
   199                 ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
       
   200                ]
       
   201         status, req = _test_cache(hin, hout)
       
   202         self.assertCache(304, status, 'both ok')
       
   203 
       
   204     @tag('etag', 'HEAD')
       
   205     def test_head_verb(self):
       
   206         #: check than FOUND 200 is properly raise without content on HEAD request
       
   207         #: This logic does not really belong here :-/
       
   208         # modified
       
   209         hin  = [('if-none-match', 'babar'),
       
   210                ]
       
   211         hout = [('etag', 'rhino/really-not-babar'),
       
   212                ]
       
   213         status, req = _test_cache(hin, hout, method='HEAD')
       
   214         self.assertCache(200, status, 'modifier HEAD verb')
       
   215         # not modified
       
   216         hin  = [('if-none-match', 'babar'),
       
   217                ]
       
   218         hout = [('etag', 'babar'),
       
   219                ]
       
   220         status, req = _test_cache(hin, hout, method='HEAD')
       
   221         self.assertCache(304, status, 'not modifier HEAD verb')
       
   222 
       
   223     @tag('etag', 'POST')
       
   224     def test_post_verb(self):
       
   225         # modified
       
   226         hin  = [('if-none-match', 'babar'),
       
   227                ]
       
   228         hout = [('etag', 'rhino/really-not-babar'),
       
   229                ]
       
   230         status, req = _test_cache(hin, hout, method='POST')
       
   231         self.assertCache(None, status, 'modifier HEAD verb')
       
   232         # not modified
       
   233         hin  = [('if-none-match', 'babar'),
       
   234                ]
       
   235         hout = [('etag', 'babar'),
       
   236                ]
       
   237         status, req = _test_cache(hin, hout, method='POST')
       
   238         self.assertCache(412, status, 'not modifier HEAD verb')
       
   239 
       
   240     @tag('expires')
       
   241     def test_expires_added(self):
       
   242         #: Check that Expires header is added:
       
   243         #: - when the page is modified
       
   244         #: - when none was already present
       
   245         hin  = [('if-none-match', 'babar'),
       
   246                ]
       
   247         hout = [('etag', 'rhino/really-not-babar'),
       
   248                ]
       
   249         status, req = _test_cache(hin, hout)
       
   250         self.assertCache(None, status, 'modifier HEAD verb')
       
   251         value = req.headers_out.getHeader('expires')
       
   252         self.assertIsNotNone(value)
       
   253 
       
   254     @tag('expires')
       
   255     def test_expires_not_added(self):
       
   256         #: Check that Expires header is not added if NOT-MODIFIED
       
   257         hin  = [('if-none-match', 'babar'),
       
   258                ]
       
   259         hout = [('etag', 'babar'),
       
   260                ]
       
   261         status, req = _test_cache(hin, hout)
       
   262         self.assertCache(304, status, 'not modifier HEAD verb')
       
   263         value = req.headers_out.getHeader('expires')
       
   264         self.assertIsNone(value)
       
   265 
       
   266     @tag('expires')
       
   267     def test_expires_no_overwrite(self):
       
   268         #: Check that cache does not overwrite existing Expires header
       
   269         hin  = [('if-none-match', 'babar'),
       
   270                ]
       
   271         DATE = 'Sat, 13 Apr 2012 14:39:32 GM'
       
   272         hout = [('etag', 'rhino/really-not-babar'),
       
   273                 ('expires', DATE),
       
   274                ]
       
   275         status, req = _test_cache(hin, hout)
       
   276         self.assertCache(None, status, 'not modifier HEAD verb')
       
   277         value = req.headers_out.getRawHeaders('expires')
       
   278         self.assertEqual(value, [DATE])
       
   279 
       
   280 
       
   281 if __name__ == '__main__':
       
   282     unittest_main()