~launchpad-pqm/launchpad/devel

13597.1.1 by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
8687.15.34 by Karl Fogel
Add license header blocks to .py, .zcml, and .pt files that don't have it
2
# GNU Affero General Public License version 3 (see the file LICENSE).
8698.11.9 by Tim Penhey
New view added.
3
4
"""Helper functions for code testing live here."""
5
6
__metaclass__ = type
9372.1.3 by Tim Penhey
Reworked statement counting.
7
__all__ = [
9984.4.6 by Tim Penhey
Add a helper to add a revision to a branch and update the scanned details.
8
    'add_revision_to_branch',
13662.5.1 by Aaron Bentley
Pushing to non-existant sourcepackagename creates.
9
    'get_non_existant_source_package_branch_unique_name',
10843.3.1 by Tim Penhey
Extract the method to make an official package branch.
10
    'make_erics_fooix_project',
9372.1.3 by Tim Penhey
Reworked statement counting.
11
    'make_linked_package_branch',
11542.3.18 by Ian Booth
Use helper method instead of factory method for bmp with no reviewer creation
12
    'make_merge_proposal_without_reviewers',
10843.3.1 by Tim Penhey
Extract the method to make an official package branch.
13
    'make_official_package_branch',
11435.5.3 by Tim Penhey
Make the view work better.
14
    'make_project_branch_with_revisions',
15
    'make_project_cloud_data',
14562.1.3 by William Grant
Merge databasehelpers into code
16
    'remove_all_sample_data_branches',
9372.1.3 by Tim Penhey
Reworked statement counting.
17
    ]
8698.11.9 by Tim Penhey
New view added.
18
19
11603.1.5 by Paul Hummer
Made the RecipeParser.NEWEST_VERSION monkeypatch use a contextmanager
20
from contextlib import contextmanager
8698.11.9 by Tim Penhey
New view added.
21
from datetime import timedelta
9691.5.8 by Tim Penhey
Make the page test pass again, removing references to fixed urls
22
from difflib import unified_diff
8698.11.9 by Tim Penhey
New view added.
23
from itertools import count
7675.916.98 by Henning Eggers
Merged db-stable at r10026 (recife roll-back) but without accepting the changes.
24
25
from bzrlib.plugins.builder.recipe import RecipeParser
7675.991.2 by Jeroen Vermeulen
Roll back lp:~launchpad/launchpad/recife.
26
import transaction
8698.11.9 by Tim Penhey
New view added.
27
from zope.component import getUtility
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
28
from zope.security.proxy import (
29
    isinstance as zisinstance,
30
    removeSecurityProxy,
31
    )
8698.11.9 by Tim Penhey
New view added.
32
14562.1.3 by William Grant
Merge databasehelpers into code
33
from canonical.database.sqlbase import cursor
7675.624.84 by Tim Penhey
Fix doc/codereviewcomment.txt. 2 to go.
34
from lp.code.interfaces.branchmergeproposal import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
35
    IBranchMergeProposalJobSource,
36
    )
10843.3.1 by Tim Penhey
Extract the method to make an official package branch.
37
from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
11435.5.3 by Tim Penhey
Make the view work better.
38
from lp.code.interfaces.revision import IRevisionSet
13139.3.3 by Francis J. Lacoste
Remove IMakeOfficialBranchLinks non-utility.
39
from lp.code.model.seriessourcepackagebranch import (
13597.1.1 by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint.
40
    SeriesSourcePackageBranchSet,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
41
    )
42
from lp.registry.interfaces.pocket import PackagePublishingPocket
10054.26.1 by Adi Roiban
Refactor DistroSeriesStatus to SeriesStatus; Don't prompt for setting up translations for obsolete product series.
43
from lp.registry.interfaces.series import SeriesStatus
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
44
from lp.testing import (
45
    run_with_login,
46
    time_counter,
47
    )
9691.5.7 by Tim Penhey
Add a helper function and make the page test use it.
48
49
7675.624.84 by Tim Penhey
Fix doc/codereviewcomment.txt. 2 to go.
50
def mark_all_merge_proposal_jobs_done():
51
    """Sometimes in tests we want to clear out all pending jobs.
52
53
    This function iterates through all the pending jobs and marks the done.
54
    """
