web/test/unittest_http.py
branchstable
changeset 9229 739ae5366bed
parent 8695 358d8bed9626
child 9571 aaf83cc07eed
equal deleted inserted replaced
9228:90b8c7a7e205 9229:739ae5366bed
       
     1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
     1 from logilab.common.testlib import TestCase, unittest_main, tag, Tags
    18 from logilab.common.testlib import TestCase, unittest_main, tag, Tags
     2 
    19 
     3 from cubicweb.web import StatusResponse
       
     4 from cubicweb.devtools.fake import FakeRequest
    20 from cubicweb.devtools.fake import FakeRequest
     5 
    21 
     6 
    22 
     7 def _test_cache(hin, hout, method='GET'):
    23 def _test_cache(hin, hout, method='GET'):
     8     """forge and process a request
    24     """forge and process an HTTP request using given headers in/out and method,
     9 
    25     then return it once its .is_client_cache_valid() method has been called.
    10     return status code and the request object
    26 
    11 
    27     req.status_out is None if the page should have been calculated.
    12     status is None is no cache is involved
       
    13     """
    28     """
    14     # forge request
    29     # forge request
    15     req = FakeRequest(method=method)
    30     req = FakeRequest(method=method)
    16     for key, value in hin:
    31     for key, value in hin:
    17         req._headers_in.addRawHeader(key, str(value))
    32         req._headers_in.addRawHeader(key, str(value))
    18     for key, value in hout:
    33     for key, value in hout:
    19         req.headers_out.addRawHeader(key, str(value))
    34         req.headers_out.addRawHeader(key, str(value))
    20     # process
    35     # process
    21     status = None
    36     req.status_out = None
    22     try:
    37     req.is_client_cache_valid()
    23         req.validate_cache()
    38     return req
    24     except StatusResponse as ex:
       
    25         status = ex.status
       
    26     return status, req
       
    27 
    39 
    28 class HTTPCache(TestCase):
    40 class HTTPCache(TestCase):
    29     """Check that the http cache logiac work as expected
    41     """Check that the http cache logiac work as expected
    30     (as far as we understood the RFC)
    42     (as far as we understood the RFC)
    31 
    43 
    46             self.fail(msg)
    58             self.fail(msg)
    47 
    59 
    48     def test_IN_none_OUT_none(self):
    60     def test_IN_none_OUT_none(self):
    49         #: test that no caching is requested when not data is available
    61         #: test that no caching is requested when not data is available
    50         #: on any side
    62         #: on any side
    51         status, req =_test_cache((),())
    63         req =_test_cache((), ())
    52         self.assertIsNone(status)
    64         self.assertIsNone(req.status_out)
    53 
    65 
    54     def test_IN_Some_OUT_none(self):
    66     def test_IN_Some_OUT_none(self):
    55         #: test that no caching is requested when no data is available
    67         #: test that no caching is requested when no data is available
    56         #: server (origin) side
    68         #: server (origin) side
    57         hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
    69         hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
    58               ]
    70               ]
    59         status, req = _test_cache(hin, ())
    71         req = _test_cache(hin, ())
    60         self.assertIsNone(status)
    72         self.assertIsNone(req.status_out)
    61         hin = [('if-none-match','babar/huitre'),
    73         hin = [('if-none-match','babar/huitre'),
    62               ]
    74               ]
    63         status, req = _test_cache(hin, ())
    75         req = _test_cache(hin, ())
    64         self.assertIsNone(status)
    76         self.assertIsNone(req.status_out)
    65         hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
    77         hin = [('if-modified-since','Sat, 14 Apr 2012 14:39:32 GM'),
    66                ('if-none-match','babar/huitre'),
    78                ('if-none-match','babar/huitre'),
    67               ]
    79               ]
    68         status, req = _test_cache(hin, ())
    80         req = _test_cache(hin, ())
    69         self.assertIsNone(status)
    81         self.assertIsNone(req.status_out)
    70 
    82 
    71     def test_IN_none_OUT_Some(self):
    83     def test_IN_none_OUT_Some(self):
    72         #: test that no caching is requested when no data is provided
    84         #: test that no caching is requested when no data is provided
    73         #: by the client
    85         #: by the client
    74         hout = [('last-modified','Sat, 14 Apr 2012 14:39:32 GM'),
    86         hout = [('last-modified','Sat, 14 Apr 2012 14:39:32 GM'),
    75                ]
    87                ]
    76         status, req = _test_cache((), hout)
    88         req = _test_cache((), hout)
    77         self.assertIsNone(status)
    89         self.assertIsNone(req.status_out)
    78         hout = [('etag','babar/huitre'),
    90         hout = [('etag','babar/huitre'),
    79                ]
    91                ]
    80         status, req = _test_cache((), hout)
    92         req = _test_cache((), hout)
    81         self.assertIsNone(status)
    93         self.assertIsNone(req.status_out)
    82         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
    94         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
    83                 ('etag','babar/huitre'),
    95                 ('etag','babar/huitre'),
    84                ]
    96                ]
    85         status, req = _test_cache((), hout)
    97         req = _test_cache((), hout)
    86         self.assertIsNone(status)
    98         self.assertIsNone(req.status_out)
    87 
    99 
    88     @tag('last_modified')
   100     @tag('last_modified')
    89     def test_last_modified_newer(self):
   101     def test_last_modified_newer(self):
    90         #: test the proper behavior of modification date only
   102         #: test the proper behavior of modification date only
    91         # newer
   103         # newer
    92         hin  = [('if-modified-since', 'Sat, 13 Apr 2012 14:39:32 GM'),
   104         hin  = [('if-modified-since', 'Sat, 13 Apr 2012 14:39:32 GM'),
    93                ]
   105                ]
    94         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
   106         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
    95                ]
   107                ]
    96         status, req = _test_cache(hin, hout)
   108         req = _test_cache(hin, hout)
    97         self.assertCache(None, status, 'origin is newer than client')
   109         self.assertCache(None, req.status_out, 'origin is newer than client')
    98 
   110 
    99     @tag('last_modified')
   111     @tag('last_modified')
   100     def test_last_modified_older(self):
   112     def test_last_modified_older(self):
   101         # older
   113         # older
   102         hin  = [('if-modified-since', 'Sat, 15 Apr 2012 14:39:32 GM'),
   114         hin  = [('if-modified-since', 'Sat, 15 Apr 2012 14:39:32 GM'),
   103                ]
   115                ]
   104         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
   116         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
   105                ]
   117                ]
   106         status, req = _test_cache(hin, hout)
   118         req = _test_cache(hin, hout)
   107         self.assertCache(304, status, 'origin is older than client')
   119         self.assertCache(304, req.status_out, 'origin is older than client')
   108 
   120 
   109     @tag('last_modified')
   121     @tag('last_modified')
   110     def test_last_modified_same(self):
   122     def test_last_modified_same(self):
   111         # same
   123         # same
   112         hin  = [('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   124         hin  = [('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   113                ]
   125                ]
   114         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
   126         hout = [('last-modified', 'Sat, 14 Apr 2012 14:39:32 GM'),
   115                ]
   127                ]
   116         status, req = _test_cache(hin, hout)
   128         req = _test_cache(hin, hout)
   117         self.assertCache(304, status, 'origin is equal to client')
   129         self.assertCache(304, req.status_out, 'origin is equal to client')
   118 
   130 
   119     @tag('etag')
   131     @tag('etag')
   120     def test_etag_mismatch(self):
   132     def test_etag_mismatch(self):
   121         #: test the proper behavior of etag only
   133         #: test the proper behavior of etag only
   122         # etag mismatch
   134         # etag mismatch
   123         hin  = [('if-none-match', 'babar'),
   135         hin  = [('if-none-match', 'babar'),
   124                ]
   136                ]
   125         hout = [('etag', 'celestine'),
   137         hout = [('etag', 'celestine'),
   126                ]
   138                ]
   127         status, req = _test_cache(hin, hout)
   139         req = _test_cache(hin, hout)
   128         self.assertCache(None, status, 'etag mismatch')
   140         self.assertCache(None, req.status_out, 'etag mismatch')
   129 
   141 
   130     @tag('etag')
   142     @tag('etag')
   131     def test_etag_match(self):
   143     def test_etag_match(self):
   132         # etag match
   144         # etag match
   133         hin  = [('if-none-match', 'babar'),
   145         hin  = [('if-none-match', 'babar'),
   134                ]
   146                ]
   135         hout = [('etag', 'babar'),
   147         hout = [('etag', 'babar'),
   136                ]
   148                ]
   137         status, req = _test_cache(hin, hout)
   149         req = _test_cache(hin, hout)
   138         self.assertCache(304, status, 'etag match')
   150         self.assertCache(304, req.status_out, 'etag match')
   139         # etag match in multiple
   151         # etag match in multiple
   140         hin  = [('if-none-match', 'loutre'),
   152         hin  = [('if-none-match', 'loutre'),
   141                 ('if-none-match', 'babar'),
   153                 ('if-none-match', 'babar'),
   142                ]
   154                ]
   143         hout = [('etag', 'babar'),
   155         hout = [('etag', 'babar'),
   144                ]
   156                ]
   145         status, req = _test_cache(hin, hout)
   157         req = _test_cache(hin, hout)
   146         self.assertCache(304, status, 'etag match in multiple')
   158         self.assertCache(304, req.status_out, 'etag match in multiple')
   147         # client use "*" as etag
   159         # client use "*" as etag
   148         hin  = [('if-none-match', '*'),
   160         hin  = [('if-none-match', '*'),
   149                ]
   161                ]
   150         hout = [('etag', 'babar'),
   162         hout = [('etag', 'babar'),
   151                ]
   163                ]
   152         status, req = _test_cache(hin, hout)
   164         req = _test_cache(hin, hout)
   153         self.assertCache(304, status, 'client use "*" as etag')
   165         self.assertCache(304, req.status_out, 'client use "*" as etag')
   154 
   166 
   155     @tag('etag', 'last_modified')
   167     @tag('etag', 'last_modified')
   156     def test_both(self):
   168     def test_both(self):
   157         #: test the proper behavior of etag only
   169         #: test the proper behavior of etag only
   158         # both wrong
   170         # both wrong
   160                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   172                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   161                ]
   173                ]
   162         hout = [('etag', 'loutre'),
   174         hout = [('etag', 'loutre'),
   163                 ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
   175                 ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
   164                ]
   176                ]
   165         status, req = _test_cache(hin, hout)
   177         req = _test_cache(hin, hout)
   166         self.assertCache(None, status, 'both wrong')
   178         self.assertCache(None, req.status_out, 'both wrong')
   167 
   179 
   168     @tag('etag', 'last_modified')
   180     @tag('etag', 'last_modified')
   169     def test_both_etag_mismatch(self):
   181     def test_both_etag_mismatch(self):
   170         # both etag mismatch
   182         # both etag mismatch
   171         hin  = [('if-none-match', 'babar'),
   183         hin  = [('if-none-match', 'babar'),
   172                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   184                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   173                ]
   185                ]
   174         hout = [('etag', 'loutre'),
   186         hout = [('etag', 'loutre'),
   175                 ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
   187                 ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
   176                ]
   188                ]
   177         status, req = _test_cache(hin, hout)
   189         req = _test_cache(hin, hout)
   178         self.assertCache(None, status, 'both  but etag mismatch')
   190         self.assertCache(None, req.status_out, 'both  but etag mismatch')
   179 
   191 
   180     @tag('etag', 'last_modified')
   192     @tag('etag', 'last_modified')
   181     def test_both_but_modified(self):
   193     def test_both_but_modified(self):
   182         # both but modified
   194         # both but modified
   183         hin  = [('if-none-match', 'babar'),
   195         hin  = [('if-none-match', 'babar'),
   184                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   196                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   185                ]
   197                ]
   186         hout = [('etag', 'babar'),
   198         hout = [('etag', 'babar'),
   187                 ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
   199                 ('last-modified', 'Sat, 15 Apr 2012 14:39:32 GM'),
   188                ]
   200                ]
   189         status, req = _test_cache(hin, hout)
   201         req = _test_cache(hin, hout)
   190         self.assertCache(None, status, 'both  but modified')
   202         self.assertCache(None, req.status_out, 'both  but modified')
   191 
   203 
   192     @tag('etag', 'last_modified')
   204     @tag('etag', 'last_modified')
   193     def test_both_ok(self):
   205     def test_both_ok(self):
   194         # both ok
   206         # both ok
   195         hin  = [('if-none-match', 'babar'),
   207         hin  = [('if-none-match', 'babar'),
   196                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   208                 ('if-modified-since', 'Sat, 14 Apr 2012 14:39:32 GM'),
   197                ]
   209                ]
   198         hout = [('etag', 'babar'),
   210         hout = [('etag', 'babar'),
   199                 ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
   211                 ('last-modified', 'Sat, 13 Apr 2012 14:39:32 GM'),
   200                ]
   212                ]
   201         status, req = _test_cache(hin, hout)
   213         req = _test_cache(hin, hout)
   202         self.assertCache(304, status, 'both ok')
   214         self.assertCache(304, req.status_out, 'both ok')
   203 
   215 
   204     @tag('etag', 'HEAD')
   216     @tag('etag', 'HEAD')
   205     def test_head_verb(self):
   217     def test_head_verb(self):
   206         #: check than FOUND 200 is properly raise without content on HEAD request
   218         #: check than FOUND 200 is properly raise without content on HEAD request
   207         #: This logic does not really belong here :-/
   219         #: This logic does not really belong here :-/
   208         # modified
   220         # modified
   209         hin  = [('if-none-match', 'babar'),
   221         hin  = [('if-none-match', 'babar'),
   210                ]
   222                ]
   211         hout = [('etag', 'rhino/really-not-babar'),
   223         hout = [('etag', 'rhino/really-not-babar'),
   212                ]
   224                ]
   213         status, req = _test_cache(hin, hout, method='HEAD')
   225         req = _test_cache(hin, hout, method='HEAD')
   214         self.assertCache(200, status, 'modifier HEAD verb')
   226         self.assertCache(200, req.status_out, 'modifier HEAD verb')
   215         # not modified
   227         # not modified
   216         hin  = [('if-none-match', 'babar'),
   228         hin  = [('if-none-match', 'babar'),
   217                ]
   229                ]
   218         hout = [('etag', 'babar'),
   230         hout = [('etag', 'babar'),
   219                ]
   231                ]
   220         status, req = _test_cache(hin, hout, method='HEAD')
   232         req = _test_cache(hin, hout, method='HEAD')
   221         self.assertCache(304, status, 'not modifier HEAD verb')
   233         self.assertCache(304, req.status_out, 'not modifier HEAD verb')
   222 
   234 
   223     @tag('etag', 'POST')
   235     @tag('etag', 'POST')
   224     def test_post_verb(self):
   236     def test_post_verb(self):
   225         # modified
   237         # modified
   226         hin  = [('if-none-match', 'babar'),
   238         hin  = [('if-none-match', 'babar'),
   227                ]
   239                ]
   228         hout = [('etag', 'rhino/really-not-babar'),
   240         hout = [('etag', 'rhino/really-not-babar'),
   229                ]
   241                ]
   230         status, req = _test_cache(hin, hout, method='POST')
   242         req = _test_cache(hin, hout, method='POST')
   231         self.assertCache(None, status, 'modifier HEAD verb')
   243         self.assertCache(None, req.status_out, 'modifier HEAD verb')
   232         # not modified
   244         # not modified
   233         hin  = [('if-none-match', 'babar'),
   245         hin  = [('if-none-match', 'babar'),
   234                ]
   246                ]
   235         hout = [('etag', 'babar'),
   247         hout = [('etag', 'babar'),
   236                ]
   248                ]
   237         status, req = _test_cache(hin, hout, method='POST')
   249         req = _test_cache(hin, hout, method='POST')
   238         self.assertCache(412, status, 'not modifier HEAD verb')
   250         self.assertCache(412, req.status_out, 'not modifier HEAD verb')
   239 
   251 
   240     @tag('expires')
   252     @tag('expires')
   241     def test_expires_added(self):
   253     def test_expires_added(self):
   242         #: Check that Expires header is added:
   254         #: Check that Expires header is added:
   243         #: - when the page is modified
   255         #: - when the page is modified
   244         #: - when none was already present
   256         #: - when none was already present
   245         hin  = [('if-none-match', 'babar'),
   257         hin  = [('if-none-match', 'babar'),
   246                ]
   258                ]
   247         hout = [('etag', 'rhino/really-not-babar'),
   259         hout = [('etag', 'rhino/really-not-babar'),
   248                ]
   260                ]
   249         status, req = _test_cache(hin, hout)
   261         req = _test_cache(hin, hout)
   250         self.assertCache(None, status, 'modifier HEAD verb')
   262         self.assertCache(None, req.status_out, 'modifier HEAD verb')
   251         value = req.headers_out.getHeader('expires')
   263         value = req.headers_out.getHeader('expires')
   252         self.assertIsNotNone(value)
   264         self.assertIsNotNone(value)
   253 
   265 
   254     @tag('expires')
   266     @tag('expires')
   255     def test_expires_not_added(self):
   267     def test_expires_not_added(self):
   256         #: Check that Expires header is not added if NOT-MODIFIED
   268         #: Check that Expires header is not added if NOT-MODIFIED
   257         hin  = [('if-none-match', 'babar'),
   269         hin  = [('if-none-match', 'babar'),
   258                ]
   270                ]
   259         hout = [('etag', 'babar'),
   271         hout = [('etag', 'babar'),
   260                ]
   272                ]
   261         status, req = _test_cache(hin, hout)
   273         req = _test_cache(hin, hout)
   262         self.assertCache(304, status, 'not modifier HEAD verb')
   274         self.assertCache(304, req.status_out, 'not modifier HEAD verb')
   263         value = req.headers_out.getHeader('expires')
   275         value = req.headers_out.getHeader('expires')
   264         self.assertIsNone(value)
   276         self.assertIsNone(value)
   265 
   277 
   266     @tag('expires')
   278     @tag('expires')
   267     def test_expires_no_overwrite(self):
   279     def test_expires_no_overwrite(self):
   270                ]
   282                ]
   271         DATE = 'Sat, 13 Apr 2012 14:39:32 GM'
   283         DATE = 'Sat, 13 Apr 2012 14:39:32 GM'
   272         hout = [('etag', 'rhino/really-not-babar'),
   284         hout = [('etag', 'rhino/really-not-babar'),
   273                 ('expires', DATE),
   285                 ('expires', DATE),
   274                ]
   286                ]
   275         status, req = _test_cache(hin, hout)
   287         req = _test_cache(hin, hout)
   276         self.assertCache(None, status, 'not modifier HEAD verb')
   288         self.assertCache(None, req.status_out, 'not modifier HEAD verb')
   277         value = req.headers_out.getRawHeaders('expires')
   289         value = req.headers_out.getRawHeaders('expires')
   278         self.assertEqual(value, [DATE])
   290         self.assertEqual(value, [DATE])
   279 
   291 
   280 
   292 
   281 if __name__ == '__main__':
   293 if __name__ == '__main__':