~launchpad-pqm/launchpad/devel

12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
1
# Copyright 2011 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
12400.2.3 by Steve Kowalik
Rename test_archive_sourcepackagerecipe.py to test_publishing.py and make it
4
"""Tests for source package publication listing."""
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
5
6
__metaclass__ = type
7
12400.2.5 by Steve Kowalik
Use soupmatchers to match the built string. Add line breaks into the TAL.
8
import soupmatchers
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
9
from testtools.matchers import (
10
    Contains,
11
    MatchesAll,
12
    )
13
from zope.app.testing.functional import HTTPCaller
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
14
from zope.component import getUtility
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
15
from zope.publisher.interfaces import NotFound
14185.1.6 by William Grant
Test private changelogs too.
16
from zope.security.interfaces import Unauthorized
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
17
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
18
from canonical.launchpad.ftests import logout
19
from canonical.launchpad.webapp.publisher import (
20
    canonical_url,
21
    RedirectionView,
22
    )
14550.1.1 by Steve Kowalik
Run format-imports over lib/lp and lib/canonical/launchpad
23
from canonical.testing.layers import LaunchpadFunctionalLayer
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
24
from lp.registry.interfaces.person import IPersonSet
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
25
from lp.soyuz.browser.publishing import (
26
    SourcePackagePublishingHistoryNavigation,
27
    )
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
28
from lp.soyuz.enums import PackagePublishingStatus
14185.1.6 by William Grant
Test private changelogs too.
29
from lp.soyuz.interfaces.archive import ArchivePurpose
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
30
from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
31
from lp.testing import (
32
    BrowserTestCase,
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
33
    FakeLaunchpadRequest,
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
34
    person_logged_in,
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
35
    TestCaseWithFactory,
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
36
    )
37
from lp.testing.sampledata import ADMIN_EMAIL
38
39
12400.2.3 by Steve Kowalik
Rename test_archive_sourcepackagerecipe.py to test_publishing.py and make it
40
class TestSourcePublicationListingExtra(BrowserTestCase):
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
41
    layer = LaunchpadFunctionalLayer
42
43
    def setUp(self):
12400.2.3 by Steve Kowalik
Rename test_archive_sourcepackagerecipe.py to test_publishing.py and make it
44
        super(TestSourcePublicationListingExtra, self).setUp()
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
45
        self.admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
46
        # Create everything we need to create builds, such as a
47
        # DistroArchSeries and a builder.
48
        self.pf = self.factory.makeProcessorFamily()
49
        pf_proc = self.pf.addProcessor(self.factory.getUniqueString(), '', '')
50
        self.distroseries = self.factory.makeDistroSeries()
51
        self.das = self.factory.makeDistroArchSeries(
52
            distroseries=self.distroseries, processorfamily=self.pf,
53
            supports_virtualized=True)
54
        self.archive = self.factory.makeArchive(
55
            distribution=self.distroseries.distribution)
56
        with person_logged_in(self.admin):
57
            self.publisher = SoyuzTestPublisher()
58
            self.publisher.prepareBreezyAutotest()
59
            self.distroseries.nominatedarchindep = self.das
60
            self.publisher.addFakeChroots(distroseries=self.distroseries)
61
            self.builder = self.factory.makeBuilder(processor=pf_proc)
62
63
    def test_view_with_source_package_recipe(self):
64
        # When a SourcePackageRelease is linked to a
65
        # SourcePackageRecipeBuild, the view shows which recipe was
66
        # responsible for creating the SPR.
67
        sprb = self.factory.makeSourcePackageRecipeBuild(
68
            archive=self.archive)
69
        recipe = sprb.recipe
12400.2.6 by Steve Kowalik
Fix some formatting issues.
70
        requester = sprb.requester
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
71
        spph = self.publisher.getPubSource(
72
            archive=self.archive, status=PackagePublishingStatus.PUBLISHED)
73
        spph.sourcepackagerelease.source_package_recipe_build = sprb
12400.2.6 by Steve Kowalik
Fix some formatting issues.
74
        recipe_link_matches = soupmatchers.HTMLContains(
12400.2.5 by Steve Kowalik
Use soupmatchers to match the built string. Add line breaks into the TAL.
75
            soupmatchers.Tag(
12484.1.1 by Steve Kowalik
Refactor displaying recipe details savagely, and without mercy. Use structured
76
                'link to build', 'a', attrs={'href': canonical_url(sprb)},
12400.2.5 by Steve Kowalik
Use soupmatchers to match the built string. Add line breaks into the TAL.
77
                text='Built'),
78
            soupmatchers.Tag(
79
                'recipe name', 'a', attrs={'href': canonical_url(recipe)},
80
                text=recipe.name),
81
            soupmatchers.Tag(
82
                'requester', 'a',
12400.2.6 by Steve Kowalik
Fix some formatting issues.
83
                attrs={
12484.1.1 by Steve Kowalik
Refactor displaying recipe details savagely, and without mercy. Use structured
84
                    'href': canonical_url(requester)},
12400.2.6 by Steve Kowalik
Fix some formatting issues.
85
                text=requester.displayname))
12400.2.3 by Steve Kowalik
Rename test_archive_sourcepackagerecipe.py to test_publishing.py and make it
86
        browser = self.getViewBrowser(spph, '+listing-archive-extra')
12400.2.6 by Steve Kowalik
Fix some formatting issues.
87
        self.assertThat(browser.contents, recipe_link_matches)
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
88
89
    def test_view_without_source_package_recipe(self):
90
        # And if a SourcePackageRelease is not linked, there is no sign of it
91
        # in the view.