55
    while True:
56
        jobs = list(getUtility(IBranchMergeProposalJobSource).iterReady())
57
        if len(jobs) == 0:
58
            break
59
        for job in jobs:
60
            job.start()
61
            job.complete()
62
63
9984.4.6 by Tim Penhey
Add a helper to add a revision to a branch and update the scanned details.
64
def add_revision_to_branch(factory, branch, revision_date, date_created=None,
9984.4.12 by Tim Penhey
Story completes the story.
65
                           mainline=True, commit_msg=None):
9984.4.6 by Tim Penhey
Add a helper to add a revision to a branch and update the scanned details.
66
    """Add a new revision to the branch with the specified revision date.
67
68
    If date_created is None, it gets set to the revision_date.
69
    """
70
    if date_created is None:
71
        date_created = revision_date
11486.2.5 by Aaron Bentley
Handle parents correctly in add_revision_to_branch.
72
    parent = branch.revision_history.last()
73
    if parent is None:
74
        parent_ids = []
75
    else:
76
        parent_ids = [parent.revision.revision_id]
9984.4.6 by Tim Penhey
Add a helper to add a revision to a branch and update the scanned details.
77
    revision = factory.makeRevision(
9984.4.12 by Tim Penhey
Story completes the story.
78
        revision_date=revision_date, date_created=date_created,
11486.2.5 by Aaron Bentley
Handle parents correctly in add_revision_to_branch.
79
        log_body=commit_msg, parent_ids=parent_ids)
9984.4.6 by Tim Penhey
Add a helper to add a revision to a branch and update the scanned details.
80
    if mainline:
81
        sequence = branch.revision_count + 1
82
        branch_revision = branch.createBranchRevision(sequence, revision)
83
        branch.updateScannedDetails(revision, sequence)
84
    else:
85
        branch_revision = branch.createBranchRevision(None, revision)
86
    return branch_revision
87
88
9691.5.7 by Tim Penhey
Add a helper function and make the page test use it.
89
def make_erics_fooix_project(factory):
90
    """Make Eric, the Fooix project, and some branches.
91
92
    :return: a dict of objects to put into local scope.
93
    """
94
    eric = factory.makePerson(
95
        name='eric', displayname='Eric the Viking',
96
        email='eric@example.com', password='test')
97
    fooix = factory.makeProduct(
98
        name='fooix', displayname='Fooix', owner=eric)
99
    trunk = factory.makeProductBranch(
100
        owner=eric, product=fooix, name='trunk')
9691.5.8 by Tim Penhey
Make the page test pass again, removing references to fixed urls
101
    removeSecurityProxy(fooix.development_focus).branch = trunk
102
    # Development is done by Fred.
103
    fred = factory.makePerson(
104
        name='fred', displayname='Fred Flintstone',
105
        email='fred@example.com', password='test')
9691.5.7 by Tim Penhey
Add a helper function and make the page test use it.
106
    feature = factory.makeProductBranch(
9691.5.8 by Tim Penhey
Make the page test pass again, removing references to fixed urls
107
        owner=fred, product=fooix, name='feature')
108
    proposed = factory.makeProductBranch(
109
        owner=fred, product=fooix, name='proposed')
110
    bmp = proposed.addLandingTarget(
111
        registrant=fred, target_branch=trunk, needs_review=True,
112
        review_requests=[(eric, 'code')])
113
    # And fake a diff.
114
    naked_bmp = removeSecurityProxy(bmp)
9691.6.4 by Tim Penhey
Add a windmill test.
115
    preview = removeSecurityProxy(naked_bmp.updatePreviewDiff(
9691.5.8 by Tim Penhey
Make the page test pass again, removing references to fixed urls
116
        ''.join(unified_diff('', 'random content')), u'rev-a', u'rev-b'))
117
    naked_bmp.source_branch.last_scanned_id = preview.source_revision_id
118
    naked_bmp.target_branch.last_scanned_id = preview.target_revision_id
119
    preview.diff_lines_count = 47
120
    preview.added_lines_count = 7
