~launchpad-pqm/launchpad/devel

10498.3.6 by Aaron Bentley
Initial cut of index page.
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
10744.2.2 by Aaron Bentley
Tweakage.
3
# pylint: disable-msg=F0401,E1002
10498.3.6 by Aaron Bentley
Initial cut of index page.
4
7675.618.19 by Paul Hummer
Fixed docstring
5
"""Tests for the source package recipe view classes and templates."""
10498.3.6 by Aaron Bentley
Initial cut of index page.
6
7
__metaclass__ = type
8
9
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
10
from datetime import (
11
    datetime,
12
    timedelta,
13
    )
10498.3.13 by Aaron Bentley
Implement index page test.
14
from textwrap import dedent
15
13130.1.12 by Curtis Hovey
Sorted imports.
16
from BeautifulSoup import BeautifulSoup
11316.3.2 by Paul Hummer
Added test to make sure no one but the owner gets to delete recipes
17
from mechanize import LinkNotFoundError
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
18
from pytz import UTC
12373.2.15 by Tim Penhey
Move matchers to lp.testing.matchers.
19
from testtools.matchers import Equals
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
20
import transaction
11814.1.1 by Paul Hummer
Added test
21
from zope.component import getUtility
7675.711.1 by Paul Hummer
Added test for failing code.
22
from zope.security.interfaces import Unauthorized
10498.3.14 by Aaron Bentley
Ensure build status is correctly displayed.
23
from zope.security.proxy import removeSecurityProxy
10498.3.6 by Aaron Bentley
Initial cut of index page.
24
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
25
from canonical.database.constants import UTC_NOW
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
26
from canonical.launchpad.testing.pages import (
27
    extract_text,
28
    find_main_content,
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
29
    find_tag_by_id,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
30
    find_tags_by_class,
12177.4.1 by Tim Penhey
Show a message on the main recipe page if the recipe owner can't upload into the daily ppa.
31
    get_feedback_messages,
11929.11.19 by Tim Penhey
A few more options.
32
    get_radio_button_text_for_field,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
33
    )
10498.3.6 by Aaron Bentley
Initial cut of index page.
34
from canonical.launchpad.webapp import canonical_url
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
35
from canonical.launchpad.webapp.interfaces import ILaunchpadRoot
13130.1.12 by Curtis Hovey
Sorted imports.
36
from canonical.launchpad.webapp.servers import LaunchpadTestRequest
11666.3.5 by Curtis Hovey
Import layers from canonical.testing.layers.
37
from canonical.testing.layers import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
38
    DatabaseFunctionalLayer,
39
    LaunchpadFunctionalLayer,
40
    )
13130.1.12 by Curtis Hovey
Sorted imports.
41
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
11458.1.1 by Jelmer Vernooij
Move enums of buildmaster.
42
from lp.buildmaster.enums import BuildStatus
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
43
from lp.code.browser.sourcepackagerecipe import (
13130.1.12 by Curtis Hovey
Sorted imports.
44
    SourcePackageRecipeEditView,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
45
    SourcePackageRecipeRequestBuildsView,
13130.1.12 by Curtis Hovey
Sorted imports.
46
    SourcePackageRecipeView,
47
    )
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
48
from lp.code.browser.sourcepackagerecipebuild import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
49
    SourcePackageRecipeBuildView,
50
    )
13130.1.12 by Curtis Hovey
Sorted imports.
51
from lp.code.interfaces.sourcepackagerecipe import MINIMAL_RECIPE_TEXT
11603.1.5 by Paul Hummer
Made the RecipeParser.NEWEST_VERSION monkeypatch use a contextmanager
52
from lp.code.tests.helpers import recipe_parser_newest_version
13130.1.12 by Curtis Hovey
Sorted imports.
53
from lp.registry.interfaces.person import TeamSubscriptionPolicy
10936.6.2 by Aaron Bentley
Handle over-quota builds
54
from lp.registry.interfaces.pocket import PackagePublishingPocket
12373.2.14 by Tim Penhey
Test the initial series.
55
from lp.registry.interfaces.series import SeriesStatus
11889.4.7 by Tim Penhey
Fix the existing test failures due to new cached properties.
56
from lp.services.propertycache import clear_property_cache
10859.1.5 by Paul Hummer
Fixed tests
57
from lp.soyuz.model.processor import ProcessorFamily
11236.1.2 by Aaron Bentley
Handle PrivateBranchRecipe as a user error in the web UI.
58
from lp.testing import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
59
    ANONYMOUS,
60
    BrowserTestCase,
61
    login,
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
62
    login_person,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
63
    person_logged_in,
12119.1.12 by Tim Penhey
Add canonical url unit test.
64
    TestCaseWithFactory,
12178.2.2 by Tim Penhey
Fix the group test.
65
    time_counter,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
66
    )
11151.3.3 by Abel Deuring
fix tests that failed for proxied distroseries and productseries objects
67
from lp.testing.factory import remove_security_proxy_and_shout_at_engineer
12373.2.15 by Tim Penhey
Move matchers to lp.testing.matchers.
68
from lp.testing.matchers import (
13130.1.12 by Curtis Hovey
Sorted imports.
69
    MatchesPickerText,
12373.2.15 by Tim Penhey
Move matchers to lp.testing.matchers.
70
    MatchesTagText,
71
    )
12177.4.1 by Tim Penhey
Show a message on the main recipe page if the recipe owner can't upload into the daily ppa.
72
from lp.testing.views import create_initialized_view
7675.618.37 by Paul Hummer
Added BrowserTestCase
73
74
12119.1.12 by Tim Penhey
Add canonical url unit test.
75
class TestCanonicalUrlForRecipe(TestCaseWithFactory):
76
77
    layer = DatabaseFunctionalLayer
78
79
    def test_canonical_url(self):
80
        owner = self.factory.makePerson(name='recipe-owner')
81
        recipe = self.factory.makeSourcePackageRecipe(
12119.1.14 by Tim Penhey
Unicode...
82
            owner=owner, name=u'recipe-name')
12119.1.12 by Tim Penhey
Add canonical url unit test.
83
        self.assertEqual(
84
            'http://code.launchpad.dev/~recipe-owner/+recipe/recipe-name',
85
            canonical_url(recipe))
86
12119.1.16 by Tim Penhey
Redirect +build urls into +buildjob.
87
7675.618.37 by Paul Hummer
Added BrowserTestCase
88
class TestCaseForRecipe(BrowserTestCase):
7675.618.36 by Paul Hummer
Added a pagetest^Wunittest
89
    """Create some sample data for recipe tests."""
10498.3.6 by Aaron Bentley
Initial cut of index page.
90
10498.5.11 by Aaron Bentley
Update existing tests for new layout.
91
    def setUp(self):
10498.5.16 by Aaron Bentley
Update docs
92
        """Provide useful defaults."""
7675.618.36 by Paul Hummer
Added a pagetest^Wunittest
93
        super(TestCaseForRecipe, self).setUp()
10498.5.25 by Aaron Bentley
Merged stable into request-build.
94
        self.chef = self.factory.makePerson(
10498.5.12 by Aaron Bentley
Test request page.
95
            displayname='Master Chef', name='chef', password='test')
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
96
        self.user = self.chef
10498.5.12 by Aaron Bentley
Test request page.
97
        self.ppa = self.factory.makeArchive(
10747.1.21 by Aaron Bentley
Fix more failing tests.
98
            displayname='Secret PPA', owner=self.chef, name='ppa')
10498.5.11 by Aaron Bentley
Update existing tests for new layout.
99
        self.squirrel = self.factory.makeDistroSeries(
10999.2.1 by William Grant
Sort the recipe build series vocab by version string.
100
            displayname='Secret Squirrel', name='secret', version='100.04',
10833.1.2 by Paul Hummer
Fixed tests
101
            distribution=self.ppa.distribution)
11151.3.3 by Abel Deuring
fix tests that failed for proxied distroseries and productseries objects
102
        naked_squirrel = remove_security_proxy_and_shout_at_engineer(
103
            self.squirrel)
104
        naked_squirrel.nominatedarchindep = self.squirrel.newArch(
10859.1.5 by Paul Hummer
Fixed tests
105
            'i386', ProcessorFamily.get(1), False, self.chef,
106
            supports_virtualized=True)
10498.5.11 by Aaron Bentley
Update existing tests for new layout.
107
10498.3.16 by Aaron Bentley
Add tests for pending builds.
108
    def makeRecipe(self):
10498.5.16 by Aaron Bentley
Update docs
109
        """Create and return a specific recipe."""
10498.3.13 by Aaron Bentley
Implement index page test.
110
        chocolate = self.factory.makeProduct(name='chocolate')
10498.3.24 by Aaron Bentley
Updates from review.
111
        cake_branch = self.factory.makeProductBranch(
10498.5.12 by Aaron Bentley
Test request page.
112
            owner=self.chef, name='cake', product=chocolate)
10498.3.16 by Aaron Bentley
Add tests for pending builds.
113
        return self.factory.makeSourcePackageRecipe(
10498.5.29 by Aaron Bentley
makeSourcePackageRecipe flushes and takes branches as a normal argument.
114
            owner=self.chef, distroseries=self.squirrel, name=u'cake_recipe',
115
            description=u'This recipe builds a foo for disto bar, with my'
10899.2.7 by Aaron Bentley
Fix test failures.
116
            ' Secret Squirrel changes.', branches=[cake_branch],
117
            daily_build_archive=self.ppa)
10498.3.16 by Aaron Bentley
Add tests for pending builds.
118
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
119
    def checkRelatedBranches(self, related_series_branch_info,
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
120
                             related_package_branch_info, browser_contents):
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
121
        """Check that the browser contents contain the correct branch info."""
122
        login(ANONYMOUS)
123
        soup = BeautifulSoup(browser_contents)
124
125
        # The related branches collapsible section needs to be there.
126
        related_branches = soup.find('fieldset', {'id': 'related-branches'})
127
        self.assertIsNot(related_branches, None)
128
129
        # Check the related package branches.
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
130
        root_url = canonical_url(
131
            getUtility(ILaunchpadRoot), rootsite='code')
132
        root_url = root_url.rstrip('/')
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
133
        branch_table = soup.find(
134
            'table', {'id': 'related-package-branches-listing'})
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
135
        if not related_package_branch_info:
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
136
            self.assertIs(branch_table, None)
137
        else:
138
            rows = branch_table.tbody.findAll('tr')
139
140
            package_branches_info = []
141
            for row in rows:
142
                branch_links = row.findAll('a')
143
                self.assertEqual(2, len(branch_links))
144
                package_branches_info.append(
145
                    '%s%s' % (root_url, branch_links[0]['href']))
146
                package_branches_info.append(branch_links[0].renderContents())
147
                package_branches_info.append(
148
                    '%s%s' % (root_url, branch_links[1]['href']))
149
                package_branches_info.append(branch_links[1].renderContents())
150
            expected_branch_info = []
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
151
            for branch_info in related_package_branch_info:
152
                branch = branch_info[0]
153
                distro_series = branch_info[1]
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
154
                expected_branch_info.append(
155
                    canonical_url(branch, rootsite='code'))
156
                expected_branch_info.append(branch.displayname)
157
                expected_branch_info.append(
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
158
                    canonical_url(distro_series, rootsite='code'))
159
                expected_branch_info.append(distro_series.name)
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
160
            self.assertEqual(package_branches_info, expected_branch_info)
161
162
        # Check the related series branches.
163
        branch_table = soup.find(
164
            'table', {'id': 'related-series-branches-listing'})
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
165
        if not related_series_branch_info:
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
166
            self.assertIs(branch_table, None)
167
        else:
168
            rows = branch_table.tbody.findAll('tr')
169
170
            series_branches_info = []
171
            for row in rows:
172
                branch_links = row.findAll('a')
173
                self.assertEqual(2, len(branch_links))
174
                series_branches_info.append(
175
                    '%s%s' % (root_url, branch_links[0]['href']))
176
                series_branches_info.append(branch_links[0].renderContents())
177
                series_branches_info.append(branch_links[1]['href'])
178
                series_branches_info.append(branch_links[1].renderContents())
179
            expected_branch_info = []
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
180
            for branch_info in related_series_branch_info:
181
                branch = branch_info[0]
182
                product_series = branch_info[1]
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
183
                expected_branch_info.append(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
184
                    canonical_url(branch,
185
                                  rootsite='code',
186
                                  path_only_if_possible=True))
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
187
                expected_branch_info.append(branch.displayname)
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
188
                expected_branch_info.append(
189
                    canonical_url(product_series,
190
                                  path_only_if_possible=True))
191
                expected_branch_info.append(product_series.name)
192
            self.assertEqual(expected_branch_info, series_branches_info)
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
193
7675.618.42 by Paul Hummer
Getting the tests shaped up.
194
10994.1.5 by Aaron Bentley
Convert method to function.
195
def get_message_text(browser, index):
196
    """Return the text of a message, specified by index."""
197
    tags = find_tags_by_class(browser.contents, 'message')[index]
198
    return extract_text(tags)
199
200
12373.2.13 by Tim Penhey
Add a test for the name generation.
201
class TestSourcePackageRecipeAddViewInitalValues(TestCaseWithFactory):
202
203
    layer = DatabaseFunctionalLayer
204
205
    def test_project_branch_initial_name(self):
206
        # When a project branch is used, the initial name is the name of the
207
        # project followed by "-daily"
208
        widget = self.factory.makeProduct(name='widget')
209
        branch = self.factory.makeProductBranch(widget)
210
        with person_logged_in(branch.owner):
211
            view = create_initialized_view(branch, '+new-recipe')
212
        self.assertThat('widget-daily', Equals(view.initial_values['name']))
213
214
    def test_package_branch_initial_name(self):
215
        # When a package branch is used, the initial name is the name of the
216
        # source package followed by "-daily"
217
        branch = self.factory.makePackageBranch(sourcepackagename='widget')
218
        with person_logged_in(branch.owner):
219
            view = create_initialized_view(branch, '+new-recipe')
220
        self.assertThat('widget-daily', Equals(view.initial_values['name']))
221
12599.4.2 by Leonard Richardson
Merge from trunk.
222
    def test_personal_branch_initial_name(self):
