Merge lp:~bac/charmworld/bundle-redirect into lp:charmworld
- bundle-redirect
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Brad Crittenden |
Approved revision: | 524 |
Merged at revision: | 523 |
Proposed branch: | lp:~bac/charmworld/bundle-redirect |
Merge into: | lp:charmworld |
Diff against target: |
374 lines (+114/-68) 7 files modified
charmworld/__init__.py (+2/-2) charmworld/jobs/config.py (+3/-1) charmworld/testing/factory.py (+1/-4) charmworld/views/bundles.py (+19/-5) charmworld/views/helpers.py (+5/-0) charmworld/views/tests/test_bundles.py (+77/-56) default.ini (+7/-0) |
To merge this branch: | bzr merge lp:~bac/charmworld/bundle-redirect |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Gui Bot | continuous-integration | Approve | |
Brad Crittenden (community) | code | Approve | |
Fabrice Matrat | Approve | ||
Francesco Banconi | Approve | ||
Review via email:
|
Commit message
Redirect bundles.
Description of the change
Redirect bundles to jujucharms.com
QA: a bit hard as getting bundles to load that are visible in jujucharms.com is difficult since 1) many bundles name a specific version of the charm and that version may not be ingestable, 2) jujucharms.com does not seem to have a complete set of available bundles. (?)
But if you can find a local bundle that has a corresponding one in jujucharms.com, test that the redirect works.
In all honesty, I'm not going to feel 100% about this branch until we get it on staging and can do very thorough QA.

Fabrice Matrat (fabricematrat) wrote : | # |
I just wonder if redirecting to a search in jujucharms.com won't be safer ??

Brad Crittenden (bac) wrote : | # |
QA:
# Personal bundle
http://
# Personal bundle with revision
http://
# Official bundle
http://

Fabrice Matrat (fabricematrat) wrote : | # |
Working great, did browse a few bundles and get redirected.
Code LGTM.

Juju Gui Bot (juju-gui-bot) wrote : | # |
FAILED: Autolanding.
No commit message was specified in the merge proposal. Hit 'Add commit message' on the merge proposal web page or follow the link below. You can approve the merge proposal yourself to rerun.
https:/