121
    preview.remvoed_lines_count = 13
122
    preview.diffstat = {'file1': (3, 8), 'file2': (4, 5)}
9691.5.7 by Tim Penhey
Add a helper function and make the page test use it.
123
    return {
11486.2.8 by Aaron Bentley
lint fixes.
124
        'eric': eric, 'fooix': fooix, 'trunk': trunk, 'feature': feature,
9691.5.8 by Tim Penhey
Make the page test pass again, removing references to fixed urls
125
        'proposed': proposed, 'fred': fred}
8698.11.9 by Tim Penhey
New view added.
126
127
9372.1.3 by Tim Penhey
Reworked statement counting.
128
def make_linked_package_branch(factory, distribution=None,
129
                               sourcepackagename=None):
130
    """Make a new package branch and make it official."""
13597.1.1 by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint.
131
    distro_series = factory.makeDistroSeries(distribution)
9372.1.3 by Tim Penhey
Reworked statement counting.
132
    source_package = factory.makeSourcePackage(
133
        sourcepackagename=sourcepackagename, distroseries=distro_series)
134
    branch = factory.makePackageBranch(sourcepackage=source_package)
135
    pocket = PackagePublishingPocket.RELEASE
136
    # It is possible for the param to be None, so reset to the factory
137
    # generated one.
138
    sourcepackagename = source_package.sourcepackagename
13139.3.3 by Francis J. Lacoste
Remove IMakeOfficialBranchLinks non-utility.
139
    SeriesSourcePackageBranchSet.new(
9372.1.3 by Tim Penhey
Reworked statement counting.
140
        distro_series, pocket, sourcepackagename, branch, branch.owner)
141
    return branch
142
143
8698.11.9 by Tim Penhey
New view added.
144
def consistent_branch_names():
145
    """Provide a generator for getting consistent branch names.
146
147
    This generator does not finish!
148
    """
149
    for name in ['trunk', 'testing', 'feature-x', 'feature-y', 'feature-z']:
150
        yield name
151
    index = count(1)
152
    while True:
153
        yield "branch-%s" % index.next()
154
155
156
def make_package_branches(factory, series, sourcepackagename, branch_count,
157
                          official_count=0, owner=None, registrant=None):
158
    """Make some package branches.
159
160
    Make `branch_count` branches, and make `official_count` of those
161
    official branches.
162
    """
163
    if zisinstance(sourcepackagename, basestring):
164
        sourcepackagename = factory.getOrMakeSourcePackageName(
165
            sourcepackagename)
166
    # Make the branches created in the past in order.
167
    time_gen = time_counter(delta=timedelta(days=-1))
168
    branch_names = consistent_branch_names()
169
    branches = [
170
        factory.makePackageBranch(
171
            distroseries=series,
172
            sourcepackagename=sourcepackagename,
173
            date_created=time_gen.next(),
174
            name=branch_names.next(), owner=owner, registrant=registrant)
175
        for i in range(branch_count)]
176
177
    official = []
178
    # Sort the pocket items so RELEASE is last, and thus first popped.
179
    pockets = sorted(PackagePublishingPocket.items, reverse=True)
180
    # Since there can be only one link per pocket, max out the number of
181
    # official branches at the pocket count.
182
    for i in range(min(official_count, len(pockets))):
183
        branch = branches.pop()
184
        pocket = pockets.pop()
13139.3.5 by Francis J. Lacoste
Fix lint.
185
        SeriesSourcePackageBranchSet.new(
8698.11.9 by Tim Penhey
New view added.
186
            series, pocket, sourcepackagename, branch, branch.owner)
187
        official.append(branch)
188
189
    return series, branches, official
190
191
192
def make_mint_distro_with_branches(factory):
193
    """This method makes a distro called mint with many branches.
194
195
    The mint distro has the following series and status:
196
        wild - experimental
197
        dev - development
198
        stable - current
199
        old - supported
200
        very-old - supported
201
        ancient - supported
202
        mouldy - supported
203
        dead - obsolete
204
205
    The mint distro has a team: mint-team, which has Albert, Bob, and Charlie
206
    as members.
207
8747.2.1 by Tim Penhey
Docstring update.
208
    There are four different source packages:
8698.11.9 by Tim Penhey
New view added.
209
        twisted, zope, bzr, python
210
    """