223
        # When a personal branch is used, the initial name is the name of the
224
        # branch followed by "-daily". +junk-daily is not valid nor
225
        # helpful.
226
        branch = self.factory.makePersonalBranch(name='widget')
227
        with person_logged_in(branch.owner):
228
            view = create_initialized_view(branch, '+new-recipe')
229
        self.assertThat('widget-daily', Equals(view.initial_values['name']))
230
12373.2.13 by Tim Penhey
Add a test for the name generation.
231
    def test_initial_name_exists(self):
232
        # If the initial name exists, a generator is used to find an unused
233
        # name by appending a numbered suffix on the end.
234
        owner = self.factory.makePerson()
235
        self.factory.makeSourcePackageRecipe(owner=owner, name=u'widget-daily')
236
        widget = self.factory.makeProduct(name='widget')
237
        branch = self.factory.makeProductBranch(widget)
238
        with person_logged_in(owner):
239
            view = create_initialized_view(branch, '+new-recipe')
240
        self.assertThat('widget-daily-1', Equals(view.initial_values['name']))
241
12373.2.14 by Tim Penhey
Test the initial series.
242
    def test_initial_series(self):
243
        # The initial series are those that are current or in development.
244
        archive = self.factory.makeArchive()
245
        experimental = self.factory.makeDistroSeries(
246
            distribution=archive.distribution,
247
            status=SeriesStatus.EXPERIMENTAL)
248
        development = self.factory.makeDistroSeries(
249
            distribution=archive.distribution,
250
            status=SeriesStatus.DEVELOPMENT)
251
        frozen = self.factory.makeDistroSeries(
252
            distribution=archive.distribution,
253
            status=SeriesStatus.FROZEN)
254
        current = self.factory.makeDistroSeries(
255
            distribution=archive.distribution,
256
            status=SeriesStatus.CURRENT)
257
        supported = self.factory.makeDistroSeries(
258
            distribution=archive.distribution,
259
            status=SeriesStatus.SUPPORTED)
260
        obsolete = self.factory.makeDistroSeries(
261
            distribution=archive.distribution,
262
            status=SeriesStatus.OBSOLETE)
263
        future = self.factory.makeDistroSeries(
264
            distribution=archive.distribution,
265
            status=SeriesStatus.FUTURE)
266
        branch = self.factory.makeAnyBranch()
267
        with person_logged_in(archive.owner):
268
            view = create_initialized_view(branch, '+new-recipe')
12547.1.36 by Ian Booth
Test fixes
269
        series = set(view.initial_values['distroseries'])
12373.2.14 by Tim Penhey
Test the initial series.
270
        initial_series = set([development, current])
271
        self.assertEqual(initial_series, series.intersection(initial_series))
272
        other_series = set(
273
            [experimental, frozen, supported, obsolete, future])
274
        self.assertEqual(set(), series.intersection(other_series))
12373.2.13 by Tim Penhey
Add a test for the name generation.
275
276
7675.618.42 by Paul Hummer
Getting the tests shaped up.
277
class TestSourcePackageRecipeAddView(TestCaseForRecipe):
278
279
    layer = DatabaseFunctionalLayer
280
10899.4.1 by Aaron Bentley
Initial UI for source package recipe builds.
281
    def makeBranch(self):
282
        product = self.factory.makeProduct(
283
            name='ratatouille', displayname='Ratatouille')
284
        branch = self.factory.makeBranch(
285
            owner=self.chef, product=product, name='veggies')
286
        self.factory.makeSourcePackage(sourcepackagename='ratatouille')
287
        return branch
288
7675.711.1 by Paul Hummer
Added test for failing code.
289
    def test_create_new_recipe_not_logged_in(self):
290
        product = self.factory.makeProduct(
291
            name='ratatouille', displayname='Ratatouille')
292
        branch = self.factory.makeBranch(
293
            owner=self.chef, product=product, name='veggies')
11570.1.5 by Paul Hummer
Removed the other instance of setupBrowser
294
295
        browser = self.getViewBrowser(branch, no_login=True)
7675.711.1 by Paul Hummer
Added test for failing code.
296
        self.assertRaises(
297
            Unauthorized, browser.getLink('Create packaging recipe').click)
298
7675.618.42 by Paul Hummer
Getting the tests shaped up.
299
    def test_create_new_recipe(self):
10899.4.1 by Aaron Bentley
Initial UI for source package recipe builds.
300
        branch = self.makeBranch()
7675.618.43 by Paul Hummer
Added owner to the add/edit form
301
        # A new recipe can be created from the branch page.
7675.618.42 by Paul Hummer
Getting the tests shaped up.
302
        browser = self.getUserBrowser(canonical_url(branch), user=self.chef)
10891.1.1 by Paul Hummer
Changed the text for the package recipe creation
303
        browser.getLink('Create packaging recipe').click()
7675.618.42 by Paul Hummer
Getting the tests shaped up.
304
305
        browser.getControl(name='field.name').value = 'daily'
306
        browser.getControl('Description').value = 'Make some food!'
7675.622.1 by Paul Hummer
Fixing MOST of the concerns in Tim's review (still need to make LaunchpadEditForm work
307
        browser.getControl('Create Recipe').click()
308
12373.2.10 by Tim Penhey
Fix the Add tests.
309
        content = find_main_content(browser.contents)
12421.3.3 by Tim Penhey
Use extract_text now as the heading is now an editor widget.
310
        self.assertEqual('daily', extract_text(content.h1))
12373.2.10 by Tim Penhey
Fix the Add tests.
311
        self.assertThat(
312
            'Make some food!', MatchesTagText(content, 'edit-description'))
313
        self.assertThat(
314
            'Master Chef', MatchesPickerText(content, 'edit-owner'))
315
        self.assertThat(
316
            'Secret PPA',
317
            MatchesPickerText(content, 'edit-daily_build_archive'))
7675.622.1 by Paul Hummer
Fixing MOST of the concerns in Tim's review (still need to make LaunchpadEditForm work
318
11350.1.1 by Paul Hummer
Added test
319
    def test_create_new_recipe_private_branch(self):
320
        # Recipes can't be created on private branches.
11350.1.4 by Paul Hummer
Made sinzui's suggested changes
321
        with person_logged_in(self.chef):
322
            branch = self.factory.makeBranch(private=True, owner=self.chef)
323
            branch_url = canonical_url(branch)
11350.1.1 by Paul Hummer
Added test
324
325
        browser = self.getUserBrowser(branch_url, user=self.chef)
326
        self.assertRaises(
327
            LinkNotFoundError,
328
            browser.getLink,
329
            'Create packaging recipe')
330
11204.3.4 by Tim Penhey
Split the test as it is testing two things.
331
    def test_create_new_recipe_users_teams_as_owner_options(self):
332
        # Teams that the user is in are options for the recipe owner.
333
        self.factory.makeTeam(
11204.3.2 by Tim Penhey
Use the specified owner when creating a recipe.
334
            name='good-chefs', displayname='Good Chefs', members=[self.chef])
12373.2.10 by Tim Penhey
Fix the Add tests.
335
        browser = self.getViewBrowser(
336
            self.makeBranch(), '+new-recipe', user=self.chef)
11204.3.2 by Tim Penhey
Use the specified owner when creating a recipe.
337
        # The options for the owner include the Good Chefs team.
11869.12.8 by Aaron Bentley
Add tests of suggestion functionality.
338
        options = browser.getControl(name='field.owner.owner').displayOptions
11204.3.2 by Tim Penhey
Use the specified owner when creating a recipe.
339
        self.assertEquals(
13314.13.1 by Ian Booth
Fix implementation - use custom vocab
340
            ['Good Chefs (good-chefs)', 'Master Chef (chef)'],
11204.3.2 by Tim Penhey
Use the specified owner when creating a recipe.
341
            sorted([str(option) for option in options]))
342
11204.3.4 by Tim Penhey
Split the test as it is testing two things.
343
    def test_create_new_recipe_team_owner(self):
344
        # New recipes can be owned by teams that the user is a member of.
345
        team = self.factory.makeTeam(
346
            name='good-chefs', displayname='Good Chefs', members=[self.chef])
12373.2.10 by Tim Penhey
Fix the Add tests.
347
        browser = self.getViewBrowser(
348
            self.makeBranch(), '+new-recipe', user=self.chef)
11204.3.2 by Tim Penhey
Use the specified owner when creating a recipe.
349
        browser.getControl(name='field.name').value = 'daily'
350
        browser.getControl('Description').value = 'Make some food!'
11869.12.8 by Aaron Bentley
Add tests of suggestion functionality.
351
        browser.getControl('Other').click()
352
        browser.getControl(name='field.owner.owner').displayValue = [
353
            'Good Chefs']
11204.3.2 by Tim Penhey
Use the specified owner when creating a recipe.
354
        browser.getControl('Create Recipe').click()
355
11204.3.3 by Tim Penhey
Be explicit about what is being tested.
356
        login(ANONYMOUS)
357
        recipe = team.getRecipe(u'daily')
358
        self.assertEqual(team, recipe.owner)
359
        self.assertEqual('daily', recipe.name)
11204.3.2 by Tim Penhey
Use the specified owner when creating a recipe.
360
11869.12.8 by Aaron Bentley
Add tests of suggestion functionality.
361
    def test_create_new_recipe_suggests_user(self):
362
        """The current user is suggested as a recipe owner, once."""
363
        branch = self.factory.makeBranch(owner=self.chef)
364
        text = self.getMainText(branch, '+new-recipe')
365
        self.assertTextMatchesExpressionIgnoreWhitespace(
366
            r'Owner: Master Chef \(chef\) Other:', text)
367
368
    def test_create_new_recipe_suggests_user_team(self):
369
        """If current user is a member of branch owner, it is suggested."""
370
        team = self.factory.makeTeam(
371
            name='branch-team', displayname='Branch Team',
372
            members=[self.chef])
373
        branch = self.factory.makeBranch(owner=team)
374
        text = self.getMainText(branch, '+new-recipe')
375
        self.assertTextMatchesExpressionIgnoreWhitespace(
376
            r'Owner: Master Chef \(chef\)'
377
            r' Branch Team \(branch-team\) Other:', text)
378
379
    def test_create_new_recipe_ignores_non_user_team(self):
380
        """If current user isn't a member of branch owner, it is ignored."""
381
        team = self.factory.makeTeam(
382
            name='branch-team', displayname='Branch Team')
383
        branch = self.factory.makeBranch(owner=team)
384
        text = self.getMainText(branch, '+new-recipe')
385
        self.assertTextMatchesExpressionIgnoreWhitespace(
386
            r'Owner: Master Chef \(chef\) Other:', text)
387
10979.1.4 by Paul Hummer
Added failing test
388
    def test_create_recipe_forbidden_instruction(self):
10979.1.2 by Paul Hummer
Added failing test
389
        # We don't allow the "run" instruction in our recipes.  Make sure this
390
        # is communicated to the user properly.
391
        product = self.factory.makeProduct(
392
            name='ratatouille', displayname='Ratatouille')
393
        branch = self.factory.makeBranch(
394
            owner=self.chef, product=product, name='veggies')
12373.2.10 by Tim Penhey
Fix the Add tests.
395
        browser = self.getViewBrowser(branch, '+new-recipe', user=self.chef)
10979.1.2 by Paul Hummer
Added failing test
396
        browser.getControl('Description').value = 'Make some food!'
397
        browser.getControl('Recipe text').value = (
398
            browser.getControl('Recipe text').value + 'run cat /etc/passwd')
399
        browser.getControl('Create Recipe').click()
400
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
401
            get_feedback_messages(browser.contents)[1],
10979.1.2 by Paul Hummer
Added failing test
402
            'The bzr-builder instruction "run" is not permitted here.')
403
10994.1.1 by Aaron Bentley
Tread bad branch location as validation problem
404
    def createRecipe(self, recipe_text, branch=None):
405
        if branch is None:
406
            product = self.factory.makeProduct(
407
                name='ratatouille', displayname='Ratatouille')
408
            branch = self.factory.makeBranch(
409
                owner=self.chef, product=product, name='veggies')
12373.2.10 by Tim Penhey
Fix the Add tests.
410
        browser = self.getViewBrowser(branch, '+new-recipe', user=self.chef)
10994.1.1 by Aaron Bentley
Tread bad branch location as validation problem
411
        browser.getControl(name='field.name').value = 'daily'
412
        browser.getControl('Description').value = 'Make some food!'
413
        browser.getControl('Recipe text').value = recipe_text
414
        browser.getControl('Create Recipe').click()
415
        return browser
416
11970.1.1 by Aaron Bentley
Show usage for intruction parse errors.
417
    def test_create_recipe_usage(self):
418
        # The error for a recipe with invalid instruction parameters should
419
        # include instruction usage.
420
        branch = self.factory.makeBranch(name='veggies')
12392.3.1 by Steve Kowalik
Don't return recipe builds that built/are building into a disabled archive,
421
        self.factory.makeBranch(name='packaging')
11970.1.1 by Aaron Bentley
Show usage for intruction parse errors.
422
423
        browser = self.createRecipe(
424
            dedent('''\
425
                # bzr-builder format 0.2 deb-version 0+{revno}
426
                %(branch)s
427
                merge
428
                ''' % {
429
                    'branch': branch.bzr_identity,
430
                }),
431
            branch=branch)
432
        self.assertEqual(
433
            'Error parsing recipe:3:6: '
434
            'End of line while looking for the branch id.\n'
435
            'Usage: merge NAME BRANCH [REVISION]',
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
436
            get_feedback_messages(browser.contents)[1])
7675.618.42 by Paul Hummer
Getting the tests shaped up.
437
10899.4.1 by Aaron Bentley
Initial UI for source package recipe builds.
438
    def test_create_recipe_no_distroseries(self):
439
        browser = self.getViewBrowser(self.makeBranch(), '+new-recipe')
440
        browser.getControl(name='field.name').value = 'daily'
441
        browser.getControl('Description').value = 'Make some food!'
12547.1.36 by Ian Booth
Test fixes
442
        browser.getControl(name='field.distroseries').value = []
