Merge lp:~thumper/launchpad/claim-review-into-model-attempt2 into lp:launchpad/db-devel

Proposed by Tim Penhey
Status: Rejected
Rejected by: Tim Penhey
Proposed branch: lp:~thumper/launchpad/claim-review-into-model-attempt2
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~thumper/launchpad/claim-review-into-model
Diff against target: 534 lines (+243/-54)
14 files modified
lib/canonical/launchpad/interfaces/_schema_circular_imports.py (+2/-0)
lib/lp/code/browser/branch.py (+1/-1)
lib/lp/code/browser/branchmergeproposal.py (+2/-2)
lib/lp/code/configure.zcml (+1/-1)
lib/lp/code/errors.py (+63/-0)
lib/lp/code/interfaces/branchmergeproposal.py (+28/-38)
lib/lp/code/interfaces/codereviewvote.py (+4/-1)
lib/lp/code/mail/codehandler.py (+2/-2)
lib/lp/code/model/branch.py (+3/-2)
lib/lp/code/model/branchmergeproposal.py (+36/-3)
lib/lp/code/model/codereviewvote.py (+6/-0)
lib/lp/code/model/tests/test_branch.py (+2/-2)
lib/lp/code/model/tests/test_branchmergeproposals.py (+90/-2)
lib/lp/code/stories/webservice/xx-branchmergeproposal.txt (+3/-0)
To merge this branch: bzr merge lp:~thumper/launchpad/claim-review-into-model-attempt2
Reviewer Review Type Date Requested Status
Canonical Launchpad Engineering Pending
Review via email: mp+15718@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

Moves the logic of actually claiming a review into the model code itself and exposes it over the api.

This branch also creates a lp.code.errors module to hold our errors, like the lp.code.enums.

tests:
  TestBranchMergeProposalClaimReview

and for the is_pending bit:
  webservice/xx-branchmergeproposal

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