211
    albert, bob, charlie = [
212
        factory.makePerson(
213
            name=name, email=("%s@mint.example.com" % name), password="test")
214
        for name in ('albert', 'bob', 'charlie')]
215
    mint_team = factory.makeTeam(owner=albert, name="mint-team")
216
    mint_team.addMember(bob, albert)
217
    mint_team.addMember(charlie, albert)
218
    mint = factory.makeDistribution(
219
        name='mint', displayname='Mint', owner=albert, members=mint_team)
220
    series = [
10054.26.1 by Adi Roiban
Refactor DistroSeriesStatus to SeriesStatus; Don't prompt for setting up translations for obsolete product series.
221
        ("wild", "5.5", SeriesStatus.EXPERIMENTAL),
222
        ("dev", "4.0", SeriesStatus.DEVELOPMENT),
223
        ("stable", "3.0", SeriesStatus.CURRENT),
224
        ("old", "2.0", SeriesStatus.SUPPORTED),
225
        ("very-old", "1.5", SeriesStatus.SUPPORTED),
226
        ("ancient", "1.0", SeriesStatus.SUPPORTED),
227
        ("mouldy", "0.6", SeriesStatus.SUPPORTED),
228
        ("dead", "0.1", SeriesStatus.OBSOLETE),
8698.11.9 by Tim Penhey
New view added.
229
        ]
230
    for name, version, status in series:
13597.1.1 by Jeroen Vermeulen
Get rid of factory.make[Ubuntu]DistroRelease. And some lint.
231
        factory.makeDistroSeries(
8698.11.9 by Tim Penhey
New view added.
232
            distribution=mint, version=version, status=status, name=name)
233
234
    for pkg_index, name in enumerate(['twisted', 'zope', 'bzr', 'python']):
9760.8.1 by Brad Crittenden
Change the non-English 'serieses' to 'series' throughout our codebase.
235
        for series_index, series in enumerate(mint.series):
8698.11.9 by Tim Penhey
New view added.
236
            # Over the series and source packages, we want to have different
237
            # combinations of official and branch counts.
238
            # Make the more recent series have most official branches.
239
            official_count = 6 - series_index
240
            branch_count = official_count + pkg_index
241
            make_package_branches(
242
                factory, series, name, branch_count, official_count,
243
                owner=mint_team, registrant=albert)
10843.3.1 by Tim Penhey
Extract the method to make an official package branch.
244
245
10843.3.5 by Tim Penhey
Allow an optional owner for the make_official_package_branch.
246
def make_official_package_branch(factory, owner=None):
10843.3.1 by Tim Penhey
Extract the method to make an official package branch.
247
    """Make a branch linked to the pocket of a source package."""
10843.3.5 by Tim Penhey
Allow an optional owner for the make_official_package_branch.
248
    branch = factory.makePackageBranch(owner=owner)
10843.3.1 by Tim Penhey
Extract the method to make an official package branch.
249
    # Make sure the (distroseries, pocket) combination used allows us to
250
    # upload to it.
251
    stable_states = (
252
        SeriesStatus.SUPPORTED, SeriesStatus.CURRENT)
253
    if branch.distroseries.status in stable_states:
254
        pocket = PackagePublishingPocket.BACKPORTS
255
    else:
256
        pocket = PackagePublishingPocket.RELEASE
257
    sourcepackage = branch.sourcepackage
258
    suite_sourcepackage = sourcepackage.getSuiteSourcePackage(pocket)
259
    registrant = factory.makePerson()
260
    run_with_login(
13139.3.8 by Francis J. Lacoste
More ubuntu_branches removal.
261
        suite_sourcepackage.distribution.owner,
10843.3.1 by Tim Penhey
Extract the method to make an official package branch.
262
        ICanHasLinkedBranch(suite_sourcepackage).setBranch,
263
        branch, registrant)
264
    return branch
11435.5.3 by Tim Penhey
Make the view work better.
265
266
267
def make_project_branch_with_revisions(factory, date_generator, product=None,
268
                                       private=None, revision_count=None):