10899.4.1 by Aaron Bentley
Initial UI for source package recipe builds.
443
        browser.getControl('Create Recipe').click()
444
        self.assertEqual(
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
445
            'You must specify at least one series for daily builds.',
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
446
            get_feedback_messages(browser.contents)[1])
10899.4.1 by Aaron Bentley
Initial UI for source package recipe builds.
447
10994.1.1 by Aaron Bentley
Tread bad branch location as validation problem
448
    def test_create_recipe_bad_base_branch(self):
449
        # If a user tries to create source package recipe with a bad base
450
        # branch location, they should get an error.
451
        browser = self.createRecipe(MINIMAL_RECIPE_TEXT % 'foo')
452
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
453
            get_feedback_messages(browser.contents)[1],
454
            'foo is not a branch on Launchpad.')
10994.1.1 by Aaron Bentley
Tread bad branch location as validation problem
455
456
    def test_create_recipe_bad_instruction_branch(self):
457
        # If a user tries to create source package recipe with a bad
458
        # instruction branch location, they should get an error.
459
        product = self.factory.makeProduct(
460
            name='ratatouille', displayname='Ratatouille')
461
        branch = self.factory.makeBranch(
462
            owner=self.chef, product=product, name='veggies')
463
        recipe = MINIMAL_RECIPE_TEXT % branch.bzr_identity
464
        recipe += 'nest packaging foo debian'
465
        browser = self.createRecipe(recipe, branch)
466
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
467
            get_feedback_messages(browser.contents)[1],
468
            'foo is not a branch on Launchpad.')
10994.1.1 by Aaron Bentley
Tread bad branch location as validation problem
469
11603.1.1 by Paul Hummer
Added test that fails in the same way as the broken bug
470
    def test_create_recipe_format_too_new(self):
11603.1.4 by Paul Hummer
Fixed lint
471
        # If the recipe's format version is too new, we should notify the
472
        # user.
11603.1.1 by Paul Hummer
Added test that fails in the same way as the broken bug
473
        product = self.factory.makeProduct(
474
            name='ratatouille', displayname='Ratatouille')
475
        branch = self.factory.makeBranch(
476
            owner=self.chef, product=product, name='veggies')
477
11603.1.5 by Paul Hummer
Made the RecipeParser.NEWEST_VERSION monkeypatch use a contextmanager
478
        with recipe_parser_newest_version(145.115):
479
            recipe = dedent(u'''\
11929.8.1 by Tim Penhey
Make the default recipe deb-version look like: {debupstream}-0~{revno}
480
                # bzr-builder format 145.115 deb-version {debupstream}-0~{revno}
11603.1.5 by Paul Hummer
Made the RecipeParser.NEWEST_VERSION monkeypatch use a contextmanager
481
                %s
482
                ''') % branch.bzr_identity
483
            browser = self.createRecipe(recipe, branch)
484
            self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
485
                get_feedback_messages(browser.contents)[1],
11603.1.5 by Paul Hummer
Made the RecipeParser.NEWEST_VERSION monkeypatch use a contextmanager
486
                'The recipe format version specified is not available.')
11603.1.1 by Paul Hummer
Added test that fails in the same way as the broken bug
487
10931.1.1 by Paul Hummer
Added failing test
488
    def test_create_dupe_recipe(self):
489
        # You shouldn't be able to create a duplicate recipe owned by the same
490
        # person with the same name.
491
        recipe = self.factory.makeSourcePackageRecipe(owner=self.chef)
11043.2.3 by Paul Hummer
Fixed browser tests
492
        transaction.commit()
493
        recipe_name = recipe.name
10931.1.1 by Paul Hummer
Added failing test
494
495
        product = self.factory.makeProduct(
496
            name='ratatouille', displayname='Ratatouille')
497
        branch = self.factory.makeBranch(
498
            owner=self.chef, product=product, name='veggies')
499
500
        # A new recipe can be created from the branch page.
501
        browser = self.getUserBrowser(canonical_url(branch), user=self.chef)
502
        browser.getLink('Create packaging recipe').click()
503
11043.2.3 by Paul Hummer
Fixed browser tests
504
        browser.getControl(name='field.name').value = recipe_name
10931.1.1 by Paul Hummer
Added failing test
505
        browser.getControl('Description').value = 'Make some food!'
506
        browser.getControl('Secret Squirrel').click()
507
        browser.getControl('Create Recipe').click()
508
509
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
510
            get_feedback_messages(browser.contents)[1],
10931.1.2 by Paul Hummer
Fixed the test!
511
            'There is already a recipe owned by Master Chef with this name.')
10931.1.1 by Paul Hummer
Added failing test
512
11236.1.2 by Aaron Bentley
Handle PrivateBranchRecipe as a user error in the web UI.
513
    def test_create_recipe_private_branch(self):
514
        # If a user tries to create source package recipe with a private
515
        # base branch, they should get an error.
516
        branch = self.factory.makeAnyBranch(private=True, owner=self.user)
517
        with person_logged_in(self.user):
518
            bzr_identity = branch.bzr_identity
519
        recipe_text = MINIMAL_RECIPE_TEXT % bzr_identity
520
        browser = self.createRecipe(recipe_text)
521
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
522
            get_feedback_messages(browser.contents)[1],
11236.1.2 by Aaron Bentley
Handle PrivateBranchRecipe as a user error in the web UI.
523
            'Recipe may not refer to private branch: %s' % bzr_identity)
524
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
525
    def _test_new_recipe_with_no_related_branches(self, branch):
526
        # The Related Branches section should not appear if there are no
527
        # related branches.
528
        # A new recipe can be created from the branch page.
529
        browser = self.getUserBrowser(
530
            canonical_url(branch, view_name='+new-recipe'), user=self.chef)
531
        # There shouldn't be a related-branches section if there are no
532
        # related branches..
533
        soup = BeautifulSoup(browser.contents)
534
        related_branches = soup.find('fieldset', {'id': 'related-branches'})
535
        self.assertIs(related_branches, None)
536
537
    def test_new_product_branch_with_no_related_branches_recipe(self):
538
        # We can create a new recipe off a product branch.
539
        branch = self.factory.makeBranch()
540
        self._test_new_recipe_with_no_related_branches(branch)
541
542
    def test_new_package_branch_with_no_linked_branches_recipe(self):
543
        # We can create a new recipe off a sourcepackage branch where the
544
        # sourcepackage has no linked branches.
545
        branch = self.factory.makePackageBranch()
546
        self._test_new_recipe_with_no_related_branches(branch)
547
548
    def test_new_recipe_with_package_branches(self):
549
        # The series branches table should not appear if there are none.
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
550
        (branch, related_series_branch_info, related_package_branches) = (
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
551
            self.factory.makeRelatedBranches(with_series_branches=False))
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
552
        browser = self.getUserBrowser(
553
            canonical_url(branch, view_name='+new-recipe'), user=self.chef)
554
        soup = BeautifulSoup(browser.contents)
555
        related_branches = soup.find('fieldset', {'id': 'related-branches'})
556
        self.assertIsNot(related_branches, None)
