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.17
by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
3 |
||
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
4 |
from unittest import TestLoader |
5 |
||
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
6 |
from zope.security.interfaces import Unauthorized |
7 |
||
6410.4.2
by Michael Hudson
replace assertDBIsNow with something more flexible from test_codeimportjob |
8 |
from canonical.database.constants import UTC_NOW |
11666.3.5
by Curtis Hovey
Import layers from canonical.testing.layers. |
9 |
from canonical.testing.layers import DatabaseFunctionalLayer |
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
10 |
from lp.code.enums import CodeReviewVote |
7675.429.15
by Tim Penhey
Extensive tests for reassignReview. |
11 |
from lp.code.errors import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
12 |
ClaimReviewFailed, |
13 |
ReviewNotPending, |
|
14 |
UserHasExistingReview, |
|
15 |
)
|
|
8138.1.2
by Jonathan Lange
Run migrater over lp.code. Many tests broken and imports failing. |
16 |
from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference |
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
17 |
from lp.code.tests.helpers import make_merge_proposal_without_reviewers |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
18 |
from lp.testing import ( |
19 |
login_person, |
|
20 |
TestCaseWithFactory, |
|
21 |
)
|
|
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
22 |
|
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
23 |
|
24 |
class TestCodeReviewVote(TestCaseWithFactory): |
|
25 |
||
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
26 |
layer = DatabaseFunctionalLayer |
6282.2.1
by Maris Fogels
Resolved a circular import between the testing directory and layers. |
27 |
|
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
28 |
def test_create_vote(self): |
29 |
"""CodeReviewVotes can be created"""
|
|
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
30 |
merge_proposal = make_merge_proposal_without_reviewers(self.factory) |
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
31 |
reviewer = self.factory.makePerson() |
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
32 |
login_person(merge_proposal.registrant) |
33 |
vote = merge_proposal.nominateReviewer( |
|
34 |
reviewer, merge_proposal.registrant) |
|
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
35 |
self.assertEqual(reviewer, vote.reviewer) |
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
36 |
self.assertEqual(merge_proposal.registrant, vote.registrant) |
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
37 |
self.assertEqual(merge_proposal, vote.branch_merge_proposal) |
5608.9.2
by Aaron Bentley
Change createVote to nominateReviewer, add BranchMergeProposal.votes |
38 |
self.assertEqual([vote], list(merge_proposal.votes)) |
6410.4.2
by Michael Hudson
replace assertDBIsNow with something more flexible from test_codeimportjob |
39 |
self.assertSqlAttributeEqualsDate( |
40 |
vote, 'date_created', UTC_NOW) |
|
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
41 |
self.assertProvides(vote, ICodeReviewVoteReference) |
42 |
||
43 |
||
44 |
class TestCodeReviewVoteReferenceClaimReview(TestCaseWithFactory): |
|
45 |
"""Tests for CodeReviewVoteReference.claimReview."""
|
|
46 |
||
47 |
layer = DatabaseFunctionalLayer |
|
48 |
||
49 |
def setUp(self): |
|
50 |
TestCaseWithFactory.setUp(self) |
|
51 |
# Setup the proposal, claimant and team reviewer.
|
|
52 |
self.bmp = self.factory.makeBranchMergeProposal() |
|
7675.429.16
by Tim Penhey
Move validation out into separate methods. |
53 |
self.claimant = self.factory.makePerson(name='eric') |
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
54 |
self.review_team = self.factory.makeTeam() |
55 |
||
56 |
def _addPendingReview(self): |
|
57 |
"""Add a pending review for the review_team."""
|
|
58 |
login_person(self.bmp.registrant) |
|
59 |
return self.bmp.nominateReviewer( |
|
60 |
reviewer=self.review_team, |
|
61 |
registrant=self.bmp.registrant) |
|
62 |
||
63 |
def _addClaimantToReviewTeam(self): |
|
64 |
"""Add the claimant to the review team."""
|
|
65 |
login_person(self.review_team.teamowner) |
|
66 |
self.review_team.addMember( |
|
67 |
person=self.claimant, reviewer=self.review_team.teamowner) |
|
68 |
||
69 |
def test_personal_completed_review(self): |
|
70 |
# If the claimant has a personal review already, then they can't claim
|
|
71 |
# a pending team review.
|
|
72 |
login_person(self.claimant) |
|
73 |
# Make sure that the personal review is done before the pending team
|
|
74 |
# review, otherwise the pending team review will be claimed by this
|
|
75 |
# one.
|
|
76 |
self.bmp.createComment( |
|
77 |
self.claimant, 'Message subject', 'Message content', |
|
78 |
vote=CodeReviewVote.APPROVE) |
|
79 |
review = self._addPendingReview() |
|
80 |
self._addClaimantToReviewTeam() |
|
7675.429.16
by Tim Penhey
Move validation out into separate methods. |
81 |
self.assertRaisesWithContent( |
82 |
UserHasExistingReview, |
|
83 |
'Eric (eric) has already reviewed this', |
|
84 |
review.claimReview, self.claimant) |
|
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
85 |
|
86 |
def test_personal_pending_review(self): |
|
87 |
# If the claimant has a pending review already, then they can't claim
|
|
88 |
# a pending team review.
|
|
89 |
review = self._addPendingReview() |
|
90 |
self._addClaimantToReviewTeam() |
|
91 |
login_person(self.bmp.registrant) |
|
92 |
self.bmp.nominateReviewer( |
|
93 |
reviewer=self.claimant, registrant=self.bmp.registrant) |
|
94 |
login_person(self.claimant) |
|
7675.429.16
by Tim Penhey
Move validation out into separate methods. |
95 |
self.assertRaisesWithContent( |
96 |
UserHasExistingReview, |
|
97 |
'Eric (eric) has already been asked to review this', |
|
98 |
review.claimReview, self.claimant) |
|
7675.430.3
by Tim Penhey
Move the claimReview method to the CodeReviewVoteReference. |
99 |
|
100 |
def test_personal_not_in_review_team(self): |
|
101 |
# If the claimant is not in the review team, an error is raised.
|
|
102 |
review = self._addPendingReview() |
|
103 |
# Since the claimant isn't in the review team, they don't have
|
|
104 |
# launchpad.Edit on the review itself, hence Unauthorized.
|
|
105 |
login_person(self.claimant) |
|
106 |
# Actually accessing claimReview triggers the security proxy.
|
|
107 |
self.assertRaises( |
|
108 |
Unauthorized, getattr, review, 'claimReview') |
|
109 |
# The merge proposal registrant however does have edit permissions,
|
|
110 |
# but isn't in the team, so they get ClaimReviewFailed.
|
|
111 |
login_person(self.bmp.registrant) |
|
112 |
self.assertRaises( |
|
113 |
ClaimReviewFailed, review.claimReview, self.bmp.registrant) |
|
114 |
||
115 |
def test_success(self): |
|
116 |
# If the claimant is in the review team, and does not have a personal
|
|
117 |
# review, pending or completed, then they can claim the team review.
|
|
118 |
review = self._addPendingReview() |
|
119 |
self._addClaimantToReviewTeam() |
|
120 |
login_person(self.claimant) |
|
121 |
review.claimReview(self.claimant) |
|
122 |
self.assertEqual(self.claimant, review.reviewer) |
|
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
123 |
|
12959.1.1
by Aaron Bentley
Double-claiming a review is a no-op. |
124 |
def test_repeat_claim(self): |
125 |
# Attempting to claim an already-claimed review works.
|
|
126 |
review = self.factory.makeCodeReviewVoteReference() |
|
127 |
review.claimReview(review.reviewer) |
|
128 |
||
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
129 |
|
7675.429.12
by Tim Penhey
Allow the deletion of pending reviews. |
130 |
class TestCodeReviewVoteReferenceDelete(TestCaseWithFactory): |
131 |
"""Tests for CodeReviewVoteReference.delete."""
|
|
132 |
||
133 |
layer = DatabaseFunctionalLayer |
|
134 |
||
135 |
def test_delete_pending_by_registrant(self): |
|
136 |
# A pending review can be deleted by the person requesting the review.
|
|
137 |
reviewer = self.factory.makePerson() |
|
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
138 |
bmp = make_merge_proposal_without_reviewers(self.factory) |
7675.429.12
by Tim Penhey
Allow the deletion of pending reviews. |
139 |
login_person(bmp.registrant) |
140 |
review = bmp.nominateReviewer( |
|
141 |
reviewer=reviewer, registrant=bmp.registrant) |
|
142 |
review.delete() |
|
143 |
self.assertEqual([], list(bmp.votes)) |
|
144 |
||
145 |
def test_delete_pending_by_reviewer(self): |
|
146 |
# A pending review can be deleted by the person requesting the review.
|
|
147 |
reviewer = self.factory.makePerson() |
|
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
148 |
bmp = make_merge_proposal_without_reviewers(self.factory) |
7675.429.12
by Tim Penhey
Allow the deletion of pending reviews. |
149 |
login_person(bmp.registrant) |
150 |
review = bmp.nominateReviewer( |
|
151 |
reviewer=reviewer, registrant=bmp.registrant) |
|
152 |
login_person(reviewer) |
|
153 |
review.delete() |
|
154 |
self.assertEqual([], list(bmp.votes)) |
|
155 |
||
156 |
def test_delete_pending_by_review_team_member(self): |
|
157 |
# A pending review can be deleted by the person requesting the review.
|
|
158 |
review_team = self.factory.makeTeam() |
|
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
159 |
bmp = make_merge_proposal_without_reviewers(self.factory) |
7675.429.12
by Tim Penhey
Allow the deletion of pending reviews. |
160 |
login_person(bmp.registrant) |
161 |
review = bmp.nominateReviewer( |
|
162 |
reviewer=review_team, registrant=bmp.registrant) |
|
163 |
login_person(review_team.teamowner) |
|
164 |
review.delete() |
|
165 |
self.assertEqual([], list(bmp.votes)) |
|
166 |
||
167 |
def test_delete_pending_by_target_branch_owner(self): |
|
168 |
# A pending review can be deleted by anyone with edit permissions on
|
|
169 |
# the target branch.
|
|
170 |
reviewer = self.factory.makePerson() |
|
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
171 |
bmp = make_merge_proposal_without_reviewers(self.factory) |
7675.429.12
by Tim Penhey
Allow the deletion of pending reviews. |
172 |
login_person(bmp.registrant) |
173 |
review = bmp.nominateReviewer( |
|
174 |
reviewer=reviewer, registrant=bmp.registrant) |
|
175 |
login_person(bmp.target_branch.owner) |
|
176 |
review.delete() |
|
177 |
self.assertEqual([], list(bmp.votes)) |
|
178 |
||
179 |
def test_delete_by_others_unauthorized(self): |
|
180 |
# A pending review can be deleted by the person requesting the review.
|
|
181 |
reviewer = self.factory.makePerson() |
|
182 |
bmp = self.factory.makeBranchMergeProposal() |
|
183 |
login_person(bmp.registrant) |
|
184 |
review = bmp.nominateReviewer( |
|
185 |
reviewer=reviewer, registrant=bmp.registrant) |
|
186 |
login_person(self.factory.makePerson()) |
|
187 |
self.assertRaises( |
|
188 |
Unauthorized, getattr, review, 'delete') |
|
189 |
||
190 |
def test_delete_not_pending(self): |
|
191 |
# A non-pending review reference cannot be deleted.
|
|
192 |
reviewer = self.factory.makePerson() |
|
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
193 |
bmp = make_merge_proposal_without_reviewers(self.factory) |
7675.429.12
by Tim Penhey
Allow the deletion of pending reviews. |
194 |
login_person(reviewer) |
195 |
bmp.createComment( |
|
196 |
reviewer, 'Message subject', 'Message content', |
|
197 |
vote=CodeReviewVote.APPROVE) |
|
198 |
[review] = list(bmp.votes) |
|
199 |
self.assertRaises(ReviewNotPending, review.delete) |
|
200 |
||
201 |
||
7675.429.15
by Tim Penhey
Extensive tests for reassignReview. |
202 |
class TestCodeReviewVoteReferenceReassignReview(TestCaseWithFactory): |
203 |
"""Tests for CodeReviewVoteReference.reassignReview."""
|
|
204 |
||
205 |
layer = DatabaseFunctionalLayer |
|
206 |
||
207 |
def makeMergeProposalWithReview(self, completed=False): |
|
208 |
"""Return a new merge proposal with a review."""
|
|
11542.3.26
by Ian Booth
Fix some tests after merge from trunk |
209 |
bmp = make_merge_proposal_without_reviewers(self.factory) |
7675.429.15
by Tim Penhey
Extensive tests for reassignReview. |
210 |
reviewer = self.factory.makePerson() |
211 |
if completed: |
|
212 |
login_person(reviewer) |
|
213 |
bmp.createComment( |
|
214 |
reviewer, 'Message subject', 'Message content', |
|
215 |
vote=CodeReviewVote.APPROVE) |
|
216 |
[review] = list(bmp.votes) |
|
217 |
else: |
|
218 |
login_person(bmp.registrant) |
|
219 |
review = bmp.nominateReviewer( |
|
220 |
reviewer=reviewer, registrant=bmp.registrant) |
|
221 |
return bmp, review |
|
222 |
||
223 |
def test_reassign_pending(self): |
|
224 |
# A pending review can be reassigned to someone else.
|
|
225 |
bmp, review = self.makeMergeProposalWithReview() |
|
226 |
new_reviewer = self.factory.makePerson() |
|
227 |
review.reassignReview(new_reviewer) |
|
228 |
self.assertEqual(new_reviewer, review.reviewer) |
|
229 |
||
230 |
def test_reassign_completed_review(self): |
|
231 |
# A completed review cannot be reassigned
|
|
232 |
bmp, review = self.makeMergeProposalWithReview(completed=True) |
|
233 |
self.assertRaises( |
|
234 |
ReviewNotPending, review.reassignReview, bmp.registrant) |
|
235 |
||
7675.429.16
by Tim Penhey
Move validation out into separate methods. |
236 |
def test_reassign_to_user_existing_pending(self): |
237 |
# If a user has an existing pending review, they cannot have another
|
|
7675.429.15
by Tim Penhey
Extensive tests for reassignReview. |
238 |
# pending review assigned to them.
|
239 |
bmp, review = self.makeMergeProposalWithReview() |
|
7675.429.16
by Tim Penhey
Move validation out into separate methods. |
240 |
reviewer = self.factory.makePerson(name='eric') |
12959.1.2
by Aaron Bentley
lint fixes. |
241 |
bmp.nominateReviewer(reviewer=reviewer, registrant=bmp.registrant) |
7675.429.16
by Tim Penhey
Move validation out into separate methods. |
242 |
self.assertRaisesWithContent( |
243 |
UserHasExistingReview, |
|
244 |
'Eric (eric) has already been asked to review this', |
|
245 |
review.reassignReview, reviewer) |
|
246 |
||
247 |
def test_reassign_to_user_existing_completed(self): |
|
248 |
# If a user has an existing completed review, they cannot have another
|
|
249 |
# pending review assigned to them.
|
|
250 |
bmp, review = self.makeMergeProposalWithReview() |
|
251 |
reviewer = self.factory.makePerson(name='eric') |
|
252 |
bmp.createComment( |
|
253 |
reviewer, 'Message subject', 'Message content', |
|
254 |
vote=CodeReviewVote.APPROVE) |
|
255 |
self.assertRaisesWithContent( |
|
256 |
UserHasExistingReview, |
|
257 |
'Eric (eric) has already reviewed this', |
|
258 |
review.reassignReview, reviewer) |
|
7675.429.15
by Tim Penhey
Extensive tests for reassignReview. |
259 |
|
260 |
def test_reassign_to_team_existing(self): |
|
261 |
# If a team has an existing review, they can have another pending
|
|
262 |
# review assigned to them.
|
|
263 |
bmp, review = self.makeMergeProposalWithReview() |
|
264 |
reviewer_team = self.factory.makeTeam() |
|
12959.1.2
by Aaron Bentley
lint fixes. |
265 |
bmp.nominateReviewer( |
7675.429.15
by Tim Penhey
Extensive tests for reassignReview. |
266 |
reviewer=reviewer_team, registrant=bmp.registrant) |
267 |
review.reassignReview(reviewer_team) |
|
268 |
self.assertEqual(reviewer_team, review.reviewer) |
|
269 |
||
270 |
||
5608.9.1
by Aaron Bentley
Initial cut of CodeReviewVote support |
271 |
def test_suite(): |
272 |
return TestLoader().loadTestsFromName(__name__) |