269
    """Make a new branch with revisions."""
270
    if revision_count is None:
271
        revision_count = 5
272
    branch = factory.makeProductBranch(product=product, private=private)
273
    naked_branch = removeSecurityProxy(branch)
274
    factory.makeRevisionsForBranch(
275
        naked_branch, count=revision_count, date_generator=date_generator)
276
    # The code that updates the revision cache doesn't need to care about
277
    # the privacy of the branch.
278
    getUtility(IRevisionSet).updateRevisionCacheForBranch(naked_branch)
279
    return branch
280
281
282
def make_project_cloud_data(factory, details):
283
    """Make test data to populate the project cloud.
284
285
    Details is a list of tuples containing:
286
      (project-name, num_commits, num_authors, last_commit)
287
    """
288
    delta = timedelta(seconds=1)
289
    for project_name, num_commits, num_authors, last_commit in details:
290
        project = factory.makeProduct(name=project_name)
291
        start_date = last_commit - delta * (num_commits - 1)
292
        gen = time_counter(start_date, delta)
293
        commits_each = num_commits / num_authors
294
        for committer in range(num_authors - 1):
295
            make_project_branch_with_revisions(
296
                factory, gen, project, commits_each)
297
            num_commits -= commits_each
11435.5.6 by Tim Penhey
A test for the helper, and fix the helper.
298
        make_project_branch_with_revisions(
299
            factory, gen, project, revision_count=num_commits)
11435.5.3 by Tim Penhey
Make the view work better.
300
    transaction.commit()
11603.1.5 by Paul Hummer
Made the RecipeParser.NEWEST_VERSION monkeypatch use a contextmanager
301
302
303
@contextmanager
304
def recipe_parser_newest_version(version):
305
    old_version = RecipeParser.NEWEST_VERSION
11603.1.6 by Paul Hummer
Moved the RecipeParser.NEWEST_VERSION outside of the try/finally
306
    RecipeParser.NEWEST_VERSION = version
11603.1.5 by Paul Hummer
Made the RecipeParser.NEWEST_VERSION monkeypatch use a contextmanager
307
    try:
308
        yield
309
    finally:
310
        RecipeParser.NEWEST_VERSION = old_version
11542.3.18 by Ian Booth
Use helper method instead of factory method for bmp with no reviewer creation
311
312
11542.3.20 by Ian Booth
Test refactoring as per code review
313
def make_merge_proposal_without_reviewers(factory, **kwargs):
11542.3.18 by Ian Booth
Use helper method instead of factory method for bmp with no reviewer creation
314
    """Make a merge proposal and strip of any review votes."""
11542.3.20 by Ian Booth
Test refactoring as per code review
315
    proposal = factory.makeBranchMergeProposal(**kwargs)
11542.3.18 by Ian Booth
Use helper method instead of factory method for bmp with no reviewer creation
316
    for vote in proposal.votes:
317
        removeSecurityProxy(vote).destroySelf()
318
    return proposal
13662.5.1 by Aaron Bentley
Pushing to non-existant sourcepackagename creates.
319
320
321
def get_non_existant_source_package_branch_unique_name(owner, factory):
322
    """Return the unique name for a non-existanct source package branch.
323
324
    Neither the branch nor the source package name will exist.
325
    """
326
    distroseries = factory.makeDistroSeries()
327
    source_package = factory.getUniqueString('source-package')
328
    branch = factory.getUniqueString('branch')
329
    return '~%s/%s/%s/%s/%s' % (
330
        owner, distroseries.distribution.name, distroseries.name,
331
        source_package, branch)
14562.1.3 by William Grant
Merge databasehelpers into code
332
333
334
def remove_all_sample_data_branches():
335
    c = cursor()
336
    c.execute('delete from bugbranch')
337
    c.execute('delete from specificationbranch')
338
    c.execute('update productseries set branch=NULL')
339
    c.execute('delete from branchrevision')
340
    c.execute('delete from branchsubscription')
341
    c.execute('delete from codeimportjob')
342
    c.execute('delete from codeimport')
343
    c.execute('delete from branch')