557
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
558
            'div', {'id': 'related-package-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
559
        self.assertIsNot(related_branches, None)
560
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
561
            'div', {'id': 'related-series-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
562
        self.assertIs(related_branches, None)
563
564
    def test_new_recipe_with_series_branches(self):
565
        # The package branches table should not appear if there are none.
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
566
        (branch, related_series_branch_info, related_package_branches) = (
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
567
            self.factory.makeRelatedBranches(with_package_branches=False))
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
568
        browser = self.getUserBrowser(
569
            canonical_url(branch, view_name='+new-recipe'), user=self.chef)
570
        soup = BeautifulSoup(browser.contents)
571
        related_branches = soup.find('fieldset', {'id': 'related-branches'})
572
        self.assertIsNot(related_branches, None)
573
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
574
            'div', {'id': 'related-series-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
575
        self.assertIsNot(related_branches, None)
576
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
577
            'div', {'id': 'related-package-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
578
        self.assertIs(related_branches, None)
579
580
    def test_new_product_branch_recipe_with_related_branches(self):
581
        # The related branches should be rendered correctly on the page.
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
582
        (branch, related_series_branch_info,
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
583
            related_package_branch_info) = self.factory.makeRelatedBranches()
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
584
        browser = self.getUserBrowser(
585
            canonical_url(branch, view_name='+new-recipe'), user=self.chef)
586
        self.checkRelatedBranches(
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
587
            related_series_branch_info, related_package_branch_info,
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
588
            browser.contents)
589
590
    def test_new_sourcepackage_branch_recipe_with_related_branches(self):
591
        # The related branches should be rendered correctly on the page.
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
592
        reference_branch= self.factory.makePackageBranch()
593
        (branch, ignore, related_package_branch_info) = (
594
                self.factory.makeRelatedBranches(reference_branch))
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
595
        browser = self.getUserBrowser(
596
            canonical_url(branch, view_name='+new-recipe'), user=self.chef)
597
        self.checkRelatedBranches(
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
598
                set(), related_package_branch_info, browser.contents)
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
599
11929.11.18 by Tim Penhey
A few tests.
600
    def test_ppa_selector_not_shown_if_user_has_no_ppas(self):
601
        # If the user creating a recipe has no existing PPAs, the selector
602
        # isn't shown, but the field to enter a new PPA name is.
603
        self.user = self.factory.makePerson(password='test')
604
        branch = self.factory.makeAnyBranch()
605
        with person_logged_in(self.user):
606
            content = self.getMainContent(branch, '+new-recipe')
11929.11.27 by Tim Penhey
Test tweaks for the ppa name validation.
607
        ppa_name = content.find(attrs={'id': 'field.ppa_name'})
608
        self.assertEqual('input', ppa_name.name)
609
        self.assertEqual('text', ppa_name['type'])
610
        # The new ppa name field has an initial value.
611
        self.assertEqual('ppa', ppa_name['value'])
11929.11.18 by Tim Penhey
A few tests.
612
        ppa_chooser = content.find(attrs={'id': 'field.daily_build_archive'})
613
        self.assertIs(None, ppa_chooser)
11929.11.19 by Tim Penhey
A few more options.
614
        # There is a hidden option to say create a new ppa.
615
        ppa_options = content.find(attrs={'name': 'field.use_ppa'})
616
        self.assertEqual('input', ppa_options.name)
617
        self.assertEqual('hidden', ppa_options['type'])
618
        self.assertEqual('create-new', ppa_options['value'])
11929.11.18 by Tim Penhey
A few tests.
619
620
    def test_ppa_selector_shown_if_user_has_ppas(self):
621
        # If the user creating a recipe has existing PPAs, the selector is
622
        # shown, along with radio buttons to decide whether to use an existing
623
        # ppa or to create a new one.
624
        branch = self.factory.makeAnyBranch()
625
        with person_logged_in(self.user):
626
            content = self.getMainContent(branch, '+new-recipe')
11929.11.27 by Tim Penhey
Test tweaks for the ppa name validation.
627
        ppa_name = content.find(attrs={'id': 'field.ppa_name'})
628
        self.assertEqual('input', ppa_name.name)
629
        self.assertEqual('text', ppa_name['type'])
630
        # The new ppa name field has no initial value.
631
        self.assertEqual('', ppa_name['value'])
11929.11.18 by Tim Penhey
A few tests.
632
        ppa_chooser = content.find(attrs={'id': 'field.daily_build_archive'})
633
        self.assertEqual('select', ppa_chooser.name)
11929.11.19 by Tim Penhey
A few more options.
634
        ppa_options = list(
635
            get_radio_button_text_for_field(content, 'use_ppa'))
636
        self.assertEqual(
637
            ['(*) Use an existing PPA',
638
             '( ) Create a new PPA for this recipe'''],
639
            ppa_options)
11929.11.18 by Tim Penhey
A few tests.
640
11929.11.22 by Tim Penhey
Test to show new PPA created.
641
    def test_create_new_ppa(self):
642
        # If the user doesn't have any PPAs, a new once can be created.
643
        self.user = self.factory.makePerson(name='eric', password='test')
644
        branch = self.factory.makeAnyBranch()
645
646
        # A new recipe can be created from the branch page.
647
        browser = self.getUserBrowser(canonical_url(branch), user=self.user)
648
        browser.getLink('Create packaging recipe').click()
649
650
        browser.getControl(name='field.name').value = 'name'
651
        browser.getControl('Description').value = 'Make some food!'
652
        browser.getControl('Secret Squirrel').click()
653
        browser.getControl('Create Recipe').click()
654
655
        # A new recipe is created in a new PPA.
656
        self.assertTrue(browser.url.endswith('/~eric/+recipe/name'))
657
        # Since no PPA name was entered, the default name (ppa) was used.
658
        login(ANONYMOUS)
659
        new_ppa = self.user.getPPAByName('ppa')
660
        self.assertIsNot(None, new_ppa)
661
11929.11.23 by Tim Penhey
More tests...
662
    def test_create_new_ppa_duplicate(self):
663
        # If a new PPA is being created, and the user already has a ppa of the
11929.11.27 by Tim Penhey
Test tweaks for the ppa name validation.
664
        # name specifed an error is shown.
11929.11.23 by Tim Penhey
More tests...
665
        self.user = self.factory.makePerson(name='eric', password='test')
666
        # Make a PPA called 'ppa' using the default.
11929.11.27 by Tim Penhey
Test tweaks for the ppa name validation.
667
        self.user.createPPA(name='foo')
11929.11.23 by Tim Penhey
More tests...
668
        branch = self.factory.makeAnyBranch()
669
670
        # A new recipe can be created from the branch page.
671
        browser = self.getUserBrowser(canonical_url(branch), user=self.user)
672
        browser.getLink('Create packaging recipe').click()
673
        browser.getControl(name='field.name').value = 'name'
674
        browser.getControl('Description').value = 'Make some food!'
675
        browser.getControl('Secret Squirrel').click()
676
        browser.getControl('Create a new PPA').click()
11929.11.27 by Tim Penhey
Test tweaks for the ppa name validation.
677
        browser.getControl(name='field.ppa_name').value = 'foo'
678
        browser.getControl('Create Recipe').click()
679
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
680
            get_feedback_messages(browser.contents)[1],
11929.11.27 by Tim Penhey
Test tweaks for the ppa name validation.
681
            "You already have a PPA named 'foo'.")
682
683
    def test_create_new_ppa_missing_name(self):
684
        # If a new PPA is being created, and the user has not specified a
685
        # name, an error is shown.
686
        self.user = self.factory.makePerson(name='eric', password='test')
687
        branch = self.factory.makeAnyBranch()
688
689
        # A new recipe can be created from the branch page.
690
        browser = self.getUserBrowser(canonical_url(branch), user=self.user)
691
        browser.getLink('Create packaging recipe').click()
692
        browser.getControl(name='field.name').value = 'name'
693
        browser.getControl('Description').value = 'Make some food!'
694
        browser.getControl('Secret Squirrel').click()
695
        browser.getControl(name='field.ppa_name').value = ''
696
        browser.getControl('Create Recipe').click()
697
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
698
            get_feedback_messages(browser.contents)[1],
11929.11.27 by Tim Penhey
Test tweaks for the ppa name validation.
699
            "You need to specify a name for the PPA.")
11929.11.23 by Tim Penhey
More tests...
700
701
    def test_create_new_ppa_owned_by_recipe_owner(self):
702
        # The new PPA that is created is owned by the recipe owner.
703
        self.user = self.factory.makePerson(name='eric', password='test')
704
        team = self.factory.makeTeam(
705
            name='vikings', members=[self.user],
706
            subscription_policy=TeamSubscriptionPolicy.MODERATED)
707
        branch = self.factory.makeAnyBranch(owner=team)
708
709
        # A new recipe can be created from the branch page.
710
        browser = self.getUserBrowser(canonical_url(branch), user=self.user)
711
        browser.getLink('Create packaging recipe').click()
712
713
        browser.getControl(name='field.name').value = 'name'
714
        browser.getControl('Description').value = 'Make some food!'
715
        browser.getControl(name='field.owner').value = ['vikings']
716
        browser.getControl('Secret Squirrel').click()
717
        browser.getControl('Create Recipe').click()
718
719
        # A new recipe is created in a new PPA.
720
        self.assertTrue(browser.url.endswith('/~vikings/+recipe/name'))
721
        # Since no PPA name was entered, the default name (ppa) was used.
722
        login(ANONYMOUS)
723
        new_ppa = team.getPPAByName('ppa')
724
        self.assertIsNot(None, new_ppa)
725
7675.618.42 by Paul Hummer
Getting the tests shaped up.
726
727
class TestSourcePackageRecipeEditView(TestCaseForRecipe):
728
    """Test the editing behaviour of a source package recipe."""
729
730
    layer = DatabaseFunctionalLayer
731
7675.618.43 by Paul Hummer
Added owner to the add/edit form
732
    def test_edit_recipe(self):
7675.618.45 by Paul Hummer
Fixed some lint
733
        self.factory.makeDistroSeries(
10833.1.2 by Paul Hummer
Fixed tests
734
            displayname='Mumbly Midget', name='mumbly',
735
            distribution=self.ppa.distribution)
7675.618.42 by Paul Hummer
Getting the tests shaped up.
736
        product = self.factory.makeProduct(
737
            name='ratatouille', displayname='Ratatouille')
738
        veggie_branch = self.factory.makeBranch(
739
            owner=self.chef, product=product, name='veggies')
740
        meat_branch = self.factory.makeBranch(
741
            owner=self.chef, product=product, name='meat')
742
        recipe = self.factory.makeSourcePackageRecipe(
743
            owner=self.chef, registrant=self.chef,
744
            name=u'things', description=u'This is a recipe',
10899.4.1 by Aaron Bentley
Initial UI for source package recipe builds.
745
            distroseries=self.squirrel, branches=[veggie_branch],
746
            daily_build_archive=self.ppa)
747
        self.factory.makeArchive(
748
            distribution=self.ppa.distribution, name='ppa2',
749
            displayname="PPA 2", owner=self.chef)
7675.618.42 by Paul Hummer
Getting the tests shaped up.
750
751
        meat_path = meat_branch.bzr_identity
752
753
        browser = self.getUserBrowser(canonical_url(recipe), user=self.chef)
754
        browser.getLink('Edit recipe').click()
755
        browser.getControl(name='field.name').value = 'fings'
756
        browser.getControl('Description').value = 'This is stuff'
757
        browser.getControl('Recipe text').value = (
758
            MINIMAL_RECIPE_TEXT % meat_path)
759
        browser.getControl('Secret Squirrel').click()
760
        browser.getControl('Mumbly Midget').click()
10899.4.1 by Aaron Bentley
Initial UI for source package recipe builds.
761
        browser.getControl('PPA 2').click()
7675.622.2 by Paul Hummer
Fixed the recipe edit view.
762
        browser.getControl('Update Recipe').click()
7675.618.42 by Paul Hummer
Getting the tests shaped up.
763
12373.2.12 by Tim Penhey
More tests.
764
        content = find_main_content(browser.contents)
765
        self.assertThat(
766
            'This is stuff', MatchesTagText(content, 'edit-description'))
767
        self.assertThat(
768
            '# bzr-builder format 0.3 deb-version {debupstream}-0~{revno}\n'
769
            'lp://dev/~chef/ratatouille/meat',
770
            MatchesTagText(content, 'edit-recipe_text'))
771
        self.assertThat(
12547.1.36 by Ian Booth
Test fixes
772
            'Distribution series: Edit Mumbly Midget',
773
            MatchesTagText(content, 'distroseries'))
12373.2.12 by Tim Penhey
More tests.
774
        self.assertThat(
775
            'PPA 2', MatchesPickerText(content, 'edit-daily_build_archive'))
7675.622.1 by Paul Hummer
Fixing MOST of the concerns in Tim's review (still need to make LaunchpadEditForm work
776
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
777
    def test_edit_recipe_sets_date_last_modified(self):
778
        """Editing a recipe sets the date_last_modified property."""
779
        date_created = datetime(2000, 1, 1, 12, tzinfo=UTC)
780
        recipe = self.factory.makeSourcePackageRecipe(
12607.5.2 by Ian Booth
Code review fixes
781
            owner=self.chef, date_created=date_created)
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
782
783
        login_person(self.chef)
784
        view = SourcePackageRecipeEditView(recipe, LaunchpadTestRequest())
785
        view.initialize()
786
        view.request_action.success({
787
            'name': u'fings',
788
            'recipe_text': recipe.recipe_text,
12547.1.37 by Ian Booth
Merge from trunk
789
            'distroseries': recipe.distroseries})
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
790
        self.assertSqlAttributeEqualsDate(
791
            recipe, 'date_last_modified', UTC_NOW)
792
11814.1.1 by Paul Hummer
Added test
793
    def test_admin_edit(self):
794
        self.factory.makeDistroSeries(
795
            displayname='Mumbly Midget', name='mumbly',
796
            distribution=self.ppa.distribution)
797
        product = self.factory.makeProduct(
798
            name='ratatouille', displayname='Ratatouille')
799
        veggie_branch = self.factory.makeBranch(
800
            owner=self.chef, product=product, name='veggies')
801
        meat_branch = self.factory.makeBranch(
802
            owner=self.chef, product=product, name='meat')
803
        recipe = self.factory.makeSourcePackageRecipe(
804
            owner=self.chef, registrant=self.chef,
805
            name=u'things', description=u'This is a recipe',
806
            distroseries=self.squirrel, branches=[veggie_branch],
807
            daily_build_archive=self.ppa)
808
809
        meat_path = meat_branch.bzr_identity
810
        expert = getUtility(ILaunchpadCelebrities).admin.teamowner
811
812
        browser = self.getUserBrowser(canonical_url(recipe), user=expert)
813
        browser.getLink('Edit recipe').click()
814
815
        # There shouldn't be a daily build archive property.
816
        self.assertRaises(
817
            LookupError,
818
            browser.getControl,
819
            name='field.daily_build_archive')
820
821
        browser.getControl(name='field.name').value = 'fings'
822
        browser.getControl('Description').value = 'This is stuff'
823
        browser.getControl('Recipe text').value = (
824
            MINIMAL_RECIPE_TEXT % meat_path)
825
        browser.getControl('Secret Squirrel').click()
826
        browser.getControl('Mumbly Midget').click()
827
        browser.getControl('Update Recipe').click()
828
12373.2.12 by Tim Penhey
More tests.
829
        content = find_main_content(browser.contents)
12421.3.3 by Tim Penhey
Use extract_text now as the heading is now an editor widget.
830
        self.assertEqual('fings', extract_text(content.h1))
12373.2.12 by Tim Penhey
More tests.
831
        self.assertThat(
832
            'This is stuff', MatchesTagText(content, 'edit-description'))
833
        self.assertThat(
834
            '# bzr-builder format 0.3 deb-version {debupstream}-0~{revno}\n'
835
            'lp://dev/~chef/ratatouille/meat',
836
            MatchesTagText(content, 'edit-recipe_text'))
837
        self.assertThat(
12547.1.36 by Ian Booth
Test fixes
838
            'Distribution series: Edit Mumbly Midget',
839
            MatchesTagText(content, 'distroseries'))
11814.1.1 by Paul Hummer
Added test
840
10979.1.4 by Paul Hummer
Added failing test
841
    def test_edit_recipe_forbidden_instruction(self):
842
        self.factory.makeDistroSeries(
843
            displayname='Mumbly Midget', name='mumbly',
844
            distribution=self.ppa.distribution)
845
        product = self.factory.makeProduct(
846
            name='ratatouille', displayname='Ratatouille')
847
        veggie_branch = self.factory.makeBranch(
848
            owner=self.chef, product=product, name='veggies')
849
        recipe = self.factory.makeSourcePackageRecipe(
850
            owner=self.chef, registrant=self.chef,
851
            name=u'things', description=u'This is a recipe',
852
            distroseries=self.squirrel, branches=[veggie_branch])
853
854
        browser = self.getUserBrowser(canonical_url(recipe), user=self.chef)
855
        browser.getLink('Edit recipe').click()
856
        browser.getControl('Recipe text').value = (
857
            browser.getControl('Recipe text').value + 'run cat /etc/passwd')
858
        browser.getControl('Update Recipe').click()
859
860
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
861
            get_feedback_messages(browser.contents)[1],
10979.1.4 by Paul Hummer
Added failing test
862
            'The bzr-builder instruction "run" is not permitted here.')
863
11603.1.7 by Paul Hummer
Added test
864
    def test_edit_recipe_format_too_new(self):
865
        # If the recipe's format version is too new, we should notify the
866
        # user.
867
        self.factory.makeDistroSeries(
868
            displayname='Mumbly Midget', name='mumbly',
869
            distribution=self.ppa.distribution)
870
        product = self.factory.makeProduct(
871
            name='ratatouille', displayname='Ratatouille')
872
        veggie_branch = self.factory.makeBranch(
873
            owner=self.chef, product=product, name='veggies')
874
        recipe = self.factory.makeSourcePackageRecipe(
875
            owner=self.chef, registrant=self.chef,
876
            name=u'things', description=u'This is a recipe',
877
            distroseries=self.squirrel, branches=[veggie_branch])
878
879
        new_recipe_text = dedent(u'''\
11929.8.1 by Tim Penhey
Make the default recipe deb-version look like: {debupstream}-0~{revno}
880
            # bzr-builder format 145.115 deb-version {debupstream}-0~{revno}
11603.1.7 by Paul Hummer
Added test
881
            %s
882
            ''') % recipe.base_branch.bzr_identity
883
884
        with recipe_parser_newest_version(145.115):
885
            browser = self.getViewBrowser(recipe)
886
            browser.getLink('Edit recipe').click()
887
            browser.getControl('Recipe text').value = new_recipe_text
888
            browser.getControl('Update Recipe').click()
889
890
            self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
891
                get_feedback_messages(browser.contents)[1],
11603.1.7 by Paul Hummer
Added test
892
                'The recipe format version specified is not available.')
893
7675.711.11 by Paul Hummer
Added test for making sure recipes are editing and checked correctly
894
    def test_edit_recipe_already_exists(self):
895
        self.factory.makeDistroSeries(
896
            displayname='Mumbly Midget', name='mumbly',
897
            distribution=self.ppa.distribution)
898
        product = self.factory.makeProduct(
899
            name='ratatouille', displayname='Ratatouille')
900
        veggie_branch = self.factory.makeBranch(
901
            owner=self.chef, product=product, name='veggies')
902
        meat_branch = self.factory.makeBranch(
903
            owner=self.chef, product=product, name='meat')
904
        recipe = self.factory.makeSourcePackageRecipe(
905
            owner=self.chef, registrant=self.chef,
906
            name=u'things', description=u'This is a recipe',
907
            distroseries=self.squirrel, branches=[veggie_branch])
10979.1.11 by Paul Hummer
Fixed the broken tests
908
        self.factory.makeSourcePackageRecipe(
909
            owner=self.chef, registrant=self.chef,
910
            name=u'fings', description=u'This is a recipe',
911
            distroseries=self.squirrel, branches=[veggie_branch])
7675.711.11 by Paul Hummer
Added test for making sure recipes are editing and checked correctly
912
913
        meat_path = meat_branch.bzr_identity
914
915
        browser = self.getUserBrowser(canonical_url(recipe), user=self.chef)
916
        browser.getLink('Edit recipe').click()
917
        browser.getControl(name='field.name').value = 'fings'
918
        browser.getControl('Description').value = 'This is stuff'
919
        browser.getControl('Recipe text').value = (
920
            MINIMAL_RECIPE_TEXT % meat_path)
921
        browser.getControl('Secret Squirrel').click()
922
        browser.getControl('Mumbly Midget').click()
923
        browser.getControl('Update Recipe').click()
924
925
        self.assertEqual(
926
            extract_text(find_tags_by_class(browser.contents, 'message')[1]),
927
            'There is already a recipe owned by Master Chef with this name.')
928
11236.1.2 by Aaron Bentley
Handle PrivateBranchRecipe as a user error in the web UI.
929
    def test_edit_recipe_private_branch(self):
930
        # If a user tries to set source package recipe to use a private
931
        # branch, they should get an error.