I'm going to change the approach and make claimReview on the CodeReviewVoteReference.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
2--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2009-11-06 21:06:38 +0000
3+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py 2009-12-06 23:36:19 +0000
4@@ -111,6 +111,8 @@
5 IBranchMergeProposal['all_comments'].value_type.schema = ICodeReviewComment
6 IBranchMergeProposal['nominateReviewer'].queryTaggedValue(
7 LAZR_WEBSERVICE_EXPORTED)['return_type'].schema = ICodeReviewVoteReference
8+IBranchMergeProposal['claimReview'].queryTaggedValue(
9+ LAZR_WEBSERVICE_EXPORTED)['return_type'].schema = ICodeReviewVoteReference
10 IBranchMergeProposal['votes'].value_type.schema = ICodeReviewVoteReference
11
12 IHasBranches['getBranches'].queryTaggedValue(
13
14=== modified file 'lib/lp/code/browser/branch.py'
15--- lib/lp/code/browser/branch.py 2009-11-25 23:25:51 +0000
16+++ lib/lp/code/browser/branch.py 2009-12-06 23:36:18 +0000
17@@ -80,10 +80,10 @@
18 latest_proposals_for_each_branch)
19 from lp.code.enums import (
20 BranchLifecycleStatus, BranchType, UICreatableBranchType)
21+from lp.code.errors import InvalidBranchMergeProposal
22 from lp.code.interfaces.branch import (
23 BranchCreationForbidden, BranchExists, IBranch,
24 user_has_special_branch_access)
25-from lp.code.interfaces.branchmergeproposal import InvalidBranchMergeProposal
26 from lp.code.interfaces.branchtarget import IBranchTarget
27 from lp.code.interfaces.codeimport import CodeImportReviewStatus
28 from lp.code.interfaces.codeimportjob import (
29
30=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
31--- lib/lp/code/browser/branchmergeproposal.py 2009-11-24 01:53:32 +0000
32+++ lib/lp/code/browser/branchmergeproposal.py 2009-12-06 23:36:19 +0000
33@@ -71,8 +71,8 @@
34 from lp.code.enums import (
35 BranchMergeProposalStatus, BranchType, CodeReviewNotificationLevel,
36 CodeReviewVote)
37-from lp.code.interfaces.branchmergeproposal import (
38- IBranchMergeProposal, WrongBranchMergeProposal)
39+from lp.code.errors import WrongBranchMergeProposal
40+from lp.code.interfaces.branchmergeproposal import IBranchMergeProposal
41 from lp.code.interfaces.codereviewcomment import ICodeReviewComment
42 from lp.code.interfaces.codereviewvote import (
43 ICodeReviewVoteReference)
44
45=== modified file 'lib/lp/code/configure.zcml'
46--- lib/lp/code/configure.zcml 2009-11-16 22:53:42 +0000
47+++ lib/lp/code/configure.zcml 2009-12-06 23:36:18 +0000
48@@ -257,7 +257,7 @@
49 updatePreviewDiff"/>
50 <require
51 permission="launchpad.AnyPerson"
52- attributes="
53+ attributes="claimReview
54 createComment
55 createCommentFromMessage"/>
56 </class>
57
58=== added file 'lib/lp/code/errors.py'
59--- lib/lp/code/errors.py 1970-01-01 00:00:00 +0000
60+++ lib/lp/code/errors.py 2009-12-06 23:36:18 +0000
61@@ -0,0 +1,63 @@
62+# Copyright 2009 Canonical Ltd. This software is licensed under the
63+# GNU Affero General Public License version 3 (see the file LICENSE).
64+
65+"""Errors used in the lp/code modules."""
66+
67+__metaclass__ = type
68+__all__ = [
69+ 'BadBranchMergeProposalSearchContext',
70+ 'BadStateTransition',
71+ 'BranchMergeProposalExists',
72+ 'ClaimantHasPersonalReview',
73+ 'ClaimantNotInReviewerTeam',
74+ 'InvalidBranchMergeProposal',
75+ 'NoSuchReview',
76+ 'UserNotBranchReviewer',
77+ 'WrongBranchMergeProposal',
78+]
79+
80+
81+class BadBranchMergeProposalSearchContext(Exception):
82+ """The context is not valid for a branch merge proposal search."""
83+
84+
85+class BadStateTransition(Exception):
86+ """The user requested a state transition that is not possible."""
87+
88+
89+class ClaimantHasPersonalReview(Exception):
90+ """The claimant already has a personal review. """
91+
92+
93+class ClaimantNotInReviewerTeam(Exception):
94+ """The claimant is not in the reviewer team."""
95+
96+
97+class InvalidBranchMergeProposal(Exception):
98+ """Raised during the creation of a new branch merge proposal.
99+
100+ The text of the exception is the rule violation.
101+ """
102+
103+
104+class BranchMergeProposalExists(InvalidBranchMergeProposal):
105+ """Raised if there is already a matching BranchMergeProposal."""
106+
107+
108+class NoSuchReview(Exception):
109+ """There is no review found for the reviewer."""
110+
111+
112+class UserNotBranchReviewer(Exception):
113+ """The user who attempted to review the merge proposal isn't a reviewer.
114+
115+ A specific reviewer may be set on a branch. If a specific reviewer
116+ isn't set then any user in the team of the owner of the branch is
117+ considered a reviewer.
118+ """
119+
120+
121+class WrongBranchMergeProposal(Exception):
122+ """The comment requested is not associated with this merge proposal."""
123+
124+
125
126=== modified file 'lib/lp/code/interfaces/branchmergeproposal.py'
127--- lib/lp/code/interfaces/branchmergeproposal.py 2009-10-23 00:48:47 +0000
128+++ lib/lp/code/interfaces/branchmergeproposal.py 2009-12-06 23:36:18 +0000
129@@ -7,11 +7,7 @@
130
131 __metaclass__ = type
132 __all__ = [
133- 'BadBranchMergeProposalSearchContext',
134- 'BadStateTransition',
135- 'BranchMergeProposalExists',
136 'BRANCH_MERGE_PROPOSAL_FINAL_STATES',
137- 'InvalidBranchMergeProposal',
138 'IBranchMergeProposal',
139 'IBranchMergeProposalGetter',
140 'IBranchMergeProposalJob',
141@@ -20,10 +16,9 @@
142 'ICreateMergeProposalJobSource',
143 'IMergeProposalCreatedJob',
144 'IMergeProposalCreatedJobSource',
145- 'UserNotBranchReviewer',
146- 'WrongBranchMergeProposal',
147 ]
148
149+
150 from lazr.lifecycle.event import ObjectModifiedEvent
151 from zope.event import notify
152 from zope.interface import Attribute, Interface
153@@ -47,38 +42,6 @@
154 REQUEST_USER)
155
156
157-class InvalidBranchMergeProposal(Exception):
158- """Raised during the creation of a new branch merge proposal.
159-
160- The text of the exception is the rule violation.
161- """
162-
163-
164-class BranchMergeProposalExists(InvalidBranchMergeProposal):
165- """Raised if there is already a matching BranchMergeProposal."""
166-
167-
168-class UserNotBranchReviewer(Exception):
169- """The user who attempted to review the merge proposal isn't a reviewer.
170-
171- A specific reviewer may be set on a branch. If a specific reviewer
172- isn't set then any user in the team of the owner of the branch is
173- considered a reviewer.
174- """
175-
176-
177-class BadStateTransition(Exception):
178- """The user requested a state transition that is not possible."""
179-
180-
181-class WrongBranchMergeProposal(Exception):
182- """The comment requested is not associated with this merge proposal."""
183-
184-
185-class BadBranchMergeProposalSearchContext(Exception):
186- """The context is not valid for a branch merge proposal search."""
187-
188-
189 BRANCH_MERGE_PROPOSAL_FINAL_STATES = (
190 BranchMergeProposalStatus.REJECTED,
191 BranchMergeProposalStatus.MERGED,
192@@ -445,6 +408,33 @@
193 the details are updated.
194 """
195
196+ @operation_parameters(
197+ reviewer=Reference(
198+ title=_("A team with an existing pending review."),
199+ schema=IPerson),
200+ review_type=Text())
201+ @call_with(claimant=REQUEST_USER)
202+ @operation_returns_entry(Interface) # Really ICodeReviewVoteReference
203+ @export_write_operation()
204+ def claimReview(claimant, reviewer, review_type=None):
205+ """Change a pending review for reviewer into a review for claimant.
206+
207+ Pending team reviews can be claimed by members of that team. This
208+ allows reviews to be moved of the general team todo list, and onto a
209+ personal todo list.
210+
211+ :param claimant: The person claiming the team review.
212+ :param reviewer: The team with a pending review.
213+ :param review_type: The review_type of the pending review.
214+ :return: The updated `CodeReviewVoteReference`.
215+ :raises ClaimantHasPersonalReview: If the claimant already has a
216+ personal review.
217+ :raises ClaimantNotInReviewerTeam: If the claimant is not in the
218+ reviewer team.
219+ :raises NoSuchReview: If there is no review found for the reviewer
220+ with the specified review_type.
221+ """
222+
223 def getUsersVoteReference(user):
224 """Get the existing vote reference for the given user.
225
226
227=== modified file 'lib/lp/code/interfaces/codereviewvote.py'
228--- lib/lp/code/interfaces/codereviewvote.py 2009-10-09 04:15:55 +0000
229+++ lib/lp/code/interfaces/codereviewvote.py 2009-12-06 23:36:19 +0000
230@@ -9,7 +9,7 @@
231 ]
232
233 from zope.interface import Interface
234-from zope.schema import Datetime, Int, TextLine
235+from zope.schema import Bool, Datetime, Int, TextLine
236
237 from canonical.launchpad import _
238 from canonical.launchpad.fields import PublicPersonChoice
239@@ -66,3 +66,6 @@
240 "The code review comment that contains the most recent vote."
241 ),
242 required=True, schema=ICodeReviewComment))
243+
244+ is_pending = exported(
245+ Bool(title=_("Is the pending?"), required=True, readonly=True))
246
247=== modified file 'lib/lp/code/mail/codehandler.py'
248--- lib/lp/code/mail/codehandler.py 2009-10-23 19:33:09 +0000
249+++ lib/lp/code/mail/codehandler.py 2009-12-06 23:36:18 +0000
250@@ -36,10 +36,10 @@
251 from canonical.launchpad.webapp.interfaces import ILaunchBag
252 from lazr.uri import URI
253 from lp.code.enums import BranchType, CodeReviewVote
254+from lp.code.errors import BranchMergeProposalExists, UserNotBranchReviewer
255 from lp.code.interfaces.branchlookup import IBranchLookup
256 from lp.code.interfaces.branchmergeproposal import (
257- BranchMergeProposalExists, IBranchMergeProposalGetter,
258- ICreateMergeProposalJobSource, UserNotBranchReviewer)
259+ IBranchMergeProposalGetter, ICreateMergeProposalJobSource)
260 from lp.code.interfaces.branchnamespace import (
261 lookup_branch_namespace, split_unique_name)
262 from lp.code.interfaces.branchtarget import check_default_stacked_on
263
264=== modified file 'lib/lp/code/model/branch.py'
265--- lib/lp/code/model/branch.py 2009-11-26 22:55:06 +0000
266+++ lib/lp/code/model/branch.py 2009-12-06 23:36:19 +0000
267@@ -47,6 +47,8 @@
268 from lp.code.enums import (
269 BranchLifecycleStatus, BranchMergeControlStatus,
270 BranchMergeProposalStatus, BranchType)
271+from lp.code.errors import (
272+ BranchMergeProposalExists, InvalidBranchMergeProposal)
273 from lp.code.mail.branch import send_branch_modified_notifications
274 from lp.code.model.branchmergeproposal import (
275 BranchMergeProposal, BranchMergeProposalGetter)
276@@ -63,8 +65,7 @@
277 from lp.code.interfaces.branchcollection import IAllBranches
278 from lp.code.interfaces.branchlookup import IBranchLookup
279 from lp.code.interfaces.branchmergeproposal import (
280- BRANCH_MERGE_PROPOSAL_FINAL_STATES, BranchMergeProposalExists,
281- InvalidBranchMergeProposal)
282+ BRANCH_MERGE_PROPOSAL_FINAL_STATES)
283 from lp.code.interfaces.branchnamespace import IBranchNamespacePolicy
284 from lp.code.interfaces.branchpuller import IBranchPuller
285 from lp.code.interfaces.branchtarget import IBranchTarget
286
287=== modified file 'lib/lp/code/model/branchmergeproposal.py'
288--- lib/lp/code/model/branchmergeproposal.py 2009-12-06 23:36:17 +0000
289+++ lib/lp/code/model/branchmergeproposal.py 2009-12-06 23:36:18 +0000
290@@ -30,6 +30,10 @@
291 from canonical.database.sqlbase import quote, SQLBase, sqlvalues
292
293 from lp.code.enums import BranchMergeProposalStatus, CodeReviewVote
294+from lp.code.errors import (
295+ BadBranchMergeProposalSearchContext, BadStateTransition,
296+ ClaimantHasPersonalReview, ClaimantNotInReviewerTeam, NoSuchReview,
297+ UserNotBranchReviewer, WrongBranchMergeProposal)
298 from lp.code.model.branchrevision import BranchRevision
299 from lp.code.model.codereviewcomment import CodeReviewComment
300 from lp.code.model.codereviewvote import (
301@@ -42,10 +46,8 @@
302 from lp.code.interfaces.branch import IBranchNavigationMenu
303 from lp.code.interfaces.branchcollection import IAllBranches
304 from lp.code.interfaces.branchmergeproposal import (
305- BadBranchMergeProposalSearchContext, BadStateTransition,
306 BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
307- IBranchMergeProposal, IBranchMergeProposalGetter, UserNotBranchReviewer,
308- WrongBranchMergeProposal)
309+ IBranchMergeProposal, IBranchMergeProposalGetter)
310 from lp.code.interfaces.branchtarget import IHasBranchTarget
311 from lp.registry.interfaces.person import IPerson
312 from lp.registry.interfaces.product import IProduct
313@@ -538,6 +540,37 @@
314 notify(ReviewerNominatedEvent(vote_reference))
315 return vote_reference
316
317+ def claimReview(self, claimant, reviewer, review_type=None):
318+ """See `IBranchMergeProposal`."""
319+ review_type = self._normalizeReviewType(review_type)
320+ vote_reference = self.getUsersVoteReference(reviewer, review_type)
321+ if vote_reference is None:
322+ if review_type is None:
323+ error_str = 'No review found for %(reviewer)s'
324+ else:
325+ error_str = (
326+ 'No "%(review_type)s" review found for %(reviewer)s')
327+ raise NoSuchReview(
328+ error_str % {
329+ 'reviewer': reviewer.unique_displayname,
330+ 'review_type': review_type})
331+ claimant_review = self.getUsersVoteReference(claimant)
332+ if claimant_review is not None:
333+ if claimant_review.is_pending:
334+ error_str = '%s has an existing pending review'
335+ else:
336+ error_str = '%s has an existing personal review'
337+ raise ClaimantHasPersonalReview(
338+ error_str % claimant.unique_displayname)
339+ if not claimant.inTeam(reviewer):
340+ raise ClaimantNotInReviewerTeam(
341+ '%s is not a member of %s' %
342+ (claimant.unique_displayname, reviewer.unique_displayname))
343+ # If we get to here then the claimant is allowed to claim the team
344+ # review.
345+ vote_reference.reviewer = claimant
346+ return vote_reference
347+
348 def deleteProposal(self):
349 """See `IBranchMergeProposal`."""
350 # Delete this proposal, but keep the superseded chain linked.
351
352=== modified file 'lib/lp/code/model/codereviewvote.py'
353--- lib/lp/code/model/codereviewvote.py 2009-06-25 04:06:00 +0000
354+++ lib/lp/code/model/codereviewvote.py 2009-12-06 23:36:19 +0000
355@@ -36,3 +36,9 @@
356 review_type = StringCol(default=None)
357 comment = ForeignKey(
358 dbName='vote_message', foreignKey='CodeReviewComment', default=None)
359+
360+ @property
361+ def is_pending(self):
362+ """See `ICodeReviewVote`"""
363+ # Reviews are pending if there is no associated comment.
364+ return self.comment is None
365
366=== modified file 'lib/lp/code/model/tests/test_branch.py'
367--- lib/lp/code/model/tests/test_branch.py 2009-11-25 23:24:58 +0000
368+++ lib/lp/code/model/tests/test_branch.py 2009-12-06 23:36:19 +0000
369@@ -37,6 +37,7 @@
370 from lp.code.enums import (
371 BranchLifecycleStatus, BranchSubscriptionNotificationLevel, BranchType,
372 BranchVisibilityRule, CodeReviewNotificationLevel)
373+from lp.code.errors import InvalidBranchMergeProposal
374 from lp.code.interfaces.branch import (
375 BranchCannotBePrivate, BranchCannotBePublic,
376 BranchCreatorNotMemberOfOwnerTeam, BranchCreatorNotOwner,
377@@ -45,8 +46,7 @@
378 from lp.code.interfaces.branchlookup import IBranchLookup
379 from lp.code.interfaces.branchnamespace import IBranchNamespaceSet
380 from lp.code.interfaces.branchmergeproposal import (
381- BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
382- InvalidBranchMergeProposal)
383+ BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES)
384 from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
385 from lp.code.interfaces.seriessourcepackagebranch import (
386 IFindOfficialBranchLinks)
387
388=== modified file 'lib/lp/code/model/tests/test_branchmergeproposals.py'
389--- lib/lp/code/model/tests/test_branchmergeproposals.py 2009-12-06 23:36:17 +0000
390+++ lib/lp/code/model/tests/test_branchmergeproposals.py 2009-12-06 23:36:19 +0000
391@@ -26,6 +26,9 @@
392 from canonical.launchpad.interfaces import IPrivacy
393 from canonical.launchpad.interfaces.message import IMessageJob
394 from canonical.launchpad.webapp.testing import verifyObject
395+from lp.code.errors import (
396+ BadStateTransition, ClaimantHasPersonalReview, ClaimantNotInReviewerTeam,
397+ NoSuchReview, WrongBranchMergeProposal)
398 from lp.code.event.branchmergeproposal import (
399 NewBranchMergeProposalEvent, NewCodeReviewCommentEvent,
400 ReviewerNominatedEvent)
401@@ -36,11 +39,10 @@
402 BranchType, CodeReviewNotificationLevel, CodeReviewVote,
403 BranchVisibilityRule)
404 from lp.code.interfaces.branchmergeproposal import (
405- BadStateTransition,
406 BRANCH_MERGE_PROPOSAL_FINAL_STATES as FINAL_STATES,
407 IBranchMergeProposal, IBranchMergeProposalGetter, IBranchMergeProposalJob,
408 ICreateMergeProposalJob, ICreateMergeProposalJobSource,
409- IMergeProposalCreatedJob, notify_modified, WrongBranchMergeProposal)
410+ IMergeProposalCreatedJob, notify_modified)
411 from lp.code.model.branchmergeproposaljob import (
412 BranchMergeProposalJob, BranchMergeProposalJobType,
413 CreateMergeProposalJob, MergeProposalCreatedJob, UpdatePreviewDiffJob)
414@@ -1682,6 +1684,92 @@
415 # Still only one vote.
416 self.assertEqual(1, len(list(merge_proposal.votes)))
417
418+
419+class TestBranchMergeProposalClaimReview(TestCaseWithFactory):
420+ """Tests for BranchMergeProposal.claimReview."""
421+
422+ layer = DatabaseFunctionalLayer
423+
424+ def setUp(self):
425+ TestCaseWithFactory.setUp(self)
426+ # Setup the proposal, claimant and team reviewer.
427+ self.bmp = self.factory.makeBranchMergeProposal()
428+ self.claimant = self.factory.makePerson()
429+ self.review_team = self.factory.makeTeam()
430+
431+ def test_missing_review(self):
432+ # If no matching review is found, an exception is raised.
433+ login_person(self.claimant)
434+ self.assertRaises(
435+ NoSuchReview,
436+ self.bmp.claimReview,
437+ self.claimant, self.review_team)
438+
439+ def _addPendingReview(self, review_type=None):
440+ """Add a pending review for the review_team."""
441+ login_person(self.bmp.registrant)
442+ self.bmp.nominateReviewer(
443+ reviewer=self.review_team,
444+ registrant=self.bmp.registrant,
445+ review_type=review_type)
446+
447+ def _addClaimantToReviewTeam(self):
448+ """Add the claimant to the review team."""
449+ login_person(self.review_team.teamowner)
450+ self.review_team.addMember(
451+ person=self.claimant, reviewer=self.review_team.teamowner)
452+
453+ def test_personal_completed_review(self):
454+ # If the claimant has a personal review already, then they can't claim
455+ # a pending team review.
456+ login_person(self.claimant)
457+ # Make sure that the personal review is done before the pending team
458+ # review, otherwise the pending team review will be claimed by this
459+ # one.
460+ self.bmp.createComment(
461+ self.claimant, 'Message subject', 'Message content',
462+ vote=CodeReviewVote.APPROVE)
463+ self._addPendingReview()
464+ self._addClaimantToReviewTeam()
465+ self.assertRaises(
466+ ClaimantHasPersonalReview,
467+ self.bmp.claimReview,
468+ self.claimant, self.review_team)
469+
470+ def test_personal_pending_review(self):
471+ # If the claimant has a pending review already, then they can't claim
472+ # a pending team review.
473+ self._addPendingReview()
474+ self._addClaimantToReviewTeam()
475+ login_person(self.bmp.registrant)
476+ self.bmp.nominateReviewer(
477+ reviewer=self.claimant,
478+ registrant=self.bmp.registrant)
479+ login_person(self.claimant)
480+ self.assertRaises(
481+ ClaimantHasPersonalReview,
482+ self.bmp.claimReview,
483+ self.claimant, self.review_team)
484+
485+ def test_personal_not_in_review_team(self):
486+ # If the claimant is not in the review team, an error is raised.
487+ self._addPendingReview()
488+ login_person(self.claimant)
489+ self.assertRaises(
490+ ClaimantNotInReviewerTeam,
491+ self.bmp.claimReview,
492+ self.claimant, self.review_team)
493+
494+ def test_success(self):
495+ # If the claimant is in the review team, and does not have a personal
496+ # review, pending or completed, then they can claim the team review.
497+ self._addPendingReview()
498+ self._addClaimantToReviewTeam()
499+ login_person(self.claimant)
500+ result = self.bmp.claimReview(self.claimant, self.review_team)
501+ self.assertEqual(self.claimant, result.reviewer)
502+
503+
504 class TestBranchMergeProposalResubmit(TestCaseWithFactory):
505
506 layer = DatabaseFunctionalLayer
507
508=== modified file 'lib/lp/code/stories/webservice/xx-branchmergeproposal.txt'
509--- lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2009-11-05 21:36:14 +0000
510+++ lib/lp/code/stories/webservice/xx-branchmergeproposal.txt 2009-12-06 23:36:19 +0000
511@@ -79,6 +79,7 @@
512 branch_merge_proposal_link: u'http://api.launchpad.dev/beta/~.../+merge/...'
513 comment_link: None
514 date_created: u'...'
515+ is_pending: True
516 registrant_link: u'http://api.launchpad.dev/beta/~person-name...'
517 resource_type_link: u'http://api.launchpad.dev/beta/#code_review_vote_reference'
518 review_type: u'green'
519@@ -194,6 +195,7 @@
520 branch_merge_proposal_link: u'http://.../~source/fooix/fix-it/+merge/...'
521 comment_link: u'http://.../~source/fooix/fix-it/+merge/.../comments/...'
522 date_created: u'...'
523+ is_pending: False
524 registrant_link: u'http://.../~person-name...'
525 resource_type_link: u'http://.../#code_review_vote_reference'
526 review_type: u'code'
527@@ -221,6 +223,7 @@
528 branch_merge_proposal_link: u'http://.../~source/fooix/fix-it/+merge/...'
529 comment_link: None
530 date_created: u'...'
531+ is_pending: True
532 registrant_link: u'http://.../~target'
533 resource_type_link: u'http://.../#code_review_vote_reference'
534 review_type: u'code'

Subscribers

People subscribed via source and target branches

to status/vote changes: