~launchpad-pqm/launchpad/devel

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