932
        recipe = self.factory.makeSourcePackageRecipe(owner=self.user)
933
        branch = self.factory.makeAnyBranch(private=True, owner=self.user)
934
        with person_logged_in(self.user):
935
            bzr_identity = branch.bzr_identity
936
        recipe_text = MINIMAL_RECIPE_TEXT % bzr_identity
937
        browser = self.getViewBrowser(recipe, '+edit')
938
        browser.getControl('Recipe text').value = recipe_text
939
        browser.getControl('Update Recipe').click()
940
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
941
            get_feedback_messages(browser.contents)[1],
11236.1.2 by Aaron Bentley
Handle PrivateBranchRecipe as a user error in the web UI.
942
            'Recipe may not refer to private branch: %s' % bzr_identity)
943
12335.5.1 by Steve Kowalik
* Refactor the error handling for creating and updating a recipe into
944
    def test_edit_recipe_no_branch(self):
945
        # If a user tries to set a source package recipe to use a branch
946
        # that isn't registred, they will get an error.
947
        recipe = self.factory.makeSourcePackageRecipe(owner=self.user)
948
        no_branch_recipe_text = recipe.recipe_text[:-4]
949
        expected_name = recipe.base_branch.unique_name[:-3]
950
        browser = self.getViewBrowser(recipe, '+edit')
951
        browser.getControl('Recipe text').value = no_branch_recipe_text
952
        browser.getControl('Update Recipe').click()
953
        self.assertEqual(
12790.3.2 by Tim Penhey
Fix the tests that assumed that the recipe beta message was there.
954
            get_feedback_messages(browser.contents)[1],
12335.5.1 by Steve Kowalik
* Refactor the error handling for creating and updating a recipe into
955
            'lp://dev/%s is not a branch on Launchpad.' % expected_name)
956
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
957
    def _test_edit_recipe_with_no_related_branches(self, recipe):
958
        # The Related Branches section should not appear if there are no
959
        # related branches.
960
        browser = self.getUserBrowser(canonical_url(recipe), user=self.chef)
961
        browser.getLink('Edit recipe').click()
962
        # There shouldn't be a related-branches section if there are no
963
        # related branches.
964
        soup = BeautifulSoup(browser.contents)
965
        related_branches = soup.find('fieldset', {'id': 'related-branches'})
966
        self.assertIs(related_branches, None)
967
968
    def test_edit_product_branch_with_no_related_branches_recipe(self):
969
        # The Related Branches section should not appear if there are no
970
        # related branches.
971
        base_branch = self.factory.makeBranch()
972
        recipe = self.factory.makeSourcePackageRecipe(
973
                owner=self.chef, branches=[base_branch])
974
        self._test_edit_recipe_with_no_related_branches(recipe)
975
976
    def test_edit_sourcepackage_branch_with_no_related_branches_recipe(self):
977
        # The Related Branches section should not appear if there are no
978
        # related branches.
979
        base_branch = self.factory.makePackageBranch()
980
        recipe = self.factory.makeSourcePackageRecipe(
981
                owner=self.chef, branches=[base_branch])
982
        self._test_edit_recipe_with_no_related_branches(recipe)
983
984
    def test_edit_recipe_with_package_branches(self):
985
        # The series branches table should not appear if there are none.
986
        with person_logged_in(self.chef):
987
            recipe = self.factory.makeSourcePackageRecipe(owner=self.chef)
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
988
            self.factory.makeRelatedBranches(
989
                    reference_branch=recipe.base_branch,
990
                    with_series_branches=False)
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
991
        browser = self.getUserBrowser(canonical_url(recipe), user=self.chef)
992
        browser.getLink('Edit recipe').click()
993
        soup = BeautifulSoup(browser.contents)
994
        related_branches = soup.find('fieldset', {'id': 'related-branches'})
995
        self.assertIsNot(related_branches, None)