Juju Gui Bot (juju-gui-bot) : | # |
Preview Diff
1 | === modified file 'charmworld/__init__.py' | |||
2 | --- charmworld/__init__.py 2013-11-14 13:38:24 +0000 | |||
3 | +++ charmworld/__init__.py 2015-02-18 14:26:31 +0000 | |||
4 | @@ -59,12 +59,12 @@ | |||
5 | 59 | 59 | ||
6 | 60 | if 'http_cache' not in settings: | 60 | if 'http_cache' not in settings: |
7 | 61 | http_cache = app_settings.get('http_cache') | 61 | http_cache = app_settings.get('http_cache') |
9 | 62 | if http_cache is not None: | 62 | if http_cache: |
10 | 63 | http_cache = int(http_cache) | 63 | http_cache = int(http_cache) |
11 | 64 | settings['http_cache'] = http_cache | 64 | settings['http_cache'] = http_cache |
12 | 65 | if 'http_cache_modifier' in settings: | 65 | if 'http_cache_modifier' in settings: |
13 | 66 | mod = settings['http_cache_modifier'] | 66 | mod = settings['http_cache_modifier'] |
15 | 67 | if settings['http_cache'] is not None: | 67 | if settings['http_cache']: |
16 | 68 | settings['http_cache'] = int(settings['http_cache'] * mod) | 68 | settings['http_cache'] = int(settings['http_cache'] * mod) |
17 | 69 | # We can't let the new setting to get add_view or it blows up | 69 | # We can't let the new setting to get add_view or it blows up |
18 | 70 | # with an unexpected kwarg. | 70 | # with an unexpected kwarg. |
19 | 71 | 71 | ||
20 | === modified file 'charmworld/jobs/config.py' | |||
21 | --- charmworld/jobs/config.py 2013-10-10 11:27:55 +0000 | |||
22 | +++ charmworld/jobs/config.py 2015-02-18 14:26:31 +0000 | |||
23 | @@ -7,12 +7,14 @@ | |||
24 | 7 | import shutil | 7 | import shutil |
25 | 8 | import tempfile | 8 | import tempfile |
26 | 9 | 9 | ||
27 | 10 | from pyramid.settings import asbool | ||
28 | 11 | |||
29 | 10 | from charmworld.utils import get_ini | 12 | from charmworld.utils import get_ini |
30 | 11 | 13 | ||
31 | 12 | 14 | ||
32 | 13 | settings = get_ini() | 15 | settings = get_ini() |
33 | 14 | 16 | ||
35 | 15 | if settings.get('is_testing', 'false').lower() == 'true': | 17 | if asbool(settings.get('is_testing')): |
36 | 16 | CHARM_DIR = tempfile.mkdtemp() | 18 | CHARM_DIR = tempfile.mkdtemp() |
37 | 17 | atexit.register(shutil.rmtree, CHARM_DIR, ignore_errors=True) | 19 | atexit.register(shutil.rmtree, CHARM_DIR, ignore_errors=True) |
38 | 18 | else: | 20 | else: |
39 | 19 | 21 | ||
40 | === modified file 'charmworld/testing/factory.py' | |||
41 | --- charmworld/testing/factory.py 2014-05-15 15:57:23 +0000 | |||
42 | +++ charmworld/testing/factory.py 2015-02-18 14:26:31 +0000 | |||
43 | @@ -375,10 +375,7 @@ | |||
44 | 375 | 375 | ||
45 | 376 | 376 | ||
46 | 377 | def make_bundle(db, *args, **kwargs): | 377 | def make_bundle(db, *args, **kwargs): |
51 | 378 | with_basket = False | 378 | with_basket = kwargs.pop('with_basket', False) |
48 | 379 | if 'with_basket' in kwargs: | ||
49 | 380 | with_basket = True | ||
50 | 381 | del kwargs['with_basket'] | ||
52 | 382 | 379 | ||
53 | 383 | bundle_data = get_bundle_data(*args, **kwargs) | 380 | bundle_data = get_bundle_data(*args, **kwargs) |
54 | 384 | bundle = Bundle(bundle_data) | 381 | bundle = Bundle(bundle_data) |
55 | 385 | 382 | ||
56 | === modified file 'charmworld/views/bundles.py' | |||
57 | --- charmworld/views/bundles.py 2014-03-20 14:00:11 +0000 | |||
58 | +++ charmworld/views/bundles.py 2015-02-18 14:26:31 +0000 | |||
59 | @@ -5,6 +5,8 @@ | |||
60 | 5 | 5 | ||
61 | 6 | import os.path | 6 | import os.path |
62 | 7 | 7 | ||
63 | 8 | from pyramid.httpexceptions import HTTPMovedPermanently | ||
64 | 9 | |||
65 | 8 | from charmworld import cached_view_config | 10 | from charmworld import cached_view_config |
66 | 9 | from charmworld.models import ( | 11 | from charmworld.models import ( |
67 | 10 | Bundle, | 12 | Bundle, |
68 | @@ -15,8 +17,8 @@ | |||
69 | 15 | from charmworld.views.api import json_response | 17 | from charmworld.views.api import json_response |
70 | 16 | from charmworld.views.helpers import ( | 18 | from charmworld.views.helpers import ( |
71 | 17 | find_bundle, | 19 | find_bundle, |
72 | 18 | found, | ||
73 | 19 | format_change, | 20 | format_change, |
74 | 21 | redirect_url, | ||
75 | 20 | ) | 22 | ) |
76 | 21 | 23 | ||
77 | 22 | 24 | ||
78 | @@ -123,6 +125,14 @@ | |||
79 | 123 | ) | 125 | ) |
80 | 124 | 126 | ||
81 | 125 | 127 | ||
82 | 128 | def _bundle_search_redirect(request): | ||
83 | 129 | """Return the redirect search location.""" | ||
84 | 130 | return '{url}/q/{basket}?type=bundle'.format( | ||
85 | 131 | url=redirect_url(request), | ||
86 | 132 | basket=request.matchdict['basket'], | ||
87 | 133 | ) | ||
88 | 134 | |||
89 | 135 | |||
90 | 126 | @cached_view_config( | 136 | @cached_view_config( |
91 | 127 | route_name="personal-bundle-revision", | 137 | route_name="personal-bundle-revision", |
92 | 128 | renderer="charmworld:templates/bundle.pt") | 138 | renderer="charmworld:templates/bundle.pt") |
93 | @@ -130,8 +140,10 @@ | |||
94 | 130 | route_name="personal-bundle", | 140 | route_name="personal-bundle", |
95 | 131 | renderer="charmworld:templates/bundle.pt") | 141 | renderer="charmworld:templates/bundle.pt") |
96 | 132 | def personal_bundle(request): | 142 | def personal_bundle(request): |
99 | 133 | bundle = find_bundle(request) | 143 | # For simplicity and safety, all bundles will redirect to a search on the |
100 | 134 | return _bundle_view(request, found(bundle)) | 144 | # basket name. |
101 | 145 | location = _bundle_search_redirect(request) | ||
102 | 146 | raise HTTPMovedPermanently(location=location) | ||
103 | 135 | 147 | ||
104 | 136 | 148 | ||
105 | 137 | @cached_view_config( | 149 | @cached_view_config( |
106 | @@ -159,8 +171,10 @@ | |||
107 | 159 | route_name="official-bundle-revision", | 171 | route_name="official-bundle-revision", |
108 | 160 | renderer="charmworld:templates/bundle.pt") | 172 | renderer="charmworld:templates/bundle.pt") |
109 | 161 | def official_bundle(request): | 173 | def official_bundle(request): |
112 | 162 | bundle = find_bundle(request, promulgated=True) | 174 | # For simplicity and safety, all bundles will redirect to a search on the |
113 | 163 | return _bundle_view(request, found(bundle)) | 175 | # basket name. |
114 | 176 | location = _bundle_search_redirect(request) | ||
115 | 177 | raise HTTPMovedPermanently(location=location) | ||
116 | 164 | 178 | ||
117 | 165 | 179 | ||
118 | 166 | @cached_view_config( | 180 | @cached_view_config( |
119 | 167 | 181 | ||
120 | === modified file 'charmworld/views/helpers.py' | |||
121 | --- charmworld/views/helpers.py 2014-02-10 21:30:20 +0000 | |||
122 | +++ charmworld/views/helpers.py 2015-02-18 14:26:31 +0000 | |||
123 | @@ -161,3 +161,8 @@ | |||
124 | 161 | else: | 161 | else: |
125 | 162 | spec["owner"] = request.matchdict['owner'] | 162 | spec["owner"] = request.matchdict['owner'] |
126 | 163 | return Bundle.from_query(spec, request.db) | 163 | return Bundle.from_query(spec, request.db) |
127 | 164 | |||
128 | 165 | |||
129 | 166 | def redirect_url(request): | ||
130 | 167 | """Get the redirect_jujucharms configuration setting.""" | ||
131 | 168 | return request.registry.settings.get('redirect_jujucharms') | ||
132 | 164 | 169 | ||
133 | === modified file 'charmworld/views/tests/test_bundles.py' | |||
134 | --- charmworld/views/tests/test_bundles.py 2014-03-06 16:01:13 +0000 | |||
135 | +++ charmworld/views/tests/test_bundles.py 2015-02-18 14:26:31 +0000 | |||
136 | @@ -1,10 +1,12 @@ | |||
138 | 1 | # Copyright 2013-2014 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2013-2015 Canonical Ltd. This software is licensed under the |
139 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
140 | 3 | 3 | ||
141 | 4 | from StringIO import StringIO | 4 | from StringIO import StringIO |
142 | 5 | import datetime | 5 | import datetime |
143 | 6 | import unittest | 6 | import unittest |
144 | 7 | 7 | ||
145 | 8 | from pyramid.httpexceptions import HTTPMovedPermanently | ||
146 | 9 | |||
147 | 8 | from charmworld.models import ( | 10 | from charmworld.models import ( |
148 | 9 | Bundle, | 11 | Bundle, |
149 | 10 | DatedMetric, | 12 | DatedMetric, |
150 | @@ -152,7 +154,7 @@ | |||
151 | 152 | found = find_bundle(request) | 154 | found = find_bundle(request) |
152 | 153 | self.assertEqual(bundle, found) | 155 | self.assertEqual(bundle, found) |
153 | 154 | 156 | ||
155 | 155 | def test_multiple_bundles_picks_newest(self): | 157 | def _multiple_bundle_setup(self): |
156 | 156 | basket_rev1 = 'riak/1' | 158 | basket_rev1 = 'riak/1' |
157 | 157 | name = 'xyz' | 159 | name = 'xyz' |
158 | 158 | owner = 'matt' | 160 | owner = 'matt' |
159 | @@ -161,12 +163,16 @@ | |||
160 | 161 | basket_rev2 = 'riak/10' | 163 | basket_rev2 = 'riak/10' |
161 | 162 | bundle2, bundle2_data = factory.makeBundle( | 164 | bundle2, bundle2_data = factory.makeBundle( |
162 | 163 | self.db, name=name, owner=owner, basket_with_rev=basket_rev2) | 165 | self.db, name=name, owner=owner, basket_with_rev=basket_rev2) |
163 | 166 | return name, owner, bundle2 | ||
164 | 167 | |||
165 | 168 | def test_multiple_bundles_picks_newest(self): | ||
166 | 169 | name, owner, expected_bundle = self._multiple_bundle_setup() | ||
167 | 164 | request = self.getRequest() | 170 | request = self.getRequest() |
168 | 165 | request.matchdict = dict(bundle=name, | 171 | request.matchdict = dict(bundle=name, |
169 | 166 | basket='riak', | 172 | basket='riak', |
170 | 167 | owner=owner) | 173 | owner=owner) |
171 | 168 | found = find_bundle(request) | 174 | found = find_bundle(request) |
173 | 169 | self.assertEqual(bundle2, found) | 175 | self.assertEqual(expected_bundle, found) |
174 | 170 | 176 | ||
175 | 171 | def test_found_bundle_promulgated(self): | 177 | def test_found_bundle_promulgated(self): |
176 | 172 | bundle, bundle_data = factory.makeBundle(self.db, promulgated=True) | 178 | bundle, bundle_data = factory.makeBundle(self.db, promulgated=True) |
177 | @@ -198,13 +204,10 @@ | |||
178 | 198 | basket=basket, | 204 | basket=basket, |
179 | 199 | bundle=bundle.name, | 205 | bundle=bundle.name, |
180 | 200 | ) | 206 | ) |
188 | 201 | expected = dict( | 207 | with self.assertRaises(HTTPMovedPermanently) as ctx: |
189 | 202 | series='raring', | 208 | personal_bundle(request) |
190 | 203 | relations={}, | 209 | expected = '/q/{}?type=bundle'.format(basket) |
191 | 204 | services={}, | 210 | self.assertTrue(ctx.exception.location.endswith(expected)) |
185 | 205 | ) | ||
186 | 206 | response = personal_bundle(request) | ||
187 | 207 | self.assertEqual(expected, response['bundle'].data) | ||
192 | 208 | 211 | ||
193 | 209 | def test_personal_bundle_json(self): | 212 | def test_personal_bundle_json(self): |
194 | 210 | basket = 'ball' | 213 | basket = 'ball' |
195 | @@ -298,37 +301,63 @@ | |||
196 | 298 | # Test that the route works. | 301 | # Test that the route works. |
197 | 299 | path = '/bundle/~{owner}/{basket}/{bundle}'.format( | 302 | path = '/bundle/~{owner}/{basket}/{bundle}'.format( |
198 | 300 | owner=owner, basket=basket, bundle=bundle_name) | 303 | owner=owner, basket=basket, bundle=bundle_name) |
212 | 301 | resp = self.app.get(path, status=200) | 304 | resp = self.app.get(path, status=301) |
213 | 302 | self.assertIn(bundle.owner, resp.body) | 305 | expected = '/q/{}?type=bundle'.format(basket) |
214 | 303 | self.assertIn(bundle.data['series'], resp.body) | 306 | self.assertTrue(resp.location.endswith(expected)) |
215 | 304 | self.assertIn(bundle.basket_name, resp.body) | 307 | |
216 | 305 | self.assertIn(bundle.owner, resp.body) | 308 | def test_personal_bundle_route_multi_bundle_basket(self): |
217 | 306 | # Ensure the short url to the branch on Launchpad is in the body. | 309 | owner = 'ladonna' |
218 | 307 | lp_path = '~{owner}/charms/bundles/{basket}/bundle'.format( | 310 | basket = 'treme' |
219 | 308 | owner=owner, basket=basket) | 311 | bundle_name = 'gigis' |
220 | 309 | lp_short_url = 'lp:{path}'.format(path=lp_path) | 312 | rev = 1 |
221 | 310 | self.assertIn(lp_short_url, resp.body) | 313 | basket_with_rev = '%s/%d' % (basket, rev) |
222 | 311 | # Ensure the long url to the branch on Launchpad is in the body. | 314 | bundle_1, bundle_data_1 = factory.makeBundle( |
223 | 312 | lp_long_url = 'https://code.launchpad.net/{path}'.format(path=lp_path) | 315 | self.db, name=bundle_name, owner=owner, |
224 | 313 | self.assertIn(lp_long_url, resp.body) | 316 | basket_with_rev=basket_with_rev, series='raring', |
225 | 317 | with_basket=True, | ||
226 | 318 | ) | ||
227 | 319 | bundle_2, bundle_data_2 = factory.makeBundle( | ||
228 | 320 | self.db, name='other_bundle', owner=owner, | ||
229 | 321 | basket_with_rev=basket_with_rev, series='raring', | ||
230 | 322 | with_basket=True, | ||
231 | 323 | ) | ||
232 | 324 | # Test that the route works. | ||
233 | 325 | path = '/bundle/~{owner}/{basket}/{bundle}'.format( | ||
234 | 326 | owner=owner, basket=basket, bundle=bundle_name) | ||
235 | 327 | resp = self.app.get(path, status=301) | ||
236 | 328 | expected = '/q/{}?type=bundle'.format(basket) | ||
237 | 329 | self.assertTrue(resp.location.endswith(expected)) | ||
238 | 330 | |||
239 | 331 | def test_personal_bundle_route_not_found(self): | ||
240 | 332 | # We just forward without checking the database, so a 404 is not | ||
241 | 333 | # thrown. | ||
242 | 334 | basket = 'nobasket' | ||
243 | 335 | path = '/bundle/~noowner/{}/nobundle'.format(basket) | ||
244 | 336 | resp = self.app.get(path, status=301) | ||
245 | 337 | expected = '/q/{}?type=bundle'.format(basket) | ||
246 | 338 | self.assertTrue(resp.location.endswith(expected)) | ||
247 | 314 | 339 | ||
248 | 315 | def test_personal_bundle_route_with_revision(self): | 340 | def test_personal_bundle_route_with_revision(self): |
249 | 341 | basket = 'wicker' | ||
250 | 316 | bundle, bundle_data = factory.makeBundle( | 342 | bundle, bundle_data = factory.makeBundle( |
251 | 317 | self.db, name='gigis', owner='ladonna', | 343 | self.db, name='gigis', owner='ladonna', |
253 | 318 | basket_with_rev='basket/1', series='raring', | 344 | basket_with_rev='{}/1'.format(basket), series='raring', |
254 | 319 | ) | 345 | ) |
259 | 320 | path = '/bundle/~ladonna/basket/1/gigis' | 346 | path = '/bundle/~ladonna/{}/1/gigis'.format(basket) |
260 | 321 | response = self.app.get(path, status=200) | 347 | resp = self.app.get(path, status=301) |
261 | 322 | self.assertIn( | 348 | expected = '/q/{}?type=bundle'.format(basket) |
262 | 323 | 'lp:~ladonna/charms/bundles/basket/bundle', response.body) | 349 | self.assertTrue(resp.location.endswith(expected)) |
263 | 324 | 350 | ||
264 | 325 | def test_personal_bundle_route_404(self): | 351 | def test_personal_bundle_route_404(self): |
265 | 352 | basket = 'wicker' | ||
266 | 326 | bundle, bundle_data = factory.makeBundle( | 353 | bundle, bundle_data = factory.makeBundle( |
267 | 327 | self.db, name='gigis', owner='ladonna', | 354 | self.db, name='gigis', owner='ladonna', |
269 | 328 | basket_with_rev='basket/1', series='raring', | 355 | basket_with_rev='{}/1'.format(basket), series='raring', |
270 | 329 | ) | 356 | ) |
273 | 330 | path = '/bundle/~ladonna/basket/1/XXX' | 357 | path = '/bundle/~ladonna/{}/1/XXX'.format(basket) |
274 | 331 | self.app.get(path, status=404) | 358 | resp = self.app.get(path, status=301) |
275 | 359 | expected = '/q/{}?type=bundle'.format(basket) | ||
276 | 360 | self.assertTrue(resp.location.endswith(expected)) | ||
277 | 332 | 361 | ||
278 | 333 | def test_personal_bundle_with_revision_json_route(self): | 362 | def test_personal_bundle_with_revision_json_route(self): |
279 | 334 | # A JSON-encoded bundle can be requested in which the ID includes both | 363 | # A JSON-encoded bundle can be requested in which the ID includes both |
280 | @@ -364,7 +393,7 @@ | |||
281 | 364 | path = '/bundle/~ladonna/basket/1/XXX/json' | 393 | path = '/bundle/~ladonna/basket/1/XXX/json' |
282 | 365 | self.app.get(path, status=404) | 394 | self.app.get(path, status=404) |
283 | 366 | 395 | ||
285 | 367 | def test_official_bundle_route(self): | 396 | def test_official_bundle_json_route(self): |
286 | 368 | bundle, bundle_data = factory.makeBundle( | 397 | bundle, bundle_data = factory.makeBundle( |
287 | 369 | self.db, name='wiki', owner='charmers', | 398 | self.db, name='wiki', owner='charmers', |
288 | 370 | basket_with_rev='wiki-basket/1', series='raring', promulgated=True, | 399 | basket_with_rev='wiki-basket/1', series='raring', promulgated=True, |
289 | @@ -376,14 +405,16 @@ | |||
290 | 376 | self.assertIn(str(bundle.data['services']), resp.body) | 405 | self.assertIn(str(bundle.data['services']), resp.body) |
291 | 377 | 406 | ||
292 | 378 | def test_official_bundle_with_revision_route(self): | 407 | def test_official_bundle_with_revision_route(self): |
293 | 408 | basket = 'wiki-basket' | ||
294 | 379 | bundle, bundle_data = factory.makeBundle( | 409 | bundle, bundle_data = factory.makeBundle( |
295 | 380 | self.db, name='wiki', owner='charmers', | 410 | self.db, name='wiki', owner='charmers', |
297 | 381 | basket_with_rev='wiki-basket/1', series='raring', promulgated=True, | 411 | basket_with_rev='{}/1'.format(basket), series='raring', |
298 | 412 | promulgated=True, | ||
299 | 382 | ) | 413 | ) |
304 | 383 | path = '/bundle/wiki-basket/1/wiki' | 414 | path = '/bundle/{}/1/wiki'.format(basket) |
305 | 384 | response = self.app.get(path, status=200) | 415 | resp = self.app.get(path, status=301) |
306 | 385 | self.assertIn( | 416 | expected = '/q/{}?type=bundle'.format(basket) |
307 | 386 | 'lp:~charmers/charms/bundles/wiki-basket/bundle', response.body) | 417 | self.assertTrue(resp.location.endswith(expected)) |
308 | 387 | 418 | ||
309 | 388 | def test_official_bundle_route_404(self): | 419 | def test_official_bundle_route_404(self): |
310 | 389 | bundle, bundle_data = factory.makeBundle( | 420 | bundle, bundle_data = factory.makeBundle( |
311 | @@ -394,25 +425,15 @@ | |||
312 | 394 | self.app.get(path, status=404) | 425 | self.app.get(path, status=404) |
313 | 395 | 426 | ||
314 | 396 | def test_bundle_short_url_route(self): | 427 | def test_bundle_short_url_route(self): |
334 | 397 | bundle, bundle_data = factory.makeBundle( | 428 | basket = 'wicker' |
335 | 398 | self.db, name='gigis', owner='ladonna', | 429 | bundle, bundle_data = factory.makeBundle( |
336 | 399 | basket_with_rev='basket/1', series='raring', promulgated=True, | 430 | self.db, name='gigis', owner='ladonna', |
337 | 400 | ) | 431 | basket_with_rev='{}/1'.format(basket), series='raring', |
338 | 401 | self.app.get('/' + bundle.short_url, status=200) | 432 | promulgated=True, |
339 | 402 | 433 | ) | |
340 | 403 | 434 | resp = self.app.get('/' + bundle.short_url, status=301) | |
341 | 404 | class BundleDisplayTests(WebTestBase): | 435 | expected = '/q/{}?type=bundle'.format(basket) |
342 | 405 | """Verify that bundles are displayed correctly.""" | 436 | self.assertTrue(resp.location.endswith(expected)) |
324 | 406 | |||
325 | 407 | def test_download_statistics_are_displayed(self): | ||
326 | 408 | # The rendered page includes details about the number of times this | ||
327 | 409 | # bundle has been "downloaded" (actually, it means "deployed"). | ||
328 | 410 | bundle, bundle_data = factory.makeBundle( | ||
329 | 411 | self.db, name='gigis', owner='ladonna', | ||
330 | 412 | basket_with_rev='basket/1', series='raring', promulgated=True, | ||
331 | 413 | ) | ||
332 | 414 | response = self.app.get('/' + bundle.short_url, status=200) | ||
333 | 415 | self.assertIn('>Downloads<', response.body) | ||
343 | 416 | 437 | ||
344 | 417 | 438 | ||
345 | 418 | class StatisticsTests(unittest.TestCase): | 439 | class StatisticsTests(unittest.TestCase): |
346 | 419 | 440 | ||
347 | === modified file 'default.ini' | |||
348 | --- default.ini 2015-02-09 14:16:33 +0000 | |||
349 | +++ default.ini 2015-02-18 14:26:31 +0000 | |||
350 | @@ -29,6 +29,9 @@ | |||
351 | 29 | # App Settings | 29 | # App Settings |
352 | 30 | project_name = Charm Browser | 30 | project_name = Charm Browser |
353 | 31 | 31 | ||
354 | 32 | # Caching settings | ||
355 | 33 | http_cache = | ||
356 | 34 | |||
357 | 32 | # List of groups/teams that have edit access. | 35 | # List of groups/teams that have edit access. |
358 | 33 | openid_teams = charmers,juju-jitsu | 36 | openid_teams = charmers,juju-jitsu |
359 | 34 | 37 | ||
360 | @@ -71,6 +74,9 @@ | |||
361 | 71 | # New web site for redirection | 74 | # New web site for redirection |
362 | 72 | redirect_jujucharms = https://jujucharms.com | 75 | redirect_jujucharms = https://jujucharms.com |
363 | 73 | 76 | ||
364 | 77 | # This signals that we are running under test. | ||
365 | 78 | is_testing = false | ||
366 | 79 | |||
367 | 74 | [server:main] | 80 | [server:main] |
368 | 75 | use = egg:Paste#http | 81 | use = egg:Paste#http |
369 | 76 | host = 0.0.0.0 | 82 | host = 0.0.0.0 |
370 | @@ -134,3 +140,4 @@ | |||
371 | 134 | format = %(asctime)s %(message)s | 140 | format = %(asctime)s %(message)s |
372 | 135 | 141 | ||
373 | 136 | # End logging configuration | 142 | # End logging configuration |
374 | 143 |
Looks good to me with minor suggestions.
Thank you!