1 # -*- coding: utf-8 -*- |
|
2 # copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
3 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
4 # |
|
5 # This file is part of CubicWeb. |
|
6 # |
|
7 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
8 # terms of the GNU Lesser General Public License as published by the Free |
|
9 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
10 # any later version. |
|
11 # |
|
12 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
|
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
14 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
15 # details. |
|
16 # |
|
17 # You should have received a copy of the GNU Lesser General Public License along |
|
18 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
|
19 from contextlib import contextmanager |
|
20 |
|
21 from logilab.common import tempattr |
|
22 from logilab.common.testlib import Tags |
|
23 from cubicweb.devtools.testlib import CubicWebTC |
|
24 |
|
25 import os |
|
26 import os.path as osp |
|
27 import glob |
|
28 |
|
29 from cubicweb.utils import HTMLHead |
|
30 from cubicweb.web.views.staticcontrollers import ConcatFilesHandler |
|
31 |
|
32 class staticfilespublishermixin(object): |
|
33 |
|
34 @contextmanager |
|
35 def _publish_static_files(self, url, header={}): |
|
36 with self.admin_access.web_request(headers=header) as req: |
|
37 req._url = url |
|
38 self.app_handle_request(req, url) |
|
39 yield req |
|
40 |
|
41 class StaticControllerCacheTC(staticfilespublishermixin, CubicWebTC): |
|
42 tags = CubicWebTC.tags | Tags('static_controller', 'cache', 'http') |
|
43 |
|
44 def test_static_file_are_cached(self): |
|
45 with self._publish_static_files('data/cubicweb.css') as req: |
|
46 self.assertEqual(200, req.status_out) |
|
47 self.assertIn('last-modified', req.headers_out) |
|
48 next_headers = { |
|
49 'if-modified-since': req.get_response_header('last-modified', raw=True), |
|
50 } |
|
51 with self._publish_static_files('data/cubicweb.css', next_headers) as req: |
|
52 self.assertEqual(304, req.status_out) |
|
53 |
|
54 class StaticDirectoryControllerTC(staticfilespublishermixin, CubicWebTC): |
|
55 |
|
56 def test_check_static_dir_access(self): |
|
57 """write a file in the static directory and test the access""" |
|
58 staticdir = osp.join(self.session.vreg.config.static_directory) |
|
59 if not os.path.exists(staticdir): |
|
60 os.makedirs(staticdir) |
|
61 filename = osp.join(staticdir, 'test') |
|
62 with open(filename, 'a') as f: |
|
63 with self._publish_static_files('static/test') as req: |
|
64 self.assertEqual(200, req.status_out) |
|
65 |
|
66 class DataControllerTC(staticfilespublishermixin, CubicWebTC): |
|
67 tags = CubicWebTC.tags | Tags('static_controller', 'data', 'http') |
|
68 |
|
69 def _check_datafile_ok(self, fname): |
|
70 with self._publish_static_files(fname) as req: |
|
71 self.assertEqual(200, req.status_out) |
|
72 self.assertIn('last-modified', req.headers_out) |
|
73 self.assertIn('expires', req.headers_out) |
|
74 self.assertEqual(req.get_response_header('cache-control'), |
|
75 {'max-age': 604800}) |
|
76 next_headers = { |
|
77 'if-modified-since': req.get_response_header('last-modified', raw=True), |
|
78 } |
|
79 with self._publish_static_files(fname, next_headers) as req: |
|
80 self.assertEqual(304, req.status_out) |
|
81 |
|
82 def _check_datafile_redirect(self, fname, expected): |
|
83 with self._publish_static_files(fname) as req: |
|
84 self.assertEqual(302, req.status_out) |
|
85 self.assertEqual(req.get_response_header('location'), |
|
86 req.base_url() + expected) |
|
87 |
|
88 def _check_no_datafile(self, fname): |
|
89 with self._publish_static_files(fname) as req: |
|
90 self.assertEqual(404, req.status_out) |
|
91 |
|
92 def test_static_data_mode(self): |
|
93 hash = self.vreg.config.instance_md5_version() |
|
94 self.assertEqual(32, len(hash)) |
|
95 |
|
96 with tempattr(self.vreg.config, 'mode', 'test'): |
|
97 self._check_datafile_ok('data/cubicweb.css') |
|
98 self._check_no_datafile('data/does/not/exist') |
|
99 self._check_no_datafile('data/%s/cubicweb.css' % ('0'*len(hash))) |
|
100 |
|
101 with tempattr(self.vreg.config, 'mode', 'notest'): |
|
102 self.config._init_base_url() # reset config.datadir_url |
|
103 self._check_datafile_redirect('data/cubicweb.css', 'data/%s/cubicweb.css' % hash) |
|
104 self._check_datafile_ok('data/%s/cubicweb.css' % hash) |
|
105 self._check_no_datafile('data/%s/does/not/exist' % hash) |
|
106 self._check_datafile_redirect('data/%s/does/not/exist' % ('0'*len(hash)), |
|
107 'data/%s/%s/does/not/exist' % (hash, '0'*len(hash))) |
|
108 |
|
109 |
|
110 class ConcatFilesTC(CubicWebTC): |
|
111 |
|
112 tags = CubicWebTC.tags | Tags('static_controller', 'concat') |
|
113 |
|
114 def tearDown(self): |
|
115 super(ConcatFilesTC, self).tearDown() |
|
116 self._cleanup_concat_cache() |
|
117 |
|
118 def _cleanup_concat_cache(self): |
|
119 uicachedir = osp.join(self.config.apphome, 'uicache') |
|
120 for fname in glob.glob(osp.join(uicachedir, 'cache_concat_*')): |
|
121 os.unlink(osp.join(uicachedir, fname)) |
|
122 |
|
123 @contextmanager |
|
124 def _publish_js_files(self, js_files): |
|
125 with self.admin_access.web_request() as req: |
|
126 head = HTMLHead(req) |
|
127 url = head.concat_urls([req.data_url(js_file) |
|
128 for js_file in js_files])[len(req.base_url()):] |
|
129 req._url = url |
|
130 res = self.app_handle_request(req, url) |
|
131 yield res, req |
|
132 |
|
133 def expected_content(self, js_files): |
|
134 content = b'' |
|
135 for js_file in js_files: |
|
136 dirpath, rid = self.config.locate_resource(js_file) |
|
137 if dirpath is not None: # ignore resources not found |
|
138 with open(osp.join(dirpath, rid), 'rb') as f: |
|
139 content += f.read() + b'\n' |
|
140 return content |
|
141 |
|
142 def test_cache(self): |
|
143 js_files = ('cubicweb.ajax.js', 'jquery.js') |
|
144 with self._publish_js_files(js_files) as (result, req): |
|
145 self.assertNotEqual(404, req.status_out) |
|
146 # check result content |
|
147 self.assertEqual(result, self.expected_content(js_files)) |
|
148 # make sure we kept a cached version on filesystem |
|
149 concat_hander = ConcatFilesHandler(self.config) |
|
150 filepath = concat_hander.build_filepath(js_files) |
|
151 self.assertTrue(osp.isfile(filepath)) |
|
152 |
|
153 |
|
154 def test_invalid_file_in_debug_mode(self): |
|
155 js_files = ('cubicweb.ajax.js', 'dummy.js') |
|
156 # in debug mode, an error is raised |
|
157 self.config.debugmode = True |
|
158 try: |
|
159 with self._publish_js_files(js_files) as (result, req): |
|
160 #print result |
|
161 self.assertEqual(404, req.status_out) |
|
162 finally: |
|
163 self.config.debugmode = False |
|
164 |
|
165 def test_invalid_file_in_production_mode(self): |
|
166 js_files = ('cubicweb.ajax.js', 'dummy.js') |
|
167 with self._publish_js_files(js_files) as (result, req): |
|
168 self.assertNotEqual(404, req.status_out) |
|
169 # check result content |
|
170 self.assertEqual(result, self.expected_content(js_files)) |
|
171 |
|
172 |
|
173 if __name__ == '__main__': |
|
174 from logilab.common.testlib import unittest_main |
|
175 unittest_main() |
|