996
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
997
            'div', {'id': 'related-package-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
998
        self.assertIsNot(related_branches, None)
999
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
1000
            'div', {'id': 'related-series-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1001
        self.assertIs(related_branches, None)
1002
1003
    def test_edit_recipe_with_series_branches(self):
1004
        # The package branches table should not appear if there are none.
1005
        with person_logged_in(self.chef):
1006
            recipe = self.factory.makeSourcePackageRecipe(owner=self.chef)
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
1007
            self.factory.makeRelatedBranches(
1008
                    reference_branch=recipe.base_branch,
1009
                    with_package_branches=False)
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1010
        browser = self.getUserBrowser(canonical_url(recipe), user=self.chef)
1011
        browser.getLink('Edit recipe').click()
1012
        soup = BeautifulSoup(browser.contents)
1013
        related_branches = soup.find('fieldset', {'id': 'related-branches'})
1014
        self.assertIsNot(related_branches, None)
1015
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
1016
            'div', {'id': 'related-series-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1017
        self.assertIsNot(related_branches, None)
1018
        related_branches = soup.find(
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
1019
            'div', {'id': 'related-package-branches'})
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1020
        self.assertIs(related_branches, None)
1021
1022
    def test_edit_product_branch_recipe_with_related_branches(self):
1023
        # The related branches should be rendered correctly on the page.
1024
        with person_logged_in(self.chef):
1025
            recipe = self.factory.makeSourcePackageRecipe(owner=self.chef)
11994.2.19 by Ian Booth
Make ui pretty, keep private branches hidden, display series instead of owner, new tests
1026
            (branch, related_series_branch_info,
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
1027
                related_package_branch_info) = (
1028
                    self.factory.makeRelatedBranches(
1029
                    reference_branch=recipe.base_branch))
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1030
        browser = self.getUserBrowser(
1031
            canonical_url(recipe, view_name='+edit'), user=self.chef)
1032
        self.checkRelatedBranches(
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
1033
            related_series_branch_info, related_package_branch_info,
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1034
            browser.contents)
1035
1036
    def test_edit_sourcepackage_branch_recipe_with_related_branches(self):
1037
        # The related branches should be rendered correctly on the page.
1038
        with person_logged_in(self.chef):
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
1039
            reference_branch= self.factory.makePackageBranch()
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1040
            recipe = self.factory.makeSourcePackageRecipe(
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
1041
                    owner=self.chef, branches=[reference_branch])
1042
            (branch, ignore, related_package_branch_info) = (
1043
                    self.factory.makeRelatedBranches(reference_branch))
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1044
            browser = self.getUserBrowser(
1045
                canonical_url(recipe, view_name='+edit'), user=self.chef)
1046
            self.checkRelatedBranches(
11994.2.21 by Ian Booth
Refactor related branches methods to IBranchTarget and show distro series instead of source package for related package branches
1047
                    set(), related_package_branch_info, browser.contents)
11994.2.16 by Ian Booth
Add new tests and code to allow for branchesrelated to source packages as well as products
1048
7675.711.8 by Paul Hummer
Added test to reproduce the bug
1049
7675.618.42 by Paul Hummer
Getting the tests shaped up.
1050
class TestSourcePackageRecipeView(TestCaseForRecipe):
1051
11889.4.8 by Tim Penhey
Show the buildlog if it is there.
1052
    layer = LaunchpadFunctionalLayer
7675.618.42 by Paul Hummer
Getting the tests shaped up.
1053
10498.3.16 by Aaron Bentley
Add tests for pending builds.
1054
    def test_index(self):
1055
        recipe = self.makeRecipe()
10498.3.14 by Aaron Bentley
Ensure build status is correctly displayed.
1056
        build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
10498.5.11 by Aaron Bentley
Update existing tests for new layout.
1057
            recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1058
        build.status = BuildStatus.FULLYBUILT
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1059
        build.date_started = datetime(2010, 03, 16, tzinfo=UTC)
1060
        build.date_finished = datetime(2010, 03, 16, tzinfo=UTC)
7675.618.58 by Paul Hummer
Merge from devel, resolve conflicts (and fix tests)
1061
1062
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1063
            Master Chef Recipes cake_recipe
11049.5.5 by Paul Hummer
Fixed the tests
1064
            .*
10498.3.13 by Aaron Bentley
Implement index page test.
1065
            Description
10498.3.15 by Aaron Bentley
Improve date display.
1066
            This recipe .*changes.
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1067
10498.3.25 by Aaron Bentley
Updates from review
1068
            Recipe information
12344.2.16 by Tim Penhey
Tweak the tests. They should really be rewritten, but not now.
1069
            Build schedule: Tag help Built on request
12221.10.1 by Tim Penhey
Add Edit bits.
1070
            Owner: Master Chef Edit
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1071
            Base branch: lp://dev/~chef/chocolate/cake
11929.8.2 by Tim Penhey
Update more tests of the deb version.
1072
            Debian version: {debupstream}-0~{revno}
12221.9.34 by Tim Penhey
Fix the tests.
1073
            Daily build archive: Secret PPA Edit
12547.1.34 by Ian Booth
Text fixes
1074
            Distribution series: Edit Secret Squirrel
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1075
11889.1.2 by Tim Penhey
Test fix.
1076
            Latest builds
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1077
            Status When complete Distribution series Archive
11889.4.9 by Tim Penhey
Make it a separate test.
1078
            Successful build on 2010-03-16 Secret Squirrel Secret PPA
1079
            Request build\(s\)
1080
1081
            Recipe contents
7675.984.13 by Aaron Bentley
Merged nest-part-model into allow-0.3-2
1082
            # bzr-builder format 0.3 deb-version {debupstream}-0~{revno}
11889.4.9 by Tim Penhey
Make it a separate test.
1083
            lp://dev/~chef/chocolate/cake""", self.getMainText(recipe))
1084
1085
    def test_index_success_with_buildlog(self):
1086
        # The buildlog is shown if it is there.
1087
        recipe = self.makeRecipe()
1088
        build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
1089
            recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
1090
        build.status = BuildStatus.FULLYBUILT
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1091
        build.date_started = datetime(2010, 03, 16, tzinfo=UTC)
1092
        build.date_finished = datetime(2010, 03, 16, tzinfo=UTC)
11889.4.9 by Tim Penhey
Make it a separate test.
1093
        build.log = self.factory.makeLibraryFileAlias()
1094
1095
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
1096
            Latest builds
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1097
            Status .* Archive
11889.4.10 by Tim Penhey
Added pending binary.
1098
            Successful build on 2010-03-16 buildlog \(.*\) Secret Squirrel Secret PPA
1099
            Request build\(s\)""", self.getMainText(recipe))
1100
1101
    def test_index_success_with_binary_builds(self):
1102
        # Binary builds are shown after the recipe builds if there are any.
1103
        recipe = self.makeRecipe()
1104
        build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
1105
            recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
1106
        build.status = BuildStatus.FULLYBUILT
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1107
        build.date_started = datetime(2010, 03, 16, tzinfo=UTC)
1108
        build.date_finished = datetime(2010, 03, 16, tzinfo=UTC)
11889.4.10 by Tim Penhey
Added pending binary.
1109
        build.log = self.factory.makeLibraryFileAlias()
1110
        package_name = self.factory.getOrMakeSourcePackageName('chocolate')
1111
        source_package_release = self.factory.makeSourcePackageRelease(
12156.9.19 by Steve Kowalik
Also have the SourcePackageRecipe tests create SPPHs.
1112
            archive=self.ppa, sourcepackagename=package_name,
1113
            distroseries=self.squirrel, source_package_recipe_build=build,
1114
            version='0+r42')
12392.3.1 by Steve Kowalik
Don't return recipe builds that built/are building into a disabled archive,
1115
        self.factory.makeSourcePackagePublishingHistory(
12156.9.19 by Steve Kowalik
Also have the SourcePackageRecipe tests create SPPHs.
1116
            sourcepackagerelease=source_package_release, archive=self.ppa,
1117
            distroseries=self.squirrel)
11889.4.10 by Tim Penhey
Added pending binary.
1118
        builder = self.factory.makeBuilder()
1119
        binary_build = self.factory.makeBinaryPackageBuild(
1120
            source_package_release=source_package_release,
1121
            distroarchseries=self.squirrel.nominatedarchindep,
1122
            processor=builder.processor)
1123
        binary_build.queueBuild()
1124
1125
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
1126
            Latest builds
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1127
            Status .* Archive
11889.4.10 by Tim Penhey
Added pending binary.
1128
            Successful build on 2010-03-16 buildlog \(.*\) Secret Squirrel Secret PPA
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1129
              chocolate - 0\+r42 in .* \(estimated\) i386
11889.4.9 by Tim Penhey
Make it a separate test.
1130
            Request build\(s\)""", self.getMainText(recipe))
10744.2.1 by Aaron Bentley
Explain why there are no builds shown.
1131
11889.4.11 by Tim Penhey
And a test for a completed binary build.
1132
    def test_index_success_with_completed_binary_build(self):
1133
        # Binary builds show their buildlog too.
1134
        recipe = self.makeRecipe()
1135
        build = removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
1136
            recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
1137
        build.status = BuildStatus.FULLYBUILT
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1138
        build.date_started = datetime(2010, 03, 16, tzinfo=UTC)
1139
        build.date_finished = datetime(2010, 03, 16, tzinfo=UTC)
11889.4.11 by Tim Penhey
And a test for a completed binary build.
1140
        build.log = self.factory.makeLibraryFileAlias()
1141
        package_name = self.factory.getOrMakeSourcePackageName('chocolate')
1142
        source_package_release = self.factory.makeSourcePackageRelease(
12156.9.19 by Steve Kowalik
Also have the SourcePackageRecipe tests create SPPHs.
1143
            archive=self.ppa, sourcepackagename=package_name,
1144
            distroseries=self.squirrel, source_package_recipe_build=build,
1145
            version='0+r42')
12392.3.1 by Steve Kowalik
Don't return recipe builds that built/are building into a disabled archive,
1146
        self.factory.makeSourcePackagePublishingHistory(
12156.9.19 by Steve Kowalik
Also have the SourcePackageRecipe tests create SPPHs.
1147
            sourcepackagerelease=source_package_release, archive=self.ppa,
1148
            distroseries=self.squirrel)
11889.4.11 by Tim Penhey
And a test for a completed binary build.
1149
        builder = self.factory.makeBuilder()
1150
        binary_build = removeSecurityProxy(self.factory.makeBinaryPackageBuild(
1151
            source_package_release=source_package_release,
1152
            distroarchseries=self.squirrel.nominatedarchindep,
1153
            processor=builder.processor))
1154
        binary_build.queueBuild()
1155
        binary_build.status = BuildStatus.FULLYBUILT
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1156
        binary_build.date_started = datetime(2010, 04, 16, tzinfo=UTC)
1157
        binary_build.date_finished = datetime(2010, 04, 16, tzinfo=UTC)
11889.4.11 by Tim Penhey
And a test for a completed binary build.
1158
        binary_build.log = self.factory.makeLibraryFileAlias()
1159
1160
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
1161
            Latest builds
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1162
            Status .* Archive
11889.4.11 by Tim Penhey
And a test for a completed binary build.
1163
            Successful build on 2010-03-16 buildlog \(.*\) Secret Squirrel Secret PPA
1164
              chocolate - 0\+r42 on 2010-04-16 buildlog \(.*\) i386
1165
            Request build\(s\)""", self.getMainText(recipe))
1166
10744.2.1 by Aaron Bentley
Explain why there are no builds shown.
1167
    def test_index_no_builds(self):
10744.2.2 by Aaron Bentley
Tweakage.
1168
        """A message should be shown when there are no builds."""
10744.2.1 by Aaron Bentley
Explain why there are no builds shown.
1169
        recipe = self.makeRecipe()
7675.618.58 by Paul Hummer
Merge from devel, resolve conflicts (and fix tests)
1170
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
11889.1.2 by Tim Penhey
Test fix.
1171
            Latest builds
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1172
            Status .* Archive
7675.618.58 by Paul Hummer
Merge from devel, resolve conflicts (and fix tests)
1173
            This recipe has not been built yet.""", self.getMainText(recipe))
10498.3.16 by Aaron Bentley
Add tests for pending builds.
1174
1175
    def test_index_no_suitable_builders(self):
1176
        recipe = self.makeRecipe()
10498.5.15 by Aaron Bentley
Fix lint issues.
1177
        removeSecurityProxy(self.factory.makeSourcePackageRecipeBuild(
10498.5.11 by Aaron Bentley
Update existing tests for new layout.
1178
            recipe=recipe, distroseries=self.squirrel, archive=self.ppa))
7675.618.58 by Paul Hummer
Merge from devel, resolve conflicts (and fix tests)
1179
        self.assertTextMatchesExpressionIgnoreWhitespace("""
11889.1.2 by Tim Penhey
Test fix.
1180
            Latest builds
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1181
            Status .* Archive
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1182
            No suitable builders Secret Squirrel Secret PPA
7675.618.58 by Paul Hummer
Merge from devel, resolve conflicts (and fix tests)
1183
            Request build\(s\)""", self.getMainText(recipe))
10498.3.16 by Aaron Bentley
Add tests for pending builds.
1184
12178.2.2 by Tim Penhey
Fix the group test.
1185
    def makeBuildJob(self, recipe, date_created=None):
10498.5.16 by Aaron Bentley
Update docs
1186
        """Return a build associated with a buildjob."""
10498.5.11 by Aaron Bentley
Update existing tests for new layout.
1187
        build = self.factory.makeSourcePackageRecipeBuild(
12178.2.2 by Tim Penhey
Fix the group test.
1188
            recipe=recipe, distroseries=self.squirrel, archive=self.ppa,
1189
            date_created=date_created)
10498.5.15 by Aaron Bentley
Fix lint issues.
1190
        self.factory.makeSourcePackageRecipeBuildJob(recipe_build=build)
10498.3.22 by Aaron Bentley
Restrict the number of old builds shown.
1191
        return build
1192
1193
    def test_index_pending(self):
10498.5.16 by Aaron Bentley
Update docs
1194
        """Test the listing of a pending build."""
10498.3.22 by Aaron Bentley
Restrict the number of old builds shown.
1195
        recipe = self.makeRecipe()
10498.5.15 by Aaron Bentley
Fix lint issues.
1196
        self.makeBuildJob(recipe)
1197
        self.factory.makeBuilder()
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1198
        pattern = """\
11889.1.2 by Tim Penhey
Test fix.
1199
            Latest builds
11889.4.12 by Tim Penhey
Add the same methods to the build view.
1200
            Status .* Archive
1201
            Pending build in .* \(estimated\) Secret Squirrel Secret PPA
10498.5.11 by Aaron Bentley
Update existing tests for new layout.
1202
            Request build\(s\)
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1203
1204
            Recipe contents"""
10498.3.16 by Aaron Bentley
Add tests for pending builds.
1205
        main_text = self.getMainText(recipe)
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1206
        self.assertTextMatchesExpressionIgnoreWhitespace(
1207
            pattern, main_text)
10498.3.22 by Aaron Bentley
Restrict the number of old builds shown.
1208
1209
    def test_builds(self):
10498.3.24 by Aaron Bentley
Updates from review.
1210
        """Ensure SourcePackageRecipeView.builds is as described."""
10498.3.22 by Aaron Bentley
Restrict the number of old builds shown.
1211
        recipe = self.makeRecipe()
12397.2.14 by Ian Booth
Fix some tests
1212
        # We create builds in time ascending order (oldest first) since we
1213
        # use id as the ordering attribute and lower ids mean created earlier.
12178.2.2 by Tim Penhey
Fix the group test.
1214
        date_gen = time_counter(
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1215
            datetime(2010, 03, 16, tzinfo=UTC), timedelta(days=1))
12178.2.2 by Tim Penhey
Fix the group test.
1216
        build1 = self.makeBuildJob(recipe, date_gen.next())
1217
        build2 = self.makeBuildJob(recipe, date_gen.next())
1218
        build3 = self.makeBuildJob(recipe, date_gen.next())
1219
        build4 = self.makeBuildJob(recipe, date_gen.next())
1220
        build5 = self.makeBuildJob(recipe, date_gen.next())
1221
        build6 = self.makeBuildJob(recipe, date_gen.next())
10498.3.24 by Aaron Bentley
Updates from review.
1222
        view = SourcePackageRecipeView(recipe, None)
10498.3.22 by Aaron Bentley
Restrict the number of old builds shown.
1223
        self.assertEqual(
12397.2.14 by Ian Booth
Fix some tests
1224
            [build6, build5, build4, build3, build2, build1],
12287.2.1 by Ian Booth
Fix recipe build job query and refactor Storm extensions to services class
1225
            view.builds)
11151.3.3 by Abel Deuring
fix tests that failed for proxied distroseries and productseries objects
1226
12178.2.2 by Tim Penhey
Fix the group test.
1227
        def set_status(build, status):
7675.770.2 by Aaron Bentley
Fix failing tests.
1228
            naked_build = removeSecurityProxy(build)
12178.2.2 by Tim Penhey
Fix the group test.
1229
            naked_build.status = status
1230
            naked_build.date_started = naked_build.date_created
12287.2.1 by Ian Booth
Fix recipe build job query and refactor Storm extensions to services class
1231
            if status == BuildStatus.FULLYBUILT:
1232
                naked_build.date_finished = (
1233
                    naked_build.date_created + timedelta(minutes=10))
12397.2.14 by Ian Booth
Fix some tests
1234
        set_status(build6, BuildStatus.FULLYBUILT)
1235
        set_status(build5, BuildStatus.FAILEDTOBUILD)
10498.3.24 by Aaron Bentley
Updates from review.
1236
        # When there are 4+ pending builds, only the the most
1237
        # recently-completed build is returned (i.e. build1, not build2)
10498.3.22 by Aaron Bentley
Restrict the number of old builds shown.
1238
        self.assertEqual(
12397.2.14 by Ian Booth
Fix some tests
1239
            [build4, build3, build2, build1, build6],
12287.2.1 by Ian Booth
Fix recipe build job query and refactor Storm extensions to services class
1240
            view.builds)
12397.2.14 by Ian Booth
Fix some tests
1241
        set_status(build4, BuildStatus.FULLYBUILT)
12178.2.2 by Tim Penhey
Fix the group test.
1242
        set_status(build3, BuildStatus.FULLYBUILT)
12397.2.14 by Ian Booth
Fix some tests
1243
        set_status(build2, BuildStatus.FULLYBUILT)
1244
        set_status(build1, BuildStatus.FULLYBUILT)
10498.5.15 by Aaron Bentley
Fix lint issues.
1245
        self.assertEqual(
12397.2.14 by Ian Booth
Fix some tests
1246
            [build6, build5, build4, build3, build2], view.builds)
10498.5.12 by Aaron Bentley
Test request page.
1247
12378.2.16 by Ian Booth
Refactor some tests
1248
    def test_request_daily_builds_button_stale(self):
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1249
        # Recipes that are stale and are built daily have a build now link
1250
        recipe = self.factory.makeSourcePackageRecipe(
1251
            owner=self.chef, daily_build_archive=self.ppa,
1252
            is_stale=True, build_daily=True)
1253
        browser = self.getViewBrowser(recipe)
12378.2.5 by Ian Booth
Add tests and support for non-ajax forms
1254
        build_button = find_tag_by_id(browser.contents, 'field.actions.build')
1255
        self.assertIsNot(None, build_button)
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1256
12378.2.16 by Ian Booth
Refactor some tests
1257
    def test_request_daily_builds_button_not_stale(self):
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1258
        # Recipes that are not stale do not have a build now link
1259
        login(ANONYMOUS)
1260
        recipe = self.factory.makeSourcePackageRecipe(
1261
            owner=self.chef, daily_build_archive=self.ppa,
1262
            is_stale=False, build_daily=True)
1263
        browser = self.getViewBrowser(recipe)
12378.2.5 by Ian Booth
Add tests and support for non-ajax forms
1264
        build_button = find_tag_by_id(browser.contents, 'field.actions.build')
1265
        self.assertIs(None, build_button)
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1266
12378.2.16 by Ian Booth
Refactor some tests
1267
    def test_request_daily_builds_button_not_daily(self):
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1268
        # Recipes that are not built daily do not have a build now link
1269
        login(ANONYMOUS)
1270
        recipe = self.factory.makeSourcePackageRecipe(
1271
            owner=self.chef, daily_build_archive=self.ppa,
1272
            is_stale=True, build_daily=False)
1273
        browser = self.getViewBrowser(recipe)
12378.2.5 by Ian Booth
Add tests and support for non-ajax forms
1274
        build_button = find_tag_by_id(browser.contents, 'field.actions.build')
1275
        self.assertIs(None, build_button)
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1276
12378.2.16 by Ian Booth
Refactor some tests
1277
    def test_request_daily_builds_button_no_daily_ppa(self):
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1278
        # Recipes that have no daily build ppa do not have a build now link
1279
        login(ANONYMOUS)
1280
        recipe = self.factory.makeSourcePackageRecipe(
1281
            owner=self.chef, is_stale=True, build_daily=True)
1282
        naked_recipe = removeSecurityProxy(recipe)
1283
        naked_recipe.daily_build_archive = None
1284
        browser = self.getViewBrowser(recipe)
12378.2.5 by Ian Booth
Add tests and support for non-ajax forms
1285
        build_button = find_tag_by_id(browser.contents, 'field.actions.build')
1286
        self.assertIs(None, build_button)
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1287
12941.2.1 by Ian Booth
Do not show recipie build now if user does not have edit permission on recipe
1288
    def test_request_daily_builds_button_no_recipe_permission(self):
1289
        # Recipes do not have a build now link if the user does not have edit
1290
        # permission on the recipe.
1291
        login(ANONYMOUS)
1292
        recipe = self.factory.makeSourcePackageRecipe(
1293
            owner=self.chef, is_stale=True, build_daily=True)
1294
        person = self.factory.makePerson()
1295
        browser = self.getViewBrowser(recipe, user=person)
1296
        build_button = find_tag_by_id(browser.contents, 'field.actions.build')
1297
        self.assertIs(None, build_button)
1298
12378.2.16 by Ian Booth
Refactor some tests
1299
    def test_request_daily_builds_button_ppa_with_no_permissions(self):
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1300
        # Recipes that have a daily build ppa without upload permissions
1301
        # do not have a build now link
1302
        login(ANONYMOUS)
1303
        distroseries = self.factory.makeSourcePackageRecipeDistroseries()
1304
        person = self.factory.makePerson()
1305
        daily_build_archive = self.factory.makeArchive(
1306
                distribution=distroseries.distribution, owner=person)
1307
        recipe = self.factory.makeSourcePackageRecipe(
1308
            owner=self.chef, daily_build_archive=daily_build_archive,
1309
            is_stale=True, build_daily=True)
1310
        browser = self.getViewBrowser(recipe)
12378.2.5 by Ian Booth
Add tests and support for non-ajax forms
1311
        build_button = find_tag_by_id(browser.contents, 'field.actions.build')
1312
        self.assertIs(None, build_button)
1313
1314
    def test_request_daily_builds_ajax_link_not_rendered(self):
12378.2.18 by Ian Booth
Change some padding
1315
        # The Build now link should not be rendered without javascript.
12378.2.5 by Ian Booth
Add tests and support for non-ajax forms
1316
        recipe = self.factory.makeSourcePackageRecipe(
1317
            owner=self.chef, daily_build_archive=self.ppa,
1318
            is_stale=True, build_daily=True)
1319
        browser = self.getViewBrowser(recipe)
1320
        build_link = find_tag_by_id(browser.contents, 'request-daily-builds')
1321
        self.assertIs(None, build_link)
1322
12378.2.6 by Ian Booth
Add tests and cleanup javascript
1323
    def test_request_daily_builds_action(self):
12378.2.18 by Ian Booth
Change some padding
1324
        # Daily builds should be triggered when requested.
12378.2.5 by Ian Booth
Add tests and support for non-ajax forms
1325
        recipe = self.factory.makeSourcePackageRecipe(
1326
            owner=self.chef, daily_build_archive=self.ppa,
1327
            is_stale=True, build_daily=True)
1328
        browser = self.getViewBrowser(recipe)
1329
        browser.getControl('Build now').click()
12378.2.6 by Ian Booth
Add tests and cleanup javascript
1330
        login(ANONYMOUS)
12397.2.12 by Ian Booth
Fix typo in test
1331
        builds = recipe.pending_builds
12378.2.6 by Ian Booth
Add tests and cleanup javascript
1332
        build_distros = [
1333
            build.distroseries.displayname for build in builds]
1334
        build_distros.sort()
1335
        # Our recipe has a Warty distroseries
1336
        self.assertEqual(['Warty'], build_distros)
1337
        self.assertEqual(
1338
            set([2505]),
1339
            set(build.buildqueue_record.lastscore for build in builds))
12378.2.4 by Ian Booth
Add tests and drive by fix for recipe vocabs
1340
10498.5.14 by Aaron Bentley
Test build request action
1341
    def test_request_builds_page(self):
10498.5.16 by Aaron Bentley
Update docs
1342
        """Ensure the +request-builds page is sane."""
10498.5.12 by Aaron Bentley
Test request page.
1343
        recipe = self.makeRecipe()
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1344
        pattern = dedent("""\
10498.5.12 by Aaron Bentley
Test request page.
1345
            Request builds for cake_recipe
1346
            Master Chef
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1347
            Recipes
1348
            cake_recipe
10498.5.12 by Aaron Bentley
Test request page.
1349
            Request builds for cake_recipe
1350
            Archive:
13324.5.2 by Steve Kowalik
Fix tests.
1351
            Secret PPA
10498.5.12 by Aaron Bentley
Test request page.
1352
            Distribution series:
10833.1.2 by Paul Hummer
Fixed tests
1353
            Secret Squirrel
7675.729.9 by Aaron Bentley
Fix failing test.
1354
            Hoary
10498.5.12 by Aaron Bentley
Test request page.
1355
            Warty
1356
            or
7675.618.57 by Paul Hummer
Fixed the source package recipe tests
1357
            Cancel""")
1358
        main_text = self.getMainText(recipe, '+request-builds')
1359
        self.assertEqual(pattern, main_text)
10498.5.12 by Aaron Bentley
Test request page.
1360
10498.5.14 by Aaron Bentley
Test build request action
1361
    def test_request_builds_action(self):
1362
        """Requesting a build creates pending builds."""
10833.1.2 by Paul Hummer
Fixed tests
1363
        woody = self.factory.makeDistroSeries(
1364
            name='woody', displayname='Woody',
1365
            distribution=self.ppa.distribution)
11151.3.3 by Abel Deuring
fix tests that failed for proxied distroseries and productseries objects
1366
        naked_woody = remove_security_proxy_and_shout_at_engineer(woody)
1367
        naked_woody.nominatedarchindep = woody.newArch(
10859.1.5 by Paul Hummer
Fixed tests
1368
            'i386', ProcessorFamily.get(1), False, self.factory.makePerson(),
1369
            supports_virtualized=True)
1370
10498.5.14 by Aaron Bentley
Test build request action
1371
        recipe = self.makeRecipe()
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1372
        browser = self.getViewBrowser(recipe, '+request-builds')
10498.5.14 by Aaron Bentley
Test build request action
1373
        browser.getControl('Woody').click()
1374
        browser.getControl('Request builds').click()
11043.2.3 by Paul Hummer
Fixed browser tests
1375
1376
        login(ANONYMOUS)
12397.2.8 by Ian Booth
Change from using getter methods to properties for exported recipe and build accessors
1377
        builds = recipe.pending_builds
10498.5.14 by Aaron Bentley
Test build request action
1378
        build_distros = [
10899.2.11 by Aaron Bentley
Browser-initiated builds have 1000 lastscore.
1379
            build.distroseries.displayname for build in builds]
10498.5.14 by Aaron Bentley
Test build request action
1380
        build_distros.sort()
1381
        # Secret Squirrel is checked by default.
1382
        self.assertEqual(['Secret Squirrel', 'Woody'], build_distros)
10899.2.11 by Aaron Bentley
Browser-initiated builds have 1000 lastscore.
1383
        self.assertEqual(
11435.7.3 by Ian Booth
Fix failing unit test: lp/code/browser/tests/test_sourcepackagerecipe.py
1384
            set([2605]),
10899.2.11 by Aaron Bentley
Browser-initiated builds have 1000 lastscore.
1385
            set(build.buildqueue_record.lastscore for build in builds))
7675.618.48 by Paul Hummer
Added unittest for delete.
1386
11570.1.1 by Paul Hummer
Fixed requesting builds by a not-logged-in user
1387
    def test_request_builds_action_not_logged_in(self):
1388
        """Requesting a build creates pending builds."""
1389
        woody = self.factory.makeDistroSeries(
1390
            name='woody', displayname='Woody',
1391
            distribution=self.ppa.distribution)
11570.1.3 by Paul Hummer
Don't introduce shout_at_engineer
1392
        naked_woody = removeSecurityProxy(woody)
11570.1.1 by Paul Hummer
Fixed requesting builds by a not-logged-in user
1393
        naked_woody.nominatedarchindep = woody.newArch(
1394
            'i386', ProcessorFamily.get(1), False, self.factory.makePerson(),
1395
            supports_virtualized=True)
1396
        recipe = self.makeRecipe()
1397
11570.1.4 by Paul Hummer
Fixed getViewBrowser to not always log me in
1398
        browser = self.getViewBrowser(recipe, no_login=True)
11570.1.1 by Paul Hummer
Fixed requesting builds by a not-logged-in user
1399
        self.assertRaises(
1400
            Unauthorized, browser.getLink('Request build(s)').click)
1401
10875.2.1 by Aaron Bentley
Use last build archive as initial value
1402
    def test_request_builds_archive(self):
1403
        recipe = self.factory.makeSourcePackageRecipe()
1404
        ppa2 = self.factory.makeArchive(
1405
            displayname='Secret PPA', owner=self.chef, name='ppa2')
1406
        view = SourcePackageRecipeRequestBuildsView(recipe, None)
1407
        self.assertIs(None, view.initial_values.get('archive'))
1408
        self.factory.makeSourcePackageRecipeBuild(recipe=recipe, archive=ppa2)
1409
        self.assertEqual(ppa2, view.initial_values.get('archive'))
1410
10936.6.2 by Aaron Bentley
Handle over-quota builds
1411
    def test_request_build_rejects_over_quota(self):
1412
        """Over-quota build requests cause validation failures."""
1413
        woody = self.factory.makeDistroSeries(
1414
            name='woody', displayname='Woody',
1415
            distribution=self.ppa.distribution)
11151.3.3 by Abel Deuring
fix tests that failed for proxied distroseries and productseries objects
1416
        naked_woody = remove_security_proxy_and_shout_at_engineer(woody)
1417
        naked_woody.nominatedarchindep = woody.newArch(
10936.6.2 by Aaron Bentley
Handle over-quota builds
1418
            'i386', ProcessorFamily.get(1), False, self.factory.makePerson(),
1419
            supports_virtualized=True)
1420
1421
        recipe = self.makeRecipe()
7675.729.2 by Aaron Bentley
Fix failing tests.
1422
        for x in range(5):
1423
            build = recipe.requestBuild(
1424
                self.ppa, self.chef, woody, PackagePublishingPocket.RELEASE)
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1425
            removeSecurityProxy(build).status = BuildStatus.FULLYBUILT
10936.6.2 by Aaron Bentley
Handle over-quota builds
1426
1427
        browser = self.getViewBrowser(recipe, '+request-builds')
1428
        browser.getControl('Woody').click()
1429
        browser.getControl('Request builds').click()
1430
        self.assertIn("You have exceeded today's quota for ubuntu woody.",
1431
                extract_text(find_main_content(browser.contents)))
10875.2.1 by Aaron Bentley
Use last build archive as initial value
1432
7675.729.3 by Aaron Bentley
Handle identical builds in the UI.
1433
    def test_request_builds_rejects_duplicate(self):
1434
        """Over-quota build requests cause validation failures."""
1435
        woody = self.factory.makeDistroSeries(
1436
            name='woody', displayname='Woody',
1437
            distribution=self.ppa.distribution)
11151.3.3 by Abel Deuring
fix tests that failed for proxied distroseries and productseries objects
1438
        naked_woody = remove_security_proxy_and_shout_at_engineer(woody)
1439
        naked_woody.nominatedarchindep = woody.newArch(
7675.729.3 by Aaron Bentley
Handle identical builds in the UI.
1440
            'i386', ProcessorFamily.get(1), False, self.factory.makePerson(),
1441
            supports_virtualized=True)
1442
1443
        recipe = self.makeRecipe()
7675.729.8 by Aaron Bentley
Fix lint warnings.
1444
        recipe.requestBuild(
7675.729.3 by Aaron Bentley
Handle identical builds in the UI.
1445
            self.ppa, self.chef, woody, PackagePublishingPocket.RELEASE)
1446
1447
        browser = self.getViewBrowser(recipe, '+request-builds')
1448
        browser.getControl('Woody').click()
1449
        browser.getControl('Request builds').click()
1450
        self.assertIn(
1451
            "An identical build is already pending for ubuntu woody.",
1452
            extract_text(find_main_content(browser.contents)))
1453
12177.4.1 by Tim Penhey
Show a message on the main recipe page if the recipe owner can't upload into the daily ppa.
1454
    def makeRecipeWithUploadIssues(self):
1455
        """Make a recipe where the owner can't upload to the PPA."""
1456
        # This occurs when the PPA that the recipe is being built daily into
1457
        # is owned by a team, and the owner of the recipe isn't in the team
1458
        # that owns the PPA.
1459
        registrant = self.factory.makePerson()
1460
        owner_team = self.factory.makeTeam(members=[registrant], name='team1')
1461
        ppa_team = self.factory.makeTeam(members=[registrant], name='team2')
1462
        ppa = self.factory.makeArchive(owner=ppa_team, name='ppa')
1463
        return self.factory.makeSourcePackageRecipe(
1464
            registrant=registrant, owner=owner_team, daily_build_archive=ppa,
1465
            build_daily=True)
1466
1467
    def test_owner_with_no_ppa_upload_permission(self):
1468
        # Daily build with upload issues are a problem.
1469
        recipe = self.makeRecipeWithUploadIssues()
1470
        view = create_initialized_view(recipe, '+index')
1471
        self.assertTrue(view.dailyBuildWithoutUploadPermission())
1472
1473
    def test_owner_with_no_ppa_upload_permission_non_daily(self):
1474
        # Non-daily builds with upload issues are not so much of an issue.
1475
        recipe = self.makeRecipeWithUploadIssues()
1476
        with person_logged_in(recipe.registrant):
1477
            recipe.build_daily = False
1478
        view = create_initialized_view(recipe, '+index')
1479
        self.assertFalse(view.dailyBuildWithoutUploadPermission())
1480
1481
    def test_owner_with_no_ppa_upload_permission_message(self):
1482
        # If there is an issue, a message is shown.
1483
        recipe = self.makeRecipeWithUploadIssues()
1484
        browser = self.getViewBrowser(recipe, '+index')
1485
        messages = get_feedback_messages(browser.contents)
1486
        self.assertEqual(
1487
            "Daily builds for this recipe will not occur.\n"
1488
            "The owner of the recipe (Team1) does not have permission to "
1489
            "upload packages into the daily build PPA (PPA for Team2)",
1490
            messages[-1])
1491
12392.3.1 by Steve Kowalik
Don't return recipe builds that built/are building into a disabled archive,
1492
    def test_view_with_disabled_archive(self):
1493
        # When a PPA is disabled, it is only viewable to the owner. This
1494
        # case is handled with the view not showing builds into a disabled
1495
        # archive, rather than giving an Unauthorized error to the user.
1496
        recipe = self.factory.makeSourcePackageRecipe(build_daily=True)
1497
        recipe.requestBuild(
1498
            recipe.daily_build_archive, recipe.owner, self.squirrel,
1499
            PackagePublishingPocket.RELEASE)
1500
        with person_logged_in(recipe.owner):
1501
            recipe.daily_build_archive.disable()
12392.3.3 by Steve Kowalik
getUserBrowser creates a person for us, so no-priv can go away, and rename a
1502
        browser = self.getUserBrowser(canonical_url(recipe))
12392.3.1 by Steve Kowalik
Don't return recipe builds that built/are building into a disabled archive,
1503
        self.assertIn(
1504
            "This recipe has not been built yet.",
1505
            extract_text(find_main_content(browser.contents)))
1506
7675.618.48 by Paul Hummer
Added unittest for delete.
1507
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1508
class TestSourcePackageRecipeBuildView(BrowserTestCase):
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1509
    """Test behaviour of SourcePackageReciptBuildView."""
1510
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1511
    layer = LaunchpadFunctionalLayer
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1512
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1513
    def setUp(self):
1514
        """Provide useful defaults."""
1515
        super(TestSourcePackageRecipeBuildView, self).setUp()
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1516
        self.user = self.factory.makePerson(
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1517
            displayname='Owner', name='build-owner', password='test')
1518
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1519
    def makeBuild(self):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1520
        """Make a build suitabe for testing."""
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1521
        archive = self.factory.makeArchive(name='build',
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1522
            owner=self.user)
1523
        recipe = self.factory.makeSourcePackageRecipe(
7675.700.1 by Paul Hummer
Removed sourcepackagename from ISourcePackageRecipe and ISourcePackageRecipeBuild
1524
            owner=self.user, name=u'my-recipe')
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1525
        distro_series = self.factory.makeDistroSeries(
1526
            name='squirrel', distribution=archive.distribution)
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1527
        build = self.factory.makeSourcePackageRecipeBuild(
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1528
            requester=self.user, archive=archive, recipe=recipe,
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1529
            distroseries=distro_series)
10795.6.21 by Aaron Bentley
Fix lint problems.
1530
        self.factory.makeSourcePackageRecipeBuildJob(recipe_build=build)
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1531
        self.factory.makeBuilder()
10795.6.16 by Aaron Bentley
Clean up index.
1532
        return build
1533
1534
    def makeBuildView(self):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1535
        """Return a view of a build suitable for testing."""
10795.6.16 by Aaron Bentley
Clean up index.
1536
        return SourcePackageRecipeBuildView(self.makeBuild(), None)
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1537
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1538
    def test_estimate(self):
1539
        """Time should be estimated until the job is completed."""
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1540
        view = self.makeBuildView()
1541
        self.assertTrue(view.estimate)
1542
        view.context.buildqueue_record.job.start()
11889.4.7 by Tim Penhey
Fix the existing test failures due to new cached properties.
1543
        clear_property_cache(view)
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1544
        self.assertTrue(view.estimate)
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1545
        removeSecurityProxy(view.context).date_finished = datetime.now(UTC)
11889.4.7 by Tim Penhey
Fix the existing test failures due to new cached properties.
1546
        clear_property_cache(view)
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1547
        self.assertFalse(view.estimate)
1548
1549
    def test_eta(self):
1550
        """ETA should be reasonable.
1551
1552
        It should be None if there is no builder or queue entry.
1553
        It should be getEstimatedJobStartTime + estimated duration for jobs
1554
        that have not started.
1555
        It should be job.date_started + estimated duration for jobs that have
1556
        started.
1557
        """
1558
        build = self.factory.makeSourcePackageRecipeBuild()
1559
        view = SourcePackageRecipeBuildView(build, None)
1560
        self.assertIs(None, view.eta)
1561
        queue_entry = self.factory.makeSourcePackageRecipeBuildJob(
1562
            recipe_build=build)
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1563
        queue_entry._now = lambda: datetime(1970, 1, 1, 0, 0, 0, 0, UTC)
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1564
        self.factory.makeBuilder()
11889.4.7 by Tim Penhey
Fix the existing test failures due to new cached properties.
1565
        clear_property_cache(view)
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1566
        self.assertIsNot(None, view.eta)
1567
        self.assertEqual(
1568
            queue_entry.getEstimatedJobStartTime() +
1569
            queue_entry.estimated_duration, view.eta)
1570
        queue_entry.job.start()
11889.4.7 by Tim Penhey
Fix the existing test failures due to new cached properties.
1571
        clear_property_cache(view)
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1572
        self.assertEqual(
1573
            queue_entry.job.date_started + queue_entry.estimated_duration,
1574
            view.eta)
1575
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1576
    def getBuildBrowser(self, build, view_name=None):
1577
        """Return a browser for the specified build, opened as owner."""
1578
        login(ANONYMOUS)
1579
        url = canonical_url(build, view_name=view_name)
1580
        return self.getUserBrowser(url, self.build_owner)
1581
1582
    def test_render_index(self):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1583
        """Test the basic index page."""
1584
        main_text = self.getMainText(self.makeBuild(), '+index')
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1585
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
12119.1.16 by Tim Penhey
Redirect +build urls into +buildjob.
1586
            Owner PPA named build for Owner
11308.2.3 by Curtis Hovey
Updated tests to recognise the new position of the registration slot.
1587
            created .*
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1588
            Build status
1589
            Needs building
11243.3.2 by Aaron Bentley
Show current score for builds.
1590
            Start in .* \\(9876\\) What's this?.*
10795.6.16 by Aaron Bentley
Clean up index.
1591
            Estimated finish in .*
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1592
            Build details
10795.6.16 by Aaron Bentley
Clean up index.
1593
            Recipe:        Recipe my-recipe for Owner
1594
            Archive:       PPA named build for Owner
1595
            Series:        Squirrel
1596
            Pocket:        Release
1597
            Binary builds: None""", main_text)
10795.6.15 by Aaron Bentley
Correctly show 'None' for Binary builds.
1598
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1599
    def test_render_index_completed(self):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1600
        """Test the index page of a completed build."""
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1601
        release = self.makeBuildAndRelease()
1602
        self.makeBinaryBuild(release, 'itanic')
1603
        naked_build = removeSecurityProxy(release.source_package_recipe_build)
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1604
        naked_build.status = BuildStatus.FULLYBUILT
12607.5.1 by Ian Booth
Ensure date_last_modified is updated
1605
        naked_build.date_finished = datetime(2009, 1, 1, tzinfo=UTC)
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1606
        naked_build.date_started = (
1607
            naked_build.date_finished - timedelta(minutes=1))
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1608
        naked_build.buildqueue_record.destroySelf()
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1609
        naked_build.log = self.factory.makeLibraryFileAlias(
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1610
            content='buildlog')
1611
        naked_build.upload_log = self.factory.makeLibraryFileAlias(
1612
            content='upload_log')
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1613
        main_text = self.getMainText(
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1614
            release.source_package_recipe_build, '+index')
1615
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
12119.1.16 by Tim Penhey
Redirect +build urls into +buildjob.
1616
            Owner PPA named build for Owner
11308.2.3 by Curtis Hovey
Updated tests to recognise the new position of the registration slot.
1617
            created .*
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1618
            Build status
1619
            Successfully built
10795.8.2 by Aaron Bentley
Change date test to use pattern.
1620
            Started on .*
1621
            Finished on .*
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1622
            \(took 1 minute, 0.0 seconds\)
1623
            buildlog \(8 bytes\)
1624
            uploadlog \(10 bytes\)
1625
            Build details
1626
            Recipe:        Recipe my-recipe for Owner
1627
            Archive:       PPA named build for Owner
1628
            Series:        Squirrel
1629
            Pocket:        Release
1630
            Binary builds:
7675.700.1 by Paul Hummer
Removed sourcepackagename from ISourcePackageRecipe and ISourcePackageRecipeBuild
1631
            itanic build of .* 3.14 in ubuntu squirrel RELEASE""",
10795.6.19 by Aaron Bentley
Add test of layout when completed.
1632
            main_text)