12400.2.3 by Steve Kowalik
Rename test_archive_sourcepackagerecipe.py to test_publishing.py and make it
92
        spph = self.publisher.getPubSource(
93
            archive=self.archive, status=PackagePublishingStatus.PUBLISHED)
94
        browser = self.getViewBrowser(spph, '+listing-archive-extra')
12400.2.1 by Steve Kowalik
Refactor the PPA traversal to not assume the distribution is Ubuntu. Add a new
95
        self.assertNotIn('Built by recipe', browser.contents)
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
96
12477.1.1 by Steve Kowalik
Show 'deleted recipe' if sprb/recipe is None.
97
    def test_view_with_deleted_source_package_recipe(self):
12477.1.2 by Steve Kowalik
Correct comment.
98
        # If a SourcePackageRelease is linked to a deleted recipe, the text
99
        # 'deleted recipe' is displayed, rather than a link.
12477.1.1 by Steve Kowalik
Show 'deleted recipe' if sprb/recipe is None.
100
        sprb = self.factory.makeSourcePackageRecipeBuild(
101
            archive=self.archive)
102
        recipe = sprb.recipe
103
        requester = sprb.requester
104
        spph = self.publisher.getPubSource(
105
            archive=self.archive, status=PackagePublishingStatus.PUBLISHED)
106
        spph.sourcepackagerelease.source_package_recipe_build = sprb
107
        with person_logged_in(recipe.owner):
108
            recipe.destroySelf()
109
        recipe_link_matches = soupmatchers.HTMLContains(
110
            soupmatchers.Tag(
111
                'link to build', 'a',
12484.1.1 by Steve Kowalik
Refactor displaying recipe details savagely, and without mercy. Use structured
112
                attrs={'href': canonical_url(sprb)},
12477.1.1 by Steve Kowalik
Show 'deleted recipe' if sprb/recipe is None.
113
                text='Built'),
114
            soupmatchers.Tag(
115
                'requester', 'a',
116
                attrs={
12484.1.1 by Steve Kowalik
Refactor displaying recipe details savagely, and without mercy. Use structured
117
                    'href': canonical_url(requester)},
12477.1.1 by Steve Kowalik
Show 'deleted recipe' if sprb/recipe is None.
118
                text=requester.displayname))
119
        browser = self.getViewBrowser(spph, '+listing-archive-extra')
120
        self.assertThat(browser.contents, recipe_link_matches)
121
        self.assertIn('deleted recipe', browser.contents)
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
122
123
124
class TestSourcePackagePublishingHistoryNavigation(TestCaseWithFactory):
125
    layer = LaunchpadFunctionalLayer
126
127
    def traverse(self, spph, segments):
128
        req = FakeLaunchpadRequest([], segments[1:])
129
        nav = SourcePackagePublishingHistoryNavigation(spph, req)
130
        return nav.publishTraverse(req, segments[0])
131
14185.1.6 by William Grant
Test private changelogs too.
132
    def makeSPPHWithChangelog(self, archive=None):
133
        lfa = self.factory.makeLibraryFileAlias(
134
            filename='changelog',
135
            restricted=(archive is not None and archive.private))
136
        spr = self.factory.makeSourcePackageRelease(changelog=lfa)
137
        return self.factory.makeSourcePackagePublishingHistory(
138
            archive=archive,
139
            sourcepackagerelease=spr)
140
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
141
    def test_changelog(self):
142
        # SPPH.SPR.changelog is accessible at +files/changelog.
14185.1.6 by William Grant
Test private changelogs too.
143
        spph = self.makeSPPHWithChangelog()
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
144
        view = self.traverse(spph, ['+files', 'changelog'])
145
        self.assertIsInstance(view, RedirectionView)
14185.1.6 by William Grant
Test private changelogs too.
146
        self.assertEqual(
147
            spph.sourcepackagerelease.changelog.http_url, view.target)
148
149
    def test_private_changelog(self):
150
        # Private changelogs are inaccessible to anonymous users.
151
        archive = self.factory.makeArchive(
152
            purpose=ArchivePurpose.PPA, private=True)
153
        spph = self.makeSPPHWithChangelog(archive=archive)
154
155
        # A normal user can't traverse to the changelog.
156
        self.assertRaises(
157
            Unauthorized, self.traverse, spph, ['+files', 'changelog'])
158
159
        # But the archive owner gets a librarian URL with a token.
160
        with person_logged_in(archive.owner):
161
            view = self.traverse(spph, ['+files', 'changelog'])
162
        self.assertThat(view.target, Contains('?token='))
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
163
164
    def test_unhandled_name(self):
165
        # Unhandled names raise a NotFound.
166
        spph = self.factory.makeSourcePackagePublishingHistory()
167
        self.assertRaises(
168
            NotFound, self.traverse, spph, ['+files', 'not-changelog'])
169
170
    def test_registered(self):
171
        # The Navigation is registered and traversable over HTTP.
14185.1.6 by William Grant
Test private changelogs too.
172
        spph = self.makeSPPHWithChangelog()
173
        lfa_url = spph.sourcepackagerelease.changelog.http_url
14185.1.4 by William Grant
Introduce SourcePackagePublishingHistoryNavigation, just with FileNavigationMixin for now.
174
        redir_url = (
175
            canonical_url(spph, path_only_if_possible=True)
176
            + '/+files/changelog')
177
        logout()
178
        response = str(HTTPCaller()("GET %s HTTP/1.1\n\n" % redir_url))
179
        self.assertThat(
180
            response,
181
            MatchesAll(
182
                Contains("HTTP/1.1 303 See Other"),
183
                Contains("Location: %s" % lfa_url)))