Merge lp:~mwhudson/launchpad/vostok-main-template into lp:launchpad

Proposed by Michael Hudson-Doyle
Status: Merged
Approved by: Michael Hudson-Doyle
Approved revision: no longer in the source branch.
Merged at revision: 11299
Proposed branch: lp:~mwhudson/launchpad/vostok-main-template
Merge into: lp:launchpad
Prerequisite: lp:~mwhudson/launchpad/vostok-add-root
Diff against target: 324 lines (+155/-20)
11 files modified
Makefile (+1/-0)
lib/canonical/launchpad/doc/webapp-publication.txt (+5/-0)
lib/lp/vostok/browser/configure.zcml (+8/-0)
lib/lp/vostok/browser/root.py (+9/-0)
lib/lp/vostok/browser/tests/request.py (+5/-7)
lib/lp/vostok/browser/tests/test_main_template.py (+33/-0)
lib/lp/vostok/browser/tests/test_root.py (+41/-3)
lib/lp/vostok/publisher.py (+18/-1)
lib/lp/vostok/templates/main-template.pt (+15/-0)
lib/lp/vostok/templates/root.pt (+20/-3)
lib/lp/vostok/tests/test_publisher.py (+0/-6)
To merge this branch: bzr merge lp:~mwhudson/launchpad/vostok-main-template
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Review via email: mp+31240@code.launchpad.net

Commit message

Add the publication plumbing and very basic root page for the 'vostok' vhost

Description of the change

Hi,

This branch adds a very simple main template METAL macro for the vostok layer
and makes the view for the root object use it.

The macro is done in an old-school way compared to how it's done in Launchpad
today, mostly because we couldn't be bothered to figure out how to make the
macro: tales stuff be layer dependent and also because we should be able to get
away with all our pages using the same main template macro.

Cheers,
mwh

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

> class VostokTestRequest(VostokRequestMixin, LaunchpadTestRequest):
> pass

Instead of pass, how about a docstring?

The browser tests are missing docstrings too. I know they are (most likely)
boring, but should be there anyway.

> def test_distributions(self):
> # VostokRootView.distributions is an iterable of all registered
> # distributions.
> root_view = self.view()

This likes you are actually doing

     VostokRootView.__call__

Is that what you want? I wouldn't have thought so.

Are you familiar at all with the new lp.testing.BrowserTestCase?
It might be better than manually creating the view, initializing it, and
rendering it.

VostokBrowserRequest could benefit from a docstring rather than pass too.

I think that your main-template.pt macro should be a valid HTML file rather
than just <h1> and <div>. I'm pretty sure that most of the HTML in root.pt is
discarded given that it is using the master macro.

review: Needs Information
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

On Thu, 29 Jul 2010 23:38:41 -0000, Tim Penhey <email address hidden> wrote:
> Review: Needs Information
> > class VostokTestRequest(VostokRequestMixin, LaunchpadTestRequest):
> > pass
>
> Instead of pass, how about a docstring?

OK.

> The browser tests are missing docstrings too. I know they are (most likely)
> boring, but should be there anyway.

Added.

> > def test_distributions(self):
> > # VostokRootView.distributions is an iterable of all registered
> > # distributions.
> > root_view = self.view()
>
> This likes you are actually doing
>
> VostokRootView.__call__
>
> Is that what you want? I wouldn't have thought so.

view is a method, not a property.

> Are you familiar at all with the new lp.testing.BrowserTestCase?
> It might be better than manually creating the view, initializing it, and
> rendering it.

The basic reason I didn't use testbrowser was that I wanted to have the
view object around so I can check the list matches up with what's in the
template -- the idea being to test the template. I agree it's a bit
ugly.

> VostokBrowserRequest could benefit from a docstring rather than pass too.

I sprinkled a few docstrings around.

> I think that your main-template.pt macro should be a valid HTML file rather
> than just <h1> and <div>. I'm pretty sure that most of the HTML in root.pt is
> discarded given that it is using the master macro.

You were right. Fixed.

Cheers,
mwh

Revision history for this message
Tim Penhey (thumper) wrote :