1633
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1634
    def makeBuildAndRelease(self):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1635
        """Make a build and release suitable for testing."""
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1636
        build = self.makeBuild()
10899.2.16 by Aaron Bentley
Fix test failures due to component name silliness.
1637
        multiverse = self.factory.makeComponent(name='multiverse')
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1638
        return self.factory.makeSourcePackageRelease(
10899.2.16 by Aaron Bentley
Fix test failures due to component name silliness.
1639
            source_package_recipe_build=build, version='3.14',
1640
            component=multiverse)
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1641
1642
    def makeBinaryBuild(self, release, architecturetag):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1643
        """Make a binary build with specified release and architecturetag."""
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1644
        distroarchseries = self.factory.makeDistroArchSeries(
1645
            architecturetag=architecturetag,
1646
            distroseries=release.upload_distroseries,
1647
            processorfamily=self.factory.makeProcessorFamily())
10795.6.21 by Aaron Bentley
Fix lint problems.
1648
        return self.factory.makeBinaryPackageBuild(
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1649
            source_package_release=release, distroarchseries=distroarchseries)
1650
1651
    def test_render_binary_builds(self):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1652
        """BinaryBuilds for this source build are shown if they exist."""
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1653
        release = self.makeBuildAndRelease()
1654
        self.makeBinaryBuild(release, 'itanic')
