| | |
| | | here = os.path.dirname(__file__) |
| | | |
| | | # 5 years from now (more or less) |
| | | fiveyrsfuture = datetime.datetime.utcnow() + datetime.timedelta(5*365) |
| | | fiveyrsfuture = datetime.datetime.utcnow() + datetime.timedelta(5 * 365) |
| | | |
| | | |
| | | class Test_static_view_use_subpath_False(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.static import static_view |
| | | |
| | | return static_view |
| | | |
| | | def _makeOne(self, *arg, **kw): |
| | |
| | | |
| | | def _makeRequest(self, kw=None): |
| | | from pyramid.request import Request |
| | | |
| | | environ = { |
| | | 'wsgi.url_scheme':'http', |
| | | 'wsgi.version':(1,0), |
| | | 'SERVER_NAME':'example.com', |
| | | 'SERVER_PORT':'6543', |
| | | 'PATH_INFO':'/', |
| | | 'SCRIPT_NAME':'', |
| | | 'REQUEST_METHOD':'GET', |
| | | } |
| | | 'wsgi.url_scheme': 'http', |
| | | 'wsgi.version': (1, 0), |
| | | 'SERVER_NAME': 'example.com', |
| | | 'SERVER_PORT': '6543', |
| | | 'PATH_INFO': '/', |
| | | 'SCRIPT_NAME': '', |
| | | 'REQUEST_METHOD': 'GET', |
| | | } |
| | | if kw is not None: |
| | | environ.update(kw) |
| | | return Request(environ=environ) |
| | |
| | | |
| | | def test_call_adds_slash_path_info_empty(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':''}) |
| | | request = self._makeRequest({'PATH_INFO': ''}) |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPMovedPermanently |
| | | |
| | | self.assertRaises(HTTPMovedPermanently, inst, context, request) |
| | | |
| | | def test_path_info_slash_means_index_html(self): |
| | |
| | | |
| | | def test_oob_singledot(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/./index.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '/./index.html'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertEqual(response.status, '200 OK') |
| | |
| | | |
| | | def test_oob_emptyelement(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'//index.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '//index.html'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertEqual(response.status, '200 OK') |
| | |
| | | |
| | | def test_oob_dotdotslash(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/subdir/../../minimal.pt'}) |
| | | request = self._makeRequest({'PATH_INFO': '/subdir/../../minimal.pt'}) |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_oob_dotdotslash_encoded(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest( |
| | | {'PATH_INFO':'/subdir/%2E%2E%2F%2E%2E/minimal.pt'}) |
| | | {'PATH_INFO': '/subdir/%2E%2E%2F%2E%2E/minimal.pt'} |
| | | ) |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_oob_os_sep(self): |
| | | import os |
| | | |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | dds = '..' + os.sep |
| | | request = self._makeRequest({'PATH_INFO':'/subdir/%s%sminimal.pt' % |
| | | (dds, dds)}) |
| | | request = self._makeRequest( |
| | | {'PATH_INFO': '/subdir/%s%sminimal.pt' % (dds, dds)} |
| | | ) |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_resource_doesnt_exist(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/notthere'}) |
| | | request = self._makeRequest({'PATH_INFO': '/notthere'}) |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_resource_isdir(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/subdir/'}) |
| | | request = self._makeRequest({'PATH_INFO': '/subdir/'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertTrue(b'<html>subdir</html>' in response.body) |
| | | |
| | | def test_resource_is_file(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/index.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '/index.html'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertTrue(b'<html>static</html>' in response.body) |
| | | |
| | | def test_resource_is_file_with_wsgi_file_wrapper(self): |
| | | from pyramid.response import _BLOCK_SIZE |
| | | |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/index.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '/index.html'}) |
| | | |
| | | class _Wrapper(object): |
| | | def __init__(self, file, block_size=None): |
| | | self.file = file |
| | | self.block_size = block_size |
| | | |
| | | request.environ['wsgi.file_wrapper'] = _Wrapper |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | |
| | | |
| | | def test_resource_is_file_with_cache_max_age(self): |
| | | inst = self._makeOne('tests:fixtures/static', cache_max_age=600) |
| | | request = self._makeRequest({'PATH_INFO':'/index.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '/index.html'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertTrue(b'<html>static</html>' in response.body) |
| | | self.assertEqual(len(response.headerlist), 5) |
| | | header_names = [ x[0] for x in response.headerlist ] |
| | | header_names = [x[0] for x in response.headerlist] |
| | | header_names.sort() |
| | | self.assertEqual(header_names, |
| | | ['Cache-Control', 'Content-Length', 'Content-Type', |
| | | 'Expires', 'Last-Modified']) |
| | | self.assertEqual( |
| | | header_names, |
| | | [ |
| | | 'Cache-Control', |
| | | 'Content-Length', |
| | | 'Content-Type', |
| | | 'Expires', |
| | | 'Last-Modified', |
| | | ], |
| | | ) |
| | | |
| | | def test_resource_is_file_with_no_cache_max_age(self): |
| | | inst = self._makeOne('tests:fixtures/static', |
| | | cache_max_age=None) |
| | | request = self._makeRequest({'PATH_INFO':'/index.html'}) |
| | | inst = self._makeOne('tests:fixtures/static', cache_max_age=None) |
| | | request = self._makeRequest({'PATH_INFO': '/index.html'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertTrue(b'<html>static</html>' in response.body) |
| | | self.assertEqual(len(response.headerlist), 3) |
| | | header_names = [ x[0] for x in response.headerlist ] |
| | | header_names = [x[0] for x in response.headerlist] |
| | | header_names.sort() |
| | | self.assertEqual( |
| | | header_names, |
| | | ['Content-Length', 'Content-Type', 'Last-Modified']) |
| | | header_names, ['Content-Length', 'Content-Type', 'Last-Modified'] |
| | | ) |
| | | |
| | | def test_resource_notmodified(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/index.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '/index.html'}) |
| | | request.if_modified_since = fiveyrsfuture |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | |
| | | |
| | | def test_not_found(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/notthere.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '/notthere.html'}) |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_gz_resource_no_content_encoding(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/arcs.svg.tgz'}) |
| | | request = self._makeRequest({'PATH_INFO': '/arcs.svg.tgz'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertEqual(response.status, '200 OK') |
| | |
| | | |
| | | def test_resource_no_content_encoding(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':'/index.html'}) |
| | | request = self._makeRequest({'PATH_INFO': '/index.html'}) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertEqual(response.status, '200 OK') |
| | |
| | | self.assertEqual(response.content_encoding, None) |
| | | response.app_iter.close() |
| | | |
| | | |
| | | class Test_static_view_use_subpath_True(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.static import static_view |
| | | |
| | | return static_view |
| | | |
| | | def _makeOne(self, *arg, **kw): |
| | |
| | | |
| | | def _makeRequest(self, kw=None): |
| | | from pyramid.request import Request |
| | | |
| | | environ = { |
| | | 'wsgi.url_scheme':'http', |
| | | 'wsgi.version':(1,0), |
| | | 'SERVER_NAME':'example.com', |
| | | 'SERVER_PORT':'6543', |
| | | 'PATH_INFO':'/', |
| | | 'SCRIPT_NAME':'', |
| | | 'REQUEST_METHOD':'GET', |
| | | } |
| | | 'wsgi.url_scheme': 'http', |
| | | 'wsgi.version': (1, 0), |
| | | 'SERVER_NAME': 'example.com', |
| | | 'SERVER_PORT': '6543', |
| | | 'PATH_INFO': '/', |
| | | 'SCRIPT_NAME': '', |
| | | 'REQUEST_METHOD': 'GET', |
| | | } |
| | | if kw is not None: |
| | | environ.update(kw) |
| | | return Request(environ=environ) |
| | |
| | | |
| | | def test_call_adds_slash_path_info_empty(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest({'PATH_INFO':''}) |
| | | request = self._makeRequest({'PATH_INFO': ''}) |
| | | request.subpath = () |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPMovedPermanently |
| | | |
| | | self.assertRaises(HTTPMovedPermanently, inst, context, request) |
| | | |
| | | def test_path_info_slash_means_index_html(self): |
| | |
| | | request.subpath = ('.', 'index.html') |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_oob_emptyelement(self): |
| | |
| | | request.subpath = ('', 'index.html') |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_oob_dotdotslash(self): |
| | |
| | | request.subpath = ('subdir', '..', '..', 'minimal.pt') |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_oob_dotdotslash_encoded(self): |
| | |
| | | request.subpath = ('subdir', '%2E%2E', '%2E%2E', 'minimal.pt') |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_oob_os_sep(self): |
| | | import os |
| | | |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | dds = '..' + os.sep |
| | | request = self._makeRequest() |
| | | request.subpath = ('subdir', dds, dds, 'minimal.pt') |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_resource_doesnt_exist(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | | request = self._makeRequest() |
| | | request.subpath = ('notthere,') |
| | | request.subpath = 'notthere,' |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | def test_resource_isdir(self): |
| | |
| | | response = inst(context, request) |
| | | self.assertTrue(b'<html>static</html>' in response.body) |
| | | self.assertEqual(len(response.headerlist), 5) |
| | | header_names = [ x[0] for x in response.headerlist ] |
| | | header_names = [x[0] for x in response.headerlist] |
| | | header_names.sort() |
| | | self.assertEqual(header_names, |
| | | ['Cache-Control', 'Content-Length', 'Content-Type', |
| | | 'Expires', 'Last-Modified']) |
| | | self.assertEqual( |
| | | header_names, |
| | | [ |
| | | 'Cache-Control', |
| | | 'Content-Length', |
| | | 'Content-Type', |
| | | 'Expires', |
| | | 'Last-Modified', |
| | | ], |
| | | ) |
| | | |
| | | def test_resource_is_file_with_no_cache_max_age(self): |
| | | inst = self._makeOne('tests:fixtures/static', |
| | | cache_max_age=None) |
| | | inst = self._makeOne('tests:fixtures/static', cache_max_age=None) |
| | | request = self._makeRequest() |
| | | request.subpath = ('index.html',) |
| | | context = DummyContext() |
| | | response = inst(context, request) |
| | | self.assertTrue(b'<html>static</html>' in response.body) |
| | | self.assertEqual(len(response.headerlist), 3) |
| | | header_names = [ x[0] for x in response.headerlist ] |
| | | header_names = [x[0] for x in response.headerlist] |
| | | header_names.sort() |
| | | self.assertEqual( |
| | | header_names, |
| | | ['Content-Length', 'Content-Type', 'Last-Modified']) |
| | | header_names, ['Content-Length', 'Content-Type', 'Last-Modified'] |
| | | ) |
| | | |
| | | def test_resource_notmodified(self): |
| | | inst = self._makeOne('tests:fixtures/static') |
| | |
| | | request.subpath = ('notthere.html',) |
| | | context = DummyContext() |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | self.assertRaises(HTTPNotFound, inst, context, request) |
| | | |
| | | class TestQueryStringConstantCacheBuster(unittest.TestCase): |
| | | |
| | | class TestQueryStringConstantCacheBuster(unittest.TestCase): |
| | | def _makeOne(self, param=None): |
| | | from pyramid.static import QueryStringConstantCacheBuster as cls |
| | | |
| | | if param: |
| | | inst = cls('foo', param) |
| | | else: |
| | |
| | | def test_it(self): |
| | | fut = self._makeOne() |
| | | self.assertEqual( |
| | | fut('foo', 'bar', {}), |
| | | ('bar', {'_query': {'x': 'foo'}})) |
| | | fut('foo', 'bar', {}), ('bar', {'_query': {'x': 'foo'}}) |
| | | ) |
| | | |
| | | def test_change_param(self): |
| | | fut = self._makeOne('y') |
| | | self.assertEqual( |
| | | fut('foo', 'bar', {}), |
| | | ('bar', {'_query': {'y': 'foo'}})) |
| | | fut('foo', 'bar', {}), ('bar', {'_query': {'y': 'foo'}}) |
| | | ) |
| | | |
| | | def test_query_is_already_tuples(self): |
| | | fut = self._makeOne() |
| | | self.assertEqual( |
| | | fut('foo', 'bar', {'_query': [('a', 'b')]}), |
| | | ('bar', {'_query': (('a', 'b'), ('x', 'foo'))})) |
| | | ('bar', {'_query': (('a', 'b'), ('x', 'foo'))}), |
| | | ) |
| | | |
| | | def test_query_is_tuple_of_tuples(self): |
| | | fut = self._makeOne() |
| | | self.assertEqual( |
| | | fut('foo', 'bar', {'_query': (('a', 'b'),)}), |
| | | ('bar', {'_query': (('a', 'b'), ('x', 'foo'))})) |
| | | ('bar', {'_query': (('a', 'b'), ('x', 'foo'))}), |
| | | ) |
| | | |
| | | |
| | | class TestManifestCacheBuster(unittest.TestCase): |
| | | |
| | | def _makeOne(self, path, **kw): |
| | | from pyramid.static import ManifestCacheBuster as cls |
| | | |
| | | return cls(path, **kw) |
| | | |
| | | def test_it(self): |
| | |
| | | fut = self._makeOne(manifest_path) |
| | | self.assertEqual(fut('foo', 'bar', {}), ('bar', {})) |
| | | self.assertEqual( |
| | | fut('foo', 'css/main.css', {}), |
| | | ('css/main-test.css', {})) |
| | | fut('foo', 'css/main.css', {}), ('css/main-test.css', {}) |
| | | ) |
| | | |
| | | def test_it_with_relspec(self): |
| | | fut = self._makeOne('fixtures/manifest.json') |
| | | self.assertEqual(fut('foo', 'bar', {}), ('bar', {})) |
| | | self.assertEqual( |
| | | fut('foo', 'css/main.css', {}), |
| | | ('css/main-test.css', {})) |
| | | fut('foo', 'css/main.css', {}), ('css/main-test.css', {}) |
| | | ) |
| | | |
| | | def test_it_with_absspec(self): |
| | | fut = self._makeOne('tests:fixtures/manifest.json') |
| | | self.assertEqual(fut('foo', 'bar', {}), ('bar', {})) |
| | | self.assertEqual( |
| | | fut('foo', 'css/main.css', {}), |
| | | ('css/main-test.css', {})) |
| | | fut('foo', 'css/main.css', {}), ('css/main-test.css', {}) |
| | | ) |
| | | |
| | | def test_reload(self): |
| | | manifest_path = os.path.join(here, 'fixtures', 'manifest.json') |
| | |
| | | fut = inst |
| | | |
| | | # test without a valid manifest |
| | | self.assertEqual( |
| | | fut('foo', 'css/main.css', {}), |
| | | ('css/main.css', {})) |
| | | self.assertEqual(fut('foo', 'css/main.css', {}), ('css/main.css', {})) |
| | | |
| | | # swap to a real manifest, setting mtime to 0 |
| | | inst.manifest_path = manifest_path |
| | | self.assertEqual( |
| | | fut('foo', 'css/main.css', {}), |
| | | ('css/main-test.css', {})) |
| | | fut('foo', 'css/main.css', {}), ('css/main-test.css', {}) |
| | | ) |
| | | |
| | | # ensure switching the path doesn't change the result |
| | | inst.manifest_path = new_manifest_path |
| | | self.assertEqual( |
| | | fut('foo', 'css/main.css', {}), |
| | | ('css/main-test.css', {})) |
| | | fut('foo', 'css/main.css', {}), ('css/main-test.css', {}) |
| | | ) |
| | | |
| | | # update mtime, should cause a reload |
| | | inst.getmtime = lambda *args, **kwargs: 1 |
| | | self.assertEqual( |
| | | fut('foo', 'css/main.css', {}), |
| | | ('css/main-678b7c80.css', {})) |
| | | fut('foo', 'css/main.css', {}), ('css/main-678b7c80.css', {}) |
| | | ) |
| | | |
| | | def test_invalid_manifest(self): |
| | | self.assertRaises(IOError, lambda: self._makeOne('foo')) |
| | |
| | | inst = self._makeOne('foo', reload=True) |
| | | self.assertEqual(inst.manifest, {}) |
| | | |
| | | |
| | | class DummyContext: |
| | | pass |
| | | |
| | | |
| | | class DummyStartResponse: |
| | | status = () |
| | | headers = () |
| | | |
| | | def __call__(self, status, headers): |
| | | self.status = status |
| | | self.headers = headers |