Changes look good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2010-08-05 01:32:59 +0000
+++ Makefile 2010-08-05 01:33:00 +0000
@@ -200,6 +200,7 @@
200 configuration:instance_name=${LPCONFIG} -c $(BUILDOUT_CFG)200 configuration:instance_name=${LPCONFIG} -c $(BUILDOUT_CFG)
201201
202compile: $(PY) $(BZR_VERSION_INFO)202compile: $(PY) $(BZR_VERSION_INFO)
203 mkdir -p /var/tmp/vostok-archive
203 ${SHHH} $(MAKE) -C sourcecode build PYTHON=${PYTHON} \204 ${SHHH} $(MAKE) -C sourcecode build PYTHON=${PYTHON} \
204 LPCONFIG=${LPCONFIG}205 LPCONFIG=${LPCONFIG}
205 ${SHHH} LPCONFIG=${LPCONFIG} ${PY} -t buildmailman.py206 ${SHHH} LPCONFIG=${LPCONFIG} ${PY} -t buildmailman.py
206207
=== modified file 'lib/canonical/launchpad/doc/webapp-publication.txt'
--- lib/canonical/launchpad/doc/webapp-publication.txt 2010-07-23 08:50:49 +0000
+++ lib/canonical/launchpad/doc/webapp-publication.txt 2010-08-05 01:33:00 +0000
@@ -93,6 +93,10 @@
93 rooturl: http://ubuntu-openid.launchpad.dev/93 rooturl: http://ubuntu-openid.launchpad.dev/
94 althosts:94 althosts:
95 ----95 ----
96 vostok @ vostok.dev
97 rooturl: http://vostok.dev/
98 althosts:
99 ----
96 xmlrpc @ xmlrpc.launchpad.dev100 xmlrpc @ xmlrpc.launchpad.dev
97 rooturl: http://launchpad.dev/101 rooturl: http://launchpad.dev/
98 althosts:102 althosts:
@@ -124,6 +128,7 @@
124 testopenid.dev128 testopenid.dev
125 translations.launchpad.dev129 translations.launchpad.dev
126 ubuntu-openid.launchpad.dev130 ubuntu-openid.launchpad.dev
131 vostok.dev
127 xmlrpc-private.launchpad.dev132 xmlrpc-private.launchpad.dev
128 xmlrpc.launchpad.dev133 xmlrpc.launchpad.dev
129134
130135
=== modified file 'lib/lp/vostok/browser/configure.zcml'
--- lib/lp/vostok/browser/configure.zcml 2010-08-05 01:32:59 +0000
+++ lib/lp/vostok/browser/configure.zcml 2010-08-05 01:33:00 +0000
@@ -5,6 +5,14 @@
5 xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"5 xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
6 i18n_domain="launchpad">6 i18n_domain="launchpad">
77
8 <browser:page
9 for="*"
10 name="main_template"
11 template="../templates/main-template.pt"
12 permission="zope.Public"
13 layer="lp.vostok.publisher.VostokLayer"
14 />
15
8 <browser:defaultView16 <browser:defaultView
9 for="lp.vostok.publisher.IVostokRoot"17 for="lp.vostok.publisher.IVostokRoot"
10 name="+index"18 name="+index"
1119
=== modified file 'lib/lp/vostok/browser/root.py'
--- lib/lp/vostok/browser/root.py 2010-08-05 01:32:59 +0000
+++ lib/lp/vostok/browser/root.py 2010-08-05 01:33:00 +0000
@@ -8,8 +8,17 @@
8 'VostokRootView',8 'VostokRootView',
9 ]9 ]
1010
11from zope.component import getUtility
12
11from canonical.launchpad.webapp import LaunchpadView13from canonical.launchpad.webapp import LaunchpadView
1214
15from lp.registry.interfaces.distribution import IDistributionSet
16
1317
14class VostokRootView(LaunchpadView):18class VostokRootView(LaunchpadView):
15 """The view for the Vostok root object."""19 """The view for the Vostok root object."""
20
21 @property
22 def distributions(self):
23 """An iterable of all registered distributions."""
24 return getUtility(IDistributionSet)
1625
=== modified file 'lib/lp/vostok/browser/tests/request.py'
--- lib/lp/vostok/browser/tests/request.py 2010-08-05 01:32:59 +0000
+++ lib/lp/vostok/browser/tests/request.py 2010-08-05 01:33:00 +0000
@@ -8,12 +8,10 @@
8 'VostokTestRequest',8 'VostokTestRequest',
9 ]9 ]
1010
11from zope.interface import implements
12
13from canonical.launchpad.webapp.servers import LaunchpadTestRequest11from canonical.launchpad.webapp.servers import LaunchpadTestRequest
1412
15from lp.vostok.publisher import VostokLayer13from lp.vostok.publisher import VostokRequestMixin
1614
1715
18class VostokTestRequest(LaunchpadTestRequest):16class VostokTestRequest(VostokRequestMixin, LaunchpadTestRequest):
19 implements(VostokLayer)17 """A test request for `VostokLayer`."""
2018
=== added file 'lib/lp/vostok/browser/tests/test_main_template.py'
--- lib/lp/vostok/browser/tests/test_main_template.py 1970-01-01 00:00:00 +0000
+++ lib/lp/vostok/browser/tests/test_main_template.py 2010-08-05 01:33:00 +0000
@@ -0,0 +1,33 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for the vostok 'main_template'."""
5
6__metaclass__ = type
7
8import unittest
9
10from zope.component import getMultiAdapter
11
12from canonical.testing.layers import FunctionalLayer
13
14from lp.testing import TestCase
15from lp.vostok.browser.tests.request import VostokTestRequest
16
17
18class TestMainTemplate(TestCase):
19 """Tests for our main template."""
20
21 layer = FunctionalLayer
22
23 def test_main_template_defines_master_macro(self):
24 # The main template, which is registered as a view for any object at
25 # all when in the VostokLayer, defines a 'master' macro.
26 adapter = getMultiAdapter(
27 (None, VostokTestRequest()), name='main_template')
28 self.assertEqual(['master'], adapter.index.macros.keys())
29 self.assertIn('lp/vostok', adapter.index.filename)
30
31
32def test_suite():
33 return unittest.TestLoader().loadTestsFromName(__name__)
034
=== modified file 'lib/lp/vostok/browser/tests/test_root.py'
--- lib/lp/vostok/browser/tests/test_root.py 2010-08-05 01:32:59 +0000
+++ lib/lp/vostok/browser/tests/test_root.py 2010-08-05 01:33:00 +0000
@@ -9,16 +9,19 @@
99
10from zope.app.publisher.browser import getDefaultViewName10from zope.app.publisher.browser import getDefaultViewName
1111
12from canonical.testing.layers import FunctionalLayer12from canonical.testing.layers import DatabaseFunctionalLayer, FunctionalLayer
13from canonical.launchpad.testing.pages import extract_text, find_tag_by_id
1314
14from lp.testing import TestCase15from lp.testing import TestCase, TestCaseWithFactory
15from lp.testing.views import create_initialized_view16from lp.testing.views import create_initialized_view
16from lp.vostok.browser.root import VostokRootView17from lp.vostok.browser.root import VostokRootView
17from lp.vostok.browser.tests.request import VostokTestRequest18from lp.vostok.browser.tests.request import VostokTestRequest
18from lp.vostok.publisher import VostokLayer, VostokRoot19from lp.vostok.publisher import VostokLayer, VostokRoot
1920
2021
21class TestBrowseRoot(TestCase):22
23class TestRootRegistrations(TestCase):
24 """Test the registration of views for `VostokRoot`."""
2225
23 layer = FunctionalLayer26 layer = FunctionalLayer
2427
@@ -34,5 +37,40 @@
34 self.assertIsInstance(view, VostokRootView)37 self.assertIsInstance(view, VostokRootView)
3538
3639
40class TestRootView(TestCaseWithFactory):
41 """Tests for `VostokRootView`."""
42
43 layer = DatabaseFunctionalLayer
44
45 def view(self):
46 return create_initialized_view(
47 VostokRoot(), name='+index', layer=VostokLayer)
48
49 def test_distributions(self):
50 # VostokRootView.distributions is an iterable of all registered
51 # distributions.
52 root_view = self.view()
53 new_distro = self.factory.makeDistribution()
54 self.assertIn(new_distro, list(root_view.distributions))
55
56
57class TestRootTemplate(TestCaseWithFactory):
58 """Tests for the templates used by views of `VostokRoot`."""
59
60 layer = DatabaseFunctionalLayer
61
62 def test_distribution_list(self):
63 # The element with id 'distro-list' on the root page contains a list
64 # of links to all registered distributions.
65 v = create_initialized_view(
66 VostokRoot(), name='+index', layer=VostokLayer)
67 contents = v.render()
68 link_list = find_tag_by_id(contents, 'distro-list')('a')
69 distro_list = list(v.distributions)
70 self.assertEqual(len(link_list), len(distro_list))
71 for distro, link in zip(distro_list, link_list):
72 self.assertEqual(distro.displayname, extract_text(link))
73
74
37def test_suite():75def test_suite():
38 return unittest.TestLoader().loadTestsFromName(__name__)76 return unittest.TestLoader().loadTestsFromName(__name__)
3977
=== modified file 'lib/lp/vostok/publisher.py'
--- lib/lp/vostok/publisher.py 2010-08-05 01:32:59 +0000
+++ lib/lp/vostok/publisher.py 2010-08-05 01:33:00 +0000
@@ -18,21 +18,38 @@
18from canonical.launchpad.webapp.publication import LaunchpadBrowserPublication18from canonical.launchpad.webapp.publication import LaunchpadBrowserPublication
19from canonical.launchpad.webapp.servers import (19from canonical.launchpad.webapp.servers import (
20 LaunchpadBrowserRequest, VirtualHostRequestPublicationFactory)20 LaunchpadBrowserRequest, VirtualHostRequestPublicationFactory)
21from canonical.launchpad.webapp.vhosts import allvhosts
2122
2223
23class VostokLayer(IBrowserRequest, IDefaultBrowserLayer):24class VostokLayer(IBrowserRequest, IDefaultBrowserLayer):
24 """The Vostok layer."""25 """The Vostok layer."""
2526
2627
27class VostokBrowserRequest(LaunchpadBrowserRequest):28class VostokRequestMixin:
29 """This mixin defines behaviour for the real and test Vostok requests."""
30
28 implements(VostokLayer)31 implements(VostokLayer)
2932
33 def getRootURL(self, rootsite):
34 """See `IBasicLaunchpadRequest`."""
35 return allvhosts.configs['vostok'].rooturl
36
37
38class VostokBrowserRequest(VostokRequestMixin, LaunchpadBrowserRequest):
39 """Request class for Vostok layer."""
40
3041
31class IVostokRoot(Interface):42class IVostokRoot(Interface):
32 """Marker interface for the root vostok object."""43 """Marker interface for the root vostok object."""
3344
3445
35class VostokRoot:46class VostokRoot:
47 """The root object for the Vostok site.
48
49 No behaviour here, it just exists so it can have view and navigation
50 registrations attached to it.
51 """
52
36 implements(IVostokRoot)53 implements(IVostokRoot)
3754
3855
3956
=== added file 'lib/lp/vostok/templates/main-template.pt'
--- lib/lp/vostok/templates/main-template.pt 1970-01-01 00:00:00 +0000
+++ lib/lp/vostok/templates/main-template.pt 2010-08-05 01:33:00 +0000
@@ -0,0 +1,15 @@
1<metal:page
2 xmlns:metal="http://xml.zope.org/namespaces/metal"
3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 define-macro="master"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5<html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <!-- Obviously, we'll need to do something better here. -->
8 <title>Vostok page</title>
9 </head>
10 <body>
11 <h1 metal:define-slot="heading" />
12 <div metal:define-slot="content" />
13 </body>
14</html>
15</metal:page>
016
=== modified file 'lib/lp/vostok/templates/root.pt'
--- lib/lp/vostok/templates/root.pt 2010-08-05 01:32:59 +0000
+++ lib/lp/vostok/templates/root.pt 2010-08-05 01:33:00 +0000
@@ -1,3 +1,20 @@
1<big>1<html
2THIS IS VOSTOK2 xmlns="http://www.w3.org/1999/xhtml"
3</big>3 xmlns:tal="http://xml.zope.org/namespaces/tal"
4 xmlns:metal="http://xml.zope.org/namespaces/metal"
5 xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6 metal:use-macro="context/@@main_template/master"
7 i18n:domain="vostok">
8 <body>
9 <tal:heading metal:fill-slot="heading">
10 <h1>Vostok</h1>
11 </tal:heading>
12 <tal:content metal:fill-slot="content">
13 <ul id="distro-list">
14 <tal:loop tal:repeat="distro view/distributions">
15 <li tal:content="structure distro/fmt:link" />
16 </tal:loop>
17 </ul>
18 </tal:content>
19 </body>
20</html>
421
=== modified file 'lib/lp/vostok/tests/test_publisher.py'
--- lib/lp/vostok/tests/test_publisher.py 2010-08-05 01:32:59 +0000
+++ lib/lp/vostok/tests/test_publisher.py 2010-08-05 01:33:00 +0000
@@ -9,15 +9,12 @@
99
10from canonical.config import config10from canonical.config import config
11from canonical.testing.layers import FunctionalLayer11from canonical.testing.layers import FunctionalLayer
12from canonical.launchpad.webapp.interfaces import IOpenLaunchBag
1312
14from lp.testing import TestCase13from lp.testing import TestCase
15from lp.testing.publication import get_request_and_publication14from lp.testing.publication import get_request_and_publication
1615
17from lp.vostok.publisher import VostokLayer, VostokRoot16from lp.vostok.publisher import VostokLayer, VostokRoot
1817
19from zope.component import getUtility
20
2118
22class TestRegistration(TestCase):19class TestRegistration(TestCase):
23 """Vostok's publication customizations are installed correctly."""20 """Vostok's publication customizations are installed correctly."""
@@ -37,9 +34,6 @@
37 request, publication = get_request_and_publication(34 request, publication = get_request_and_publication(
38 host=config.vhost.vostok.hostname)35 host=config.vhost.vostok.hostname)
39 self.assertProvides(request, VostokLayer)36 self.assertProvides(request, VostokLayer)
40 # XXX getApplication caches the root object in the LaunchBag, so we
41 # need to set it up, or it crashes.
42 getUtility(IOpenLaunchBag).clear()
43 root = publication.getApplication(request)37 root = publication.getApplication(request)
44 self.assertIsInstance(root, VostokRoot)38 self.assertIsInstance(root, VostokRoot)
4539