1655
        self.makeBinaryBuild(release, 'x87-64')
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1656
        main_text = self.getMainText(
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1657
            release.source_package_recipe_build, '+index')
1658
        self.assertTextMatchesExpressionIgnoreWhitespace("""\
1659
            Binary builds:
7675.700.1 by Paul Hummer
Removed sourcepackagename from ISourcePackageRecipe and ISourcePackageRecipeBuild
1660
            itanic build of .* 3.14 in ubuntu squirrel RELEASE
1661
            x87-64 build of .* 3.14 in ubuntu squirrel RELEASE$""",
10795.6.17 by Aaron Bentley
More tests, for source_package_releases and binary builds.
1662
            main_text)
1663
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1664
    def test_logtail(self):
1665
        """Logtail is shown for BUILDING builds."""
1666
        build = self.makeBuild()
1667
        build.buildqueue_record.logtail = 'Logs have no tails!'
1668
        build.buildqueue_record.builder = self.factory.makeBuilder()
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1669
        main_text = self.getMainText(build, '+index')
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1670
        self.assertNotIn('Logs have no tails!', main_text)
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1671
        removeSecurityProxy(build).status = BuildStatus.BUILDING
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1672
        main_text = self.getMainText(build, '+index')
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1673
        self.assertIn('Logs have no tails!', main_text)
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1674
        removeSecurityProxy(build).status = BuildStatus.FULLYBUILT
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1675
        self.assertIn('Logs have no tails!', main_text)
1676
1677
    def getMainText(self, build, view_name=None):
10795.6.22 by Aaron Bentley
Misc cleanup and documentation.
1678
        """"Return the main text of a view's web page."""
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1679
        browser = self.getViewBrowser(build, '+index')
1680
        return extract_text(find_main_content(browser.contents))
1681
1682
    def test_buildlog(self):
1683
        """A link to the build log is shown if available."""
1684
        build = self.makeBuild()
11121.4.2 by Aaron Bentley
Get all sourcepackagerecipe tests passing.
1685
        removeSecurityProxy(build).log = (
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1686
            self.factory.makeLibraryFileAlias())
11121.4.13 by Aaron Bentley
Fix failing test.
1687
        build_log_url = build.log_url
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1688
        browser = self.getViewBrowser(build)
1689
        link = browser.getLink('buildlog')
11121.4.13 by Aaron Bentley
Fix failing test.
1690
        self.assertEqual(build_log_url, link.url)
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1691
1692
    def test_uploadlog(self):
1693
        """A link to the upload log is shown if available."""
1694
        build = self.makeBuild()
1695
        removeSecurityProxy(build).upload_log = (
1696
            self.factory.makeLibraryFileAlias())
11043.2.3 by Paul Hummer
Fixed browser tests
1697
        upload_log_url = build.upload_log_url
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1698
        browser = self.getViewBrowser(build)
1699
        link = browser.getLink('uploadlog')
11043.2.3 by Paul Hummer
Fixed browser tests
1700
        self.assertEqual(upload_log_url, link.url)
10795.6.18 by Aaron Bentley
Add log tests and simplify TAL
1701
10795.6.7 by Aaron Bentley
Restore accidentally-removed test.
1702
7675.618.48 by Paul Hummer
Added unittest for delete.
1703
class TestSourcePackageRecipeDeleteView(TestCaseForRecipe):
1704
1705
    layer = DatabaseFunctionalLayer
1706
1707
    def test_delete_recipe(self):
1708
        recipe = self.factory.makeSourcePackageRecipe(owner=self.chef)
1709
1710
        browser = self.getUserBrowser(
1711
            canonical_url(recipe), user=self.chef)
1712
1713
        browser.getLink('Delete recipe').click()
1714
        browser.getControl('Delete recipe').click()
1715
1716
        self.assertEqual(
1717
            'http://code.launchpad.dev/~chef',
1718
            browser.url)
11316.3.2 by Paul Hummer
Added test to make sure no one but the owner gets to delete recipes
1719
1720
    def test_delete_recipe_no_permissions(self):
1721
        recipe = self.factory.makeSourcePackageRecipe(owner=self.chef)
1722
        nopriv_person = self.factory.makePerson()
1723
        recipe_url = canonical_url(recipe)
1724
1725
        browser = self.getUserBrowser(
1726
            recipe_url, user=nopriv_person)
1727
1728
        self.assertRaises(
1729
            LinkNotFoundError,
1730
            browser.getLink, 'Delete recipe')
1731
1732
        self.assertRaises(
1733
            Unauthorized,
1734
            self.getUserBrowser, recipe_url + '/+delete', user=nopriv_person)
12178.1.2 by Tim Penhey
Tests.
1735
1736
1737
class TestBrokenExistingRecipes(BrowserTestCase):
1738
    """Existing recipes broken by builder updates need to be editable.
1739
1740
    This happened with a 0.2 -> 0.3 release where the nest command was no
1741
    longer allowed to refer the '.'.  There were already existing recipes that
1742
    had this text that were not viewable or editable.  This test case captures
1743
    that and makes sure the views stay visible.
1744
    """
1745
1746
    layer = LaunchpadFunctionalLayer
1747
12178.1.3 by Tim Penhey
Test refactoring.
1748
    RECIPE_FIRST_LINE = (
1749
        "# bzr-builder format 0.2 deb-version {debupstream}+{revno}")
1750
12178.1.2 by Tim Penhey
Tests.
1751
    def makeBrokenRecipe(self):
1752
        """Make a valid recipe, then break it."""
1753
        product = self.factory.makeProduct()
1754
        b1 = self.factory.makeProductBranch(product=product)
1755
        b2 = self.factory.makeProductBranch(product=product)
1756
        recipe_text = dedent("""\
12178.1.3 by Tim Penhey
Test refactoring.
1757
            %s
12178.1.2 by Tim Penhey
Tests.
1758
            %s
1759
            nest name %s foo
12178.1.3 by Tim Penhey
Test refactoring.
1760
            """ % (self.RECIPE_FIRST_LINE, b1.bzr_identity, b2.bzr_identity))
12178.1.2 by Tim Penhey
Tests.
1761
        recipe = self.factory.makeSourcePackageRecipe(recipe=recipe_text)
1762
        naked_data = removeSecurityProxy(recipe)._recipe_data
1763
        nest_instruction = list(naked_data.instructions)[0]
1764
        nest_instruction.directory = u'.'
1765
        return recipe
1766
1767
    def test_recipe_is_broken(self):
1768
        recipe = self.makeBrokenRecipe()
1769
        self.assertRaises(Exception, str, recipe.builder_recipe)
1770
12178.1.3 by Tim Penhey
Test refactoring.
1771
    def assertRecipeInText(self, text):
1772
        """If the first line is shown, that's good enough for us."""
1773
        self.assertTrue(self.RECIPE_FIRST_LINE in text)
1774
12178.1.2 by Tim Penhey
Tests.
1775
    def test_recipe_index_renderable(self):
1776
        recipe = self.makeBrokenRecipe()
1777
        main_text = self.getMainText(recipe, '+index')
12178.1.3 by Tim Penhey
Test refactoring.
1778
        self.assertRecipeInText(main_text)
12178.1.2 by Tim Penhey
Tests.
1779
1780
    def test_recipe_edit_renderable(self):
1781
        recipe = self.makeBrokenRecipe()
1782
        main_text = self.getMainText(recipe, '+edit', user=recipe.owner)
12178.1.3 by Tim Penhey
Test refactoring.
1783
        self.assertRecipeInText(main_text)