##// END OF EJS Templates
tests: Add test to check the link to the shadow repo of a PR.
Martin Bornhold -
r1047:f58888bc default
parent child Browse files
Show More
@@ -1,948 +1,977 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import mock
21 import mock
22 import pytest
22 import pytest
23 from webob.exc import HTTPNotFound
23 from webob.exc import HTTPNotFound
24
24
25 import rhodecode
25 import rhodecode
26 from rhodecode.lib.vcs.nodes import FileNode
26 from rhodecode.lib.vcs.nodes import FileNode
27 from rhodecode.model.changeset_status import ChangesetStatusModel
27 from rhodecode.model.changeset_status import ChangesetStatusModel
28 from rhodecode.model.db import (
28 from rhodecode.model.db import (
29 PullRequest, ChangesetStatus, UserLog, Notification)
29 PullRequest, ChangesetStatus, UserLog, Notification)
30 from rhodecode.model.meta import Session
30 from rhodecode.model.meta import Session
31 from rhodecode.model.pull_request import PullRequestModel
31 from rhodecode.model.pull_request import PullRequestModel
32 from rhodecode.model.user import UserModel
32 from rhodecode.model.user import UserModel
33 from rhodecode.tests import assert_session_flash, url, TEST_USER_ADMIN_LOGIN
33 from rhodecode.tests import assert_session_flash, url, TEST_USER_ADMIN_LOGIN
34 from rhodecode.tests.utils import AssertResponse
34 from rhodecode.tests.utils import AssertResponse
35
35
36
36
37 @pytest.mark.usefixtures('app', 'autologin_user')
37 @pytest.mark.usefixtures('app', 'autologin_user')
38 @pytest.mark.backends("git", "hg")
38 @pytest.mark.backends("git", "hg")
39 class TestPullrequestsController:
39 class TestPullrequestsController:
40
40
41 def test_index(self, backend):
41 def test_index(self, backend):
42 self.app.get(url(
42 self.app.get(url(
43 controller='pullrequests', action='index',
43 controller='pullrequests', action='index',
44 repo_name=backend.repo_name))
44 repo_name=backend.repo_name))
45
45
46 def test_option_menu_create_pull_request_exists(self, backend):
46 def test_option_menu_create_pull_request_exists(self, backend):
47 repo_name = backend.repo_name
47 repo_name = backend.repo_name
48 response = self.app.get(url('summary_home', repo_name=repo_name))
48 response = self.app.get(url('summary_home', repo_name=repo_name))
49
49
50 create_pr_link = '<a href="%s">Create Pull Request</a>' % url(
50 create_pr_link = '<a href="%s">Create Pull Request</a>' % url(
51 'pullrequest', repo_name=repo_name)
51 'pullrequest', repo_name=repo_name)
52 response.mustcontain(create_pr_link)
52 response.mustcontain(create_pr_link)
53
53
54 def test_global_redirect_of_pr(self, backend, pr_util):
54 def test_global_redirect_of_pr(self, backend, pr_util):
55 pull_request = pr_util.create_pull_request()
55 pull_request = pr_util.create_pull_request()
56
56
57 response = self.app.get(
57 response = self.app.get(
58 url('pull_requests_global',
58 url('pull_requests_global',
59 pull_request_id=pull_request.pull_request_id))
59 pull_request_id=pull_request.pull_request_id))
60
60
61 repo_name = pull_request.target_repo.repo_name
61 repo_name = pull_request.target_repo.repo_name
62 redirect_url = url('pullrequest_show', repo_name=repo_name,
62 redirect_url = url('pullrequest_show', repo_name=repo_name,
63 pull_request_id=pull_request.pull_request_id)
63 pull_request_id=pull_request.pull_request_id)
64 assert response.status == '302 Found'
64 assert response.status == '302 Found'
65 assert redirect_url in response.location
65 assert redirect_url in response.location
66
66
67 def test_create_pr_form_with_raw_commit_id(self, backend):
67 def test_create_pr_form_with_raw_commit_id(self, backend):
68 repo = backend.repo
68 repo = backend.repo
69
69
70 self.app.get(
70 self.app.get(
71 url(controller='pullrequests', action='index',
71 url(controller='pullrequests', action='index',
72 repo_name=repo.repo_name,
72 repo_name=repo.repo_name,
73 commit=repo.get_commit().raw_id),
73 commit=repo.get_commit().raw_id),
74 status=200)
74 status=200)
75
75
76 @pytest.mark.parametrize('pr_merge_enabled', [True, False])
76 @pytest.mark.parametrize('pr_merge_enabled', [True, False])
77 def test_show(self, pr_util, pr_merge_enabled):
77 def test_show(self, pr_util, pr_merge_enabled):
78 pull_request = pr_util.create_pull_request(
78 pull_request = pr_util.create_pull_request(
79 mergeable=pr_merge_enabled, enable_notifications=False)
79 mergeable=pr_merge_enabled, enable_notifications=False)
80
80
81 response = self.app.get(url(
81 response = self.app.get(url(
82 controller='pullrequests', action='show',
82 controller='pullrequests', action='show',
83 repo_name=pull_request.target_repo.scm_instance().name,
83 repo_name=pull_request.target_repo.scm_instance().name,
84 pull_request_id=str(pull_request.pull_request_id)))
84 pull_request_id=str(pull_request.pull_request_id)))
85
85
86 for commit_id in pull_request.revisions:
86 for commit_id in pull_request.revisions:
87 response.mustcontain(commit_id)
87 response.mustcontain(commit_id)
88
88
89 assert pull_request.target_ref_parts.type in response
89 assert pull_request.target_ref_parts.type in response
90 assert pull_request.target_ref_parts.name in response
90 assert pull_request.target_ref_parts.name in response
91 target_clone_url = pull_request.target_repo.clone_url()
91 target_clone_url = pull_request.target_repo.clone_url()
92 assert target_clone_url in response
92 assert target_clone_url in response
93
93
94 assert 'class="pull-request-merge"' in response
94 assert 'class="pull-request-merge"' in response
95 assert (
95 assert (
96 'Server-side pull request merging is disabled.'
96 'Server-side pull request merging is disabled.'
97 in response) != pr_merge_enabled
97 in response) != pr_merge_enabled
98
98
99 def test_close_status_visibility(self, pr_util, csrf_token):
99 def test_close_status_visibility(self, pr_util, csrf_token):
100 from rhodecode.tests.functional.test_login import login_url, logut_url
100 from rhodecode.tests.functional.test_login import login_url, logut_url
101 # Logout
101 # Logout
102 response = self.app.post(
102 response = self.app.post(
103 logut_url,
103 logut_url,
104 params={'csrf_token': csrf_token})
104 params={'csrf_token': csrf_token})
105 # Login as regular user
105 # Login as regular user
106 response = self.app.post(login_url,
106 response = self.app.post(login_url,
107 {'username': 'test_regular',
107 {'username': 'test_regular',
108 'password': 'test12'})
108 'password': 'test12'})
109
109
110 pull_request = pr_util.create_pull_request(author='test_regular')
110 pull_request = pr_util.create_pull_request(author='test_regular')
111
111
112 response = self.app.get(url(
112 response = self.app.get(url(
113 controller='pullrequests', action='show',
113 controller='pullrequests', action='show',
114 repo_name=pull_request.target_repo.scm_instance().name,
114 repo_name=pull_request.target_repo.scm_instance().name,
115 pull_request_id=str(pull_request.pull_request_id)))
115 pull_request_id=str(pull_request.pull_request_id)))
116
116
117 assert 'Server-side pull request merging is disabled.' in response
117 assert 'Server-side pull request merging is disabled.' in response
118 assert 'value="forced_closed"' in response
118 assert 'value="forced_closed"' in response
119
119
120 def test_show_invalid_commit_id(self, pr_util):
120 def test_show_invalid_commit_id(self, pr_util):
121 # Simulating invalid revisions which will cause a lookup error
121 # Simulating invalid revisions which will cause a lookup error
122 pull_request = pr_util.create_pull_request()
122 pull_request = pr_util.create_pull_request()
123 pull_request.revisions = ['invalid']
123 pull_request.revisions = ['invalid']
124 Session().add(pull_request)
124 Session().add(pull_request)
125 Session().commit()
125 Session().commit()
126
126
127 response = self.app.get(url(
127 response = self.app.get(url(
128 controller='pullrequests', action='show',
128 controller='pullrequests', action='show',
129 repo_name=pull_request.target_repo.scm_instance().name,
129 repo_name=pull_request.target_repo.scm_instance().name,
130 pull_request_id=str(pull_request.pull_request_id)))
130 pull_request_id=str(pull_request.pull_request_id)))
131
131
132 for commit_id in pull_request.revisions:
132 for commit_id in pull_request.revisions:
133 response.mustcontain(commit_id)
133 response.mustcontain(commit_id)
134
134
135 def test_show_invalid_source_reference(self, pr_util):
135 def test_show_invalid_source_reference(self, pr_util):
136 pull_request = pr_util.create_pull_request()
136 pull_request = pr_util.create_pull_request()
137 pull_request.source_ref = 'branch:b:invalid'
137 pull_request.source_ref = 'branch:b:invalid'
138 Session().add(pull_request)
138 Session().add(pull_request)
139 Session().commit()
139 Session().commit()
140
140
141 self.app.get(url(
141 self.app.get(url(
142 controller='pullrequests', action='show',
142 controller='pullrequests', action='show',
143 repo_name=pull_request.target_repo.scm_instance().name,
143 repo_name=pull_request.target_repo.scm_instance().name,
144 pull_request_id=str(pull_request.pull_request_id)))
144 pull_request_id=str(pull_request.pull_request_id)))
145
145
146 def test_edit_title_description(self, pr_util, csrf_token):
146 def test_edit_title_description(self, pr_util, csrf_token):
147 pull_request = pr_util.create_pull_request()
147 pull_request = pr_util.create_pull_request()
148 pull_request_id = pull_request.pull_request_id
148 pull_request_id = pull_request.pull_request_id
149
149
150 response = self.app.post(
150 response = self.app.post(
151 url(controller='pullrequests', action='update',
151 url(controller='pullrequests', action='update',
152 repo_name=pull_request.target_repo.repo_name,
152 repo_name=pull_request.target_repo.repo_name,
153 pull_request_id=str(pull_request_id)),
153 pull_request_id=str(pull_request_id)),
154 params={
154 params={
155 'edit_pull_request': 'true',
155 'edit_pull_request': 'true',
156 '_method': 'put',
156 '_method': 'put',
157 'title': 'New title',
157 'title': 'New title',
158 'description': 'New description',
158 'description': 'New description',
159 'csrf_token': csrf_token})
159 'csrf_token': csrf_token})
160
160
161 assert_session_flash(
161 assert_session_flash(
162 response, u'Pull request title & description updated.',
162 response, u'Pull request title & description updated.',
163 category='success')
163 category='success')
164
164
165 pull_request = PullRequest.get(pull_request_id)
165 pull_request = PullRequest.get(pull_request_id)
166 assert pull_request.title == 'New title'
166 assert pull_request.title == 'New title'
167 assert pull_request.description == 'New description'
167 assert pull_request.description == 'New description'
168
168
169 def test_edit_title_description_closed(self, pr_util, csrf_token):
169 def test_edit_title_description_closed(self, pr_util, csrf_token):
170 pull_request = pr_util.create_pull_request()
170 pull_request = pr_util.create_pull_request()
171 pull_request_id = pull_request.pull_request_id
171 pull_request_id = pull_request.pull_request_id
172 pr_util.close()
172 pr_util.close()
173
173
174 response = self.app.post(
174 response = self.app.post(
175 url(controller='pullrequests', action='update',
175 url(controller='pullrequests', action='update',
176 repo_name=pull_request.target_repo.repo_name,
176 repo_name=pull_request.target_repo.repo_name,
177 pull_request_id=str(pull_request_id)),
177 pull_request_id=str(pull_request_id)),
178 params={
178 params={
179 'edit_pull_request': 'true',
179 'edit_pull_request': 'true',
180 '_method': 'put',
180 '_method': 'put',
181 'title': 'New title',
181 'title': 'New title',
182 'description': 'New description',
182 'description': 'New description',
183 'csrf_token': csrf_token})
183 'csrf_token': csrf_token})
184
184
185 assert_session_flash(
185 assert_session_flash(
186 response, u'Cannot update closed pull requests.',
186 response, u'Cannot update closed pull requests.',
187 category='error')
187 category='error')
188
188
189 def test_update_invalid_source_reference(self, pr_util, csrf_token):
189 def test_update_invalid_source_reference(self, pr_util, csrf_token):
190 pull_request = pr_util.create_pull_request()
190 pull_request = pr_util.create_pull_request()
191 pull_request.source_ref = 'branch:invalid-branch:invalid-commit-id'
191 pull_request.source_ref = 'branch:invalid-branch:invalid-commit-id'
192 Session().add(pull_request)
192 Session().add(pull_request)
193 Session().commit()
193 Session().commit()
194
194
195 pull_request_id = pull_request.pull_request_id
195 pull_request_id = pull_request.pull_request_id
196
196
197 response = self.app.post(
197 response = self.app.post(
198 url(controller='pullrequests', action='update',
198 url(controller='pullrequests', action='update',
199 repo_name=pull_request.target_repo.repo_name,
199 repo_name=pull_request.target_repo.repo_name,
200 pull_request_id=str(pull_request_id)),
200 pull_request_id=str(pull_request_id)),
201 params={'update_commits': 'true', '_method': 'put',
201 params={'update_commits': 'true', '_method': 'put',
202 'csrf_token': csrf_token})
202 'csrf_token': csrf_token})
203
203
204 assert_session_flash(
204 assert_session_flash(
205 response, u'Update failed due to missing commits.',
205 response, u'Update failed due to missing commits.',
206 category='error')
206 category='error')
207
207
208 def test_comment_and_close_pull_request(self, pr_util, csrf_token):
208 def test_comment_and_close_pull_request(self, pr_util, csrf_token):
209 pull_request = pr_util.create_pull_request(approved=True)
209 pull_request = pr_util.create_pull_request(approved=True)
210 pull_request_id = pull_request.pull_request_id
210 pull_request_id = pull_request.pull_request_id
211 author = pull_request.user_id
211 author = pull_request.user_id
212 repo = pull_request.target_repo.repo_id
212 repo = pull_request.target_repo.repo_id
213
213
214 self.app.post(
214 self.app.post(
215 url(controller='pullrequests',
215 url(controller='pullrequests',
216 action='comment',
216 action='comment',
217 repo_name=pull_request.target_repo.scm_instance().name,
217 repo_name=pull_request.target_repo.scm_instance().name,
218 pull_request_id=str(pull_request_id)),
218 pull_request_id=str(pull_request_id)),
219 params={
219 params={
220 'changeset_status':
220 'changeset_status':
221 ChangesetStatus.STATUS_APPROVED + '_closed',
221 ChangesetStatus.STATUS_APPROVED + '_closed',
222 'change_changeset_status': 'on',
222 'change_changeset_status': 'on',
223 'text': '',
223 'text': '',
224 'csrf_token': csrf_token},
224 'csrf_token': csrf_token},
225 status=302)
225 status=302)
226
226
227 action = 'user_closed_pull_request:%d' % pull_request_id
227 action = 'user_closed_pull_request:%d' % pull_request_id
228 journal = UserLog.query()\
228 journal = UserLog.query()\
229 .filter(UserLog.user_id == author)\
229 .filter(UserLog.user_id == author)\
230 .filter(UserLog.repository_id == repo)\
230 .filter(UserLog.repository_id == repo)\
231 .filter(UserLog.action == action)\
231 .filter(UserLog.action == action)\
232 .all()
232 .all()
233 assert len(journal) == 1
233 assert len(journal) == 1
234
234
235 def test_reject_and_close_pull_request(self, pr_util, csrf_token):
235 def test_reject_and_close_pull_request(self, pr_util, csrf_token):
236 pull_request = pr_util.create_pull_request()
236 pull_request = pr_util.create_pull_request()
237 pull_request_id = pull_request.pull_request_id
237 pull_request_id = pull_request.pull_request_id
238 response = self.app.post(
238 response = self.app.post(
239 url(controller='pullrequests',
239 url(controller='pullrequests',
240 action='update',
240 action='update',
241 repo_name=pull_request.target_repo.scm_instance().name,
241 repo_name=pull_request.target_repo.scm_instance().name,
242 pull_request_id=str(pull_request.pull_request_id)),
242 pull_request_id=str(pull_request.pull_request_id)),
243 params={'close_pull_request': 'true', '_method': 'put',
243 params={'close_pull_request': 'true', '_method': 'put',
244 'csrf_token': csrf_token})
244 'csrf_token': csrf_token})
245
245
246 pull_request = PullRequest.get(pull_request_id)
246 pull_request = PullRequest.get(pull_request_id)
247
247
248 assert response.json is True
248 assert response.json is True
249 assert pull_request.is_closed()
249 assert pull_request.is_closed()
250
250
251 # check only the latest status, not the review status
251 # check only the latest status, not the review status
252 status = ChangesetStatusModel().get_status(
252 status = ChangesetStatusModel().get_status(
253 pull_request.source_repo, pull_request=pull_request)
253 pull_request.source_repo, pull_request=pull_request)
254 assert status == ChangesetStatus.STATUS_REJECTED
254 assert status == ChangesetStatus.STATUS_REJECTED
255
255
256 def test_comment_force_close_pull_request(self, pr_util, csrf_token):
256 def test_comment_force_close_pull_request(self, pr_util, csrf_token):
257 pull_request = pr_util.create_pull_request()
257 pull_request = pr_util.create_pull_request()
258 pull_request_id = pull_request.pull_request_id
258 pull_request_id = pull_request.pull_request_id
259 reviewers_data = [(1, ['reason']), (2, ['reason2'])]
259 reviewers_data = [(1, ['reason']), (2, ['reason2'])]
260 PullRequestModel().update_reviewers(pull_request_id, reviewers_data)
260 PullRequestModel().update_reviewers(pull_request_id, reviewers_data)
261 author = pull_request.user_id
261 author = pull_request.user_id
262 repo = pull_request.target_repo.repo_id
262 repo = pull_request.target_repo.repo_id
263 self.app.post(
263 self.app.post(
264 url(controller='pullrequests',
264 url(controller='pullrequests',
265 action='comment',
265 action='comment',
266 repo_name=pull_request.target_repo.scm_instance().name,
266 repo_name=pull_request.target_repo.scm_instance().name,
267 pull_request_id=str(pull_request_id)),
267 pull_request_id=str(pull_request_id)),
268 params={
268 params={
269 'changeset_status': 'forced_closed',
269 'changeset_status': 'forced_closed',
270 'csrf_token': csrf_token},
270 'csrf_token': csrf_token},
271 status=302)
271 status=302)
272
272
273 pull_request = PullRequest.get(pull_request_id)
273 pull_request = PullRequest.get(pull_request_id)
274
274
275 action = 'user_closed_pull_request:%d' % pull_request_id
275 action = 'user_closed_pull_request:%d' % pull_request_id
276 journal = UserLog.query().filter(
276 journal = UserLog.query().filter(
277 UserLog.user_id == author,
277 UserLog.user_id == author,
278 UserLog.repository_id == repo,
278 UserLog.repository_id == repo,
279 UserLog.action == action).all()
279 UserLog.action == action).all()
280 assert len(journal) == 1
280 assert len(journal) == 1
281
281
282 # check only the latest status, not the review status
282 # check only the latest status, not the review status
283 status = ChangesetStatusModel().get_status(
283 status = ChangesetStatusModel().get_status(
284 pull_request.source_repo, pull_request=pull_request)
284 pull_request.source_repo, pull_request=pull_request)
285 assert status == ChangesetStatus.STATUS_REJECTED
285 assert status == ChangesetStatus.STATUS_REJECTED
286
286
287 def test_create_pull_request(self, backend, csrf_token):
287 def test_create_pull_request(self, backend, csrf_token):
288 commits = [
288 commits = [
289 {'message': 'ancestor'},
289 {'message': 'ancestor'},
290 {'message': 'change'},
290 {'message': 'change'},
291 {'message': 'change2'},
291 {'message': 'change2'},
292 ]
292 ]
293 commit_ids = backend.create_master_repo(commits)
293 commit_ids = backend.create_master_repo(commits)
294 target = backend.create_repo(heads=['ancestor'])
294 target = backend.create_repo(heads=['ancestor'])
295 source = backend.create_repo(heads=['change2'])
295 source = backend.create_repo(heads=['change2'])
296
296
297 response = self.app.post(
297 response = self.app.post(
298 url(
298 url(
299 controller='pullrequests',
299 controller='pullrequests',
300 action='create',
300 action='create',
301 repo_name=source.repo_name
301 repo_name=source.repo_name
302 ),
302 ),
303 [
303 [
304 ('source_repo', source.repo_name),
304 ('source_repo', source.repo_name),
305 ('source_ref', 'branch:default:' + commit_ids['change2']),
305 ('source_ref', 'branch:default:' + commit_ids['change2']),
306 ('target_repo', target.repo_name),
306 ('target_repo', target.repo_name),
307 ('target_ref', 'branch:default:' + commit_ids['ancestor']),
307 ('target_ref', 'branch:default:' + commit_ids['ancestor']),
308 ('pullrequest_desc', 'Description'),
308 ('pullrequest_desc', 'Description'),
309 ('pullrequest_title', 'Title'),
309 ('pullrequest_title', 'Title'),
310 ('__start__', 'review_members:sequence'),
310 ('__start__', 'review_members:sequence'),
311 ('__start__', 'reviewer:mapping'),
311 ('__start__', 'reviewer:mapping'),
312 ('user_id', '1'),
312 ('user_id', '1'),
313 ('__start__', 'reasons:sequence'),
313 ('__start__', 'reasons:sequence'),
314 ('reason', 'Some reason'),
314 ('reason', 'Some reason'),
315 ('__end__', 'reasons:sequence'),
315 ('__end__', 'reasons:sequence'),
316 ('__end__', 'reviewer:mapping'),
316 ('__end__', 'reviewer:mapping'),
317 ('__end__', 'review_members:sequence'),
317 ('__end__', 'review_members:sequence'),
318 ('__start__', 'revisions:sequence'),
318 ('__start__', 'revisions:sequence'),
319 ('revisions', commit_ids['change']),
319 ('revisions', commit_ids['change']),
320 ('revisions', commit_ids['change2']),
320 ('revisions', commit_ids['change2']),
321 ('__end__', 'revisions:sequence'),
321 ('__end__', 'revisions:sequence'),
322 ('user', ''),
322 ('user', ''),
323 ('csrf_token', csrf_token),
323 ('csrf_token', csrf_token),
324 ],
324 ],
325 status=302)
325 status=302)
326
326
327 location = response.headers['Location']
327 location = response.headers['Location']
328 pull_request_id = int(location.rsplit('/', 1)[1])
328 pull_request_id = int(location.rsplit('/', 1)[1])
329 pull_request = PullRequest.get(pull_request_id)
329 pull_request = PullRequest.get(pull_request_id)
330
330
331 # check that we have now both revisions
331 # check that we have now both revisions
332 assert pull_request.revisions == [commit_ids['change2'], commit_ids['change']]
332 assert pull_request.revisions == [commit_ids['change2'], commit_ids['change']]
333 assert pull_request.source_ref == 'branch:default:' + commit_ids['change2']
333 assert pull_request.source_ref == 'branch:default:' + commit_ids['change2']
334 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
334 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
335 assert pull_request.target_ref == expected_target_ref
335 assert pull_request.target_ref == expected_target_ref
336
336
337 def test_reviewer_notifications(self, backend, csrf_token):
337 def test_reviewer_notifications(self, backend, csrf_token):
338 # We have to use the app.post for this test so it will create the
338 # We have to use the app.post for this test so it will create the
339 # notifications properly with the new PR
339 # notifications properly with the new PR
340 commits = [
340 commits = [
341 {'message': 'ancestor',
341 {'message': 'ancestor',
342 'added': [FileNode('file_A', content='content_of_ancestor')]},
342 'added': [FileNode('file_A', content='content_of_ancestor')]},
343 {'message': 'change',
343 {'message': 'change',
344 'added': [FileNode('file_a', content='content_of_change')]},
344 'added': [FileNode('file_a', content='content_of_change')]},
345 {'message': 'change-child'},
345 {'message': 'change-child'},
346 {'message': 'ancestor-child', 'parents': ['ancestor'],
346 {'message': 'ancestor-child', 'parents': ['ancestor'],
347 'added': [
347 'added': [
348 FileNode('file_B', content='content_of_ancestor_child')]},
348 FileNode('file_B', content='content_of_ancestor_child')]},
349 {'message': 'ancestor-child-2'},
349 {'message': 'ancestor-child-2'},
350 ]
350 ]
351 commit_ids = backend.create_master_repo(commits)
351 commit_ids = backend.create_master_repo(commits)
352 target = backend.create_repo(heads=['ancestor-child'])
352 target = backend.create_repo(heads=['ancestor-child'])
353 source = backend.create_repo(heads=['change'])
353 source = backend.create_repo(heads=['change'])
354
354
355 response = self.app.post(
355 response = self.app.post(
356 url(
356 url(
357 controller='pullrequests',
357 controller='pullrequests',
358 action='create',
358 action='create',
359 repo_name=source.repo_name
359 repo_name=source.repo_name
360 ),
360 ),
361 [
361 [
362 ('source_repo', source.repo_name),
362 ('source_repo', source.repo_name),
363 ('source_ref', 'branch:default:' + commit_ids['change']),
363 ('source_ref', 'branch:default:' + commit_ids['change']),
364 ('target_repo', target.repo_name),
364 ('target_repo', target.repo_name),
365 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
365 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
366 ('pullrequest_desc', 'Description'),
366 ('pullrequest_desc', 'Description'),
367 ('pullrequest_title', 'Title'),
367 ('pullrequest_title', 'Title'),
368 ('__start__', 'review_members:sequence'),
368 ('__start__', 'review_members:sequence'),
369 ('__start__', 'reviewer:mapping'),
369 ('__start__', 'reviewer:mapping'),
370 ('user_id', '2'),
370 ('user_id', '2'),
371 ('__start__', 'reasons:sequence'),
371 ('__start__', 'reasons:sequence'),
372 ('reason', 'Some reason'),
372 ('reason', 'Some reason'),
373 ('__end__', 'reasons:sequence'),
373 ('__end__', 'reasons:sequence'),
374 ('__end__', 'reviewer:mapping'),
374 ('__end__', 'reviewer:mapping'),
375 ('__end__', 'review_members:sequence'),
375 ('__end__', 'review_members:sequence'),
376 ('__start__', 'revisions:sequence'),
376 ('__start__', 'revisions:sequence'),
377 ('revisions', commit_ids['change']),
377 ('revisions', commit_ids['change']),
378 ('__end__', 'revisions:sequence'),
378 ('__end__', 'revisions:sequence'),
379 ('user', ''),
379 ('user', ''),
380 ('csrf_token', csrf_token),
380 ('csrf_token', csrf_token),
381 ],
381 ],
382 status=302)
382 status=302)
383
383
384 location = response.headers['Location']
384 location = response.headers['Location']
385 pull_request_id = int(location.rsplit('/', 1)[1])
385 pull_request_id = int(location.rsplit('/', 1)[1])
386 pull_request = PullRequest.get(pull_request_id)
386 pull_request = PullRequest.get(pull_request_id)
387
387
388 # Check that a notification was made
388 # Check that a notification was made
389 notifications = Notification.query()\
389 notifications = Notification.query()\
390 .filter(Notification.created_by == pull_request.author.user_id,
390 .filter(Notification.created_by == pull_request.author.user_id,
391 Notification.type_ == Notification.TYPE_PULL_REQUEST,
391 Notification.type_ == Notification.TYPE_PULL_REQUEST,
392 Notification.subject.contains("wants you to review "
392 Notification.subject.contains("wants you to review "
393 "pull request #%d"
393 "pull request #%d"
394 % pull_request_id))
394 % pull_request_id))
395 assert len(notifications.all()) == 1
395 assert len(notifications.all()) == 1
396
396
397 # Change reviewers and check that a notification was made
397 # Change reviewers and check that a notification was made
398 PullRequestModel().update_reviewers(
398 PullRequestModel().update_reviewers(
399 pull_request.pull_request_id, [(1, [])])
399 pull_request.pull_request_id, [(1, [])])
400 assert len(notifications.all()) == 2
400 assert len(notifications.all()) == 2
401
401
402 def test_create_pull_request_stores_ancestor_commit_id(self, backend,
402 def test_create_pull_request_stores_ancestor_commit_id(self, backend,
403 csrf_token):
403 csrf_token):
404 commits = [
404 commits = [
405 {'message': 'ancestor',
405 {'message': 'ancestor',
406 'added': [FileNode('file_A', content='content_of_ancestor')]},
406 'added': [FileNode('file_A', content='content_of_ancestor')]},
407 {'message': 'change',
407 {'message': 'change',
408 'added': [FileNode('file_a', content='content_of_change')]},
408 'added': [FileNode('file_a', content='content_of_change')]},
409 {'message': 'change-child'},
409 {'message': 'change-child'},
410 {'message': 'ancestor-child', 'parents': ['ancestor'],
410 {'message': 'ancestor-child', 'parents': ['ancestor'],
411 'added': [
411 'added': [
412 FileNode('file_B', content='content_of_ancestor_child')]},
412 FileNode('file_B', content='content_of_ancestor_child')]},
413 {'message': 'ancestor-child-2'},
413 {'message': 'ancestor-child-2'},
414 ]
414 ]
415 commit_ids = backend.create_master_repo(commits)
415 commit_ids = backend.create_master_repo(commits)
416 target = backend.create_repo(heads=['ancestor-child'])
416 target = backend.create_repo(heads=['ancestor-child'])
417 source = backend.create_repo(heads=['change'])
417 source = backend.create_repo(heads=['change'])
418
418
419 response = self.app.post(
419 response = self.app.post(
420 url(
420 url(
421 controller='pullrequests',
421 controller='pullrequests',
422 action='create',
422 action='create',
423 repo_name=source.repo_name
423 repo_name=source.repo_name
424 ),
424 ),
425 [
425 [
426 ('source_repo', source.repo_name),
426 ('source_repo', source.repo_name),
427 ('source_ref', 'branch:default:' + commit_ids['change']),
427 ('source_ref', 'branch:default:' + commit_ids['change']),
428 ('target_repo', target.repo_name),
428 ('target_repo', target.repo_name),
429 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
429 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
430 ('pullrequest_desc', 'Description'),
430 ('pullrequest_desc', 'Description'),
431 ('pullrequest_title', 'Title'),
431 ('pullrequest_title', 'Title'),
432 ('__start__', 'review_members:sequence'),
432 ('__start__', 'review_members:sequence'),
433 ('__start__', 'reviewer:mapping'),
433 ('__start__', 'reviewer:mapping'),
434 ('user_id', '1'),
434 ('user_id', '1'),
435 ('__start__', 'reasons:sequence'),
435 ('__start__', 'reasons:sequence'),
436 ('reason', 'Some reason'),
436 ('reason', 'Some reason'),
437 ('__end__', 'reasons:sequence'),
437 ('__end__', 'reasons:sequence'),
438 ('__end__', 'reviewer:mapping'),
438 ('__end__', 'reviewer:mapping'),
439 ('__end__', 'review_members:sequence'),
439 ('__end__', 'review_members:sequence'),
440 ('__start__', 'revisions:sequence'),
440 ('__start__', 'revisions:sequence'),
441 ('revisions', commit_ids['change']),
441 ('revisions', commit_ids['change']),
442 ('__end__', 'revisions:sequence'),
442 ('__end__', 'revisions:sequence'),
443 ('user', ''),
443 ('user', ''),
444 ('csrf_token', csrf_token),
444 ('csrf_token', csrf_token),
445 ],
445 ],
446 status=302)
446 status=302)
447
447
448 location = response.headers['Location']
448 location = response.headers['Location']
449 pull_request_id = int(location.rsplit('/', 1)[1])
449 pull_request_id = int(location.rsplit('/', 1)[1])
450 pull_request = PullRequest.get(pull_request_id)
450 pull_request = PullRequest.get(pull_request_id)
451
451
452 # target_ref has to point to the ancestor's commit_id in order to
452 # target_ref has to point to the ancestor's commit_id in order to
453 # show the correct diff
453 # show the correct diff
454 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
454 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
455 assert pull_request.target_ref == expected_target_ref
455 assert pull_request.target_ref == expected_target_ref
456
456
457 # Check generated diff contents
457 # Check generated diff contents
458 response = response.follow()
458 response = response.follow()
459 assert 'content_of_ancestor' not in response.body
459 assert 'content_of_ancestor' not in response.body
460 assert 'content_of_ancestor-child' not in response.body
460 assert 'content_of_ancestor-child' not in response.body
461 assert 'content_of_change' in response.body
461 assert 'content_of_change' in response.body
462
462
463 def test_merge_pull_request_enabled(self, pr_util, csrf_token):
463 def test_merge_pull_request_enabled(self, pr_util, csrf_token):
464 # Clear any previous calls to rcextensions
464 # Clear any previous calls to rcextensions
465 rhodecode.EXTENSIONS.calls.clear()
465 rhodecode.EXTENSIONS.calls.clear()
466
466
467 pull_request = pr_util.create_pull_request(
467 pull_request = pr_util.create_pull_request(
468 approved=True, mergeable=True)
468 approved=True, mergeable=True)
469 pull_request_id = pull_request.pull_request_id
469 pull_request_id = pull_request.pull_request_id
470 repo_name = pull_request.target_repo.scm_instance().name,
470 repo_name = pull_request.target_repo.scm_instance().name,
471
471
472 response = self.app.post(
472 response = self.app.post(
473 url(controller='pullrequests',
473 url(controller='pullrequests',
474 action='merge',
474 action='merge',
475 repo_name=str(repo_name[0]),
475 repo_name=str(repo_name[0]),
476 pull_request_id=str(pull_request_id)),
476 pull_request_id=str(pull_request_id)),
477 params={'csrf_token': csrf_token}).follow()
477 params={'csrf_token': csrf_token}).follow()
478
478
479 pull_request = PullRequest.get(pull_request_id)
479 pull_request = PullRequest.get(pull_request_id)
480
480
481 assert response.status_int == 200
481 assert response.status_int == 200
482 assert pull_request.is_closed()
482 assert pull_request.is_closed()
483 assert_pull_request_status(
483 assert_pull_request_status(
484 pull_request, ChangesetStatus.STATUS_APPROVED)
484 pull_request, ChangesetStatus.STATUS_APPROVED)
485
485
486 # Check the relevant log entries were added
486 # Check the relevant log entries were added
487 user_logs = UserLog.query().order_by('-user_log_id').limit(4)
487 user_logs = UserLog.query().order_by('-user_log_id').limit(4)
488 actions = [log.action for log in user_logs]
488 actions = [log.action for log in user_logs]
489 pr_commit_ids = PullRequestModel()._get_commit_ids(pull_request)
489 pr_commit_ids = PullRequestModel()._get_commit_ids(pull_request)
490 expected_actions = [
490 expected_actions = [
491 u'user_closed_pull_request:%d' % pull_request_id,
491 u'user_closed_pull_request:%d' % pull_request_id,
492 u'user_merged_pull_request:%d' % pull_request_id,
492 u'user_merged_pull_request:%d' % pull_request_id,
493 # The action below reflect that the post push actions were executed
493 # The action below reflect that the post push actions were executed
494 u'user_commented_pull_request:%d' % pull_request_id,
494 u'user_commented_pull_request:%d' % pull_request_id,
495 u'push:%s' % ','.join(pr_commit_ids),
495 u'push:%s' % ','.join(pr_commit_ids),
496 ]
496 ]
497 assert actions == expected_actions
497 assert actions == expected_actions
498
498
499 # Check post_push rcextension was really executed
499 # Check post_push rcextension was really executed
500 push_calls = rhodecode.EXTENSIONS.calls['post_push']
500 push_calls = rhodecode.EXTENSIONS.calls['post_push']
501 assert len(push_calls) == 1
501 assert len(push_calls) == 1
502 unused_last_call_args, last_call_kwargs = push_calls[0]
502 unused_last_call_args, last_call_kwargs = push_calls[0]
503 assert last_call_kwargs['action'] == 'push'
503 assert last_call_kwargs['action'] == 'push'
504 assert last_call_kwargs['pushed_revs'] == pr_commit_ids
504 assert last_call_kwargs['pushed_revs'] == pr_commit_ids
505
505
506 def test_merge_pull_request_disabled(self, pr_util, csrf_token):
506 def test_merge_pull_request_disabled(self, pr_util, csrf_token):
507 pull_request = pr_util.create_pull_request(mergeable=False)
507 pull_request = pr_util.create_pull_request(mergeable=False)
508 pull_request_id = pull_request.pull_request_id
508 pull_request_id = pull_request.pull_request_id
509 pull_request = PullRequest.get(pull_request_id)
509 pull_request = PullRequest.get(pull_request_id)
510
510
511 response = self.app.post(
511 response = self.app.post(
512 url(controller='pullrequests',
512 url(controller='pullrequests',
513 action='merge',
513 action='merge',
514 repo_name=pull_request.target_repo.scm_instance().name,
514 repo_name=pull_request.target_repo.scm_instance().name,
515 pull_request_id=str(pull_request.pull_request_id)),
515 pull_request_id=str(pull_request.pull_request_id)),
516 params={'csrf_token': csrf_token}).follow()
516 params={'csrf_token': csrf_token}).follow()
517
517
518 assert response.status_int == 200
518 assert response.status_int == 200
519 assert 'Server-side pull request merging is disabled.' in response.body
519 assert 'Server-side pull request merging is disabled.' in response.body
520
520
521 @pytest.mark.skip_backends('svn')
521 @pytest.mark.skip_backends('svn')
522 def test_merge_pull_request_not_approved(self, pr_util, csrf_token):
522 def test_merge_pull_request_not_approved(self, pr_util, csrf_token):
523 pull_request = pr_util.create_pull_request(mergeable=True)
523 pull_request = pr_util.create_pull_request(mergeable=True)
524 pull_request_id = pull_request.pull_request_id
524 pull_request_id = pull_request.pull_request_id
525 repo_name = pull_request.target_repo.scm_instance().name,
525 repo_name = pull_request.target_repo.scm_instance().name,
526
526
527 response = self.app.post(
527 response = self.app.post(
528 url(controller='pullrequests',
528 url(controller='pullrequests',
529 action='merge',
529 action='merge',
530 repo_name=str(repo_name[0]),
530 repo_name=str(repo_name[0]),
531 pull_request_id=str(pull_request_id)),
531 pull_request_id=str(pull_request_id)),
532 params={'csrf_token': csrf_token}).follow()
532 params={'csrf_token': csrf_token}).follow()
533
533
534 pull_request = PullRequest.get(pull_request_id)
534 pull_request = PullRequest.get(pull_request_id)
535
535
536 assert response.status_int == 200
536 assert response.status_int == 200
537 assert ' Reviewer approval is pending.' in response.body
537 assert ' Reviewer approval is pending.' in response.body
538
538
539 def test_update_source_revision(self, backend, csrf_token):
539 def test_update_source_revision(self, backend, csrf_token):
540 commits = [
540 commits = [
541 {'message': 'ancestor'},
541 {'message': 'ancestor'},
542 {'message': 'change'},
542 {'message': 'change'},
543 {'message': 'change-2'},
543 {'message': 'change-2'},
544 ]
544 ]
545 commit_ids = backend.create_master_repo(commits)
545 commit_ids = backend.create_master_repo(commits)
546 target = backend.create_repo(heads=['ancestor'])
546 target = backend.create_repo(heads=['ancestor'])
547 source = backend.create_repo(heads=['change'])
547 source = backend.create_repo(heads=['change'])
548
548
549 # create pr from a in source to A in target
549 # create pr from a in source to A in target
550 pull_request = PullRequest()
550 pull_request = PullRequest()
551 pull_request.source_repo = source
551 pull_request.source_repo = source
552 # TODO: johbo: Make sure that we write the source ref this way!
552 # TODO: johbo: Make sure that we write the source ref this way!
553 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
553 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
554 branch=backend.default_branch_name, commit_id=commit_ids['change'])
554 branch=backend.default_branch_name, commit_id=commit_ids['change'])
555 pull_request.target_repo = target
555 pull_request.target_repo = target
556
556
557 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
557 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
558 branch=backend.default_branch_name,
558 branch=backend.default_branch_name,
559 commit_id=commit_ids['ancestor'])
559 commit_id=commit_ids['ancestor'])
560 pull_request.revisions = [commit_ids['change']]
560 pull_request.revisions = [commit_ids['change']]
561 pull_request.title = u"Test"
561 pull_request.title = u"Test"
562 pull_request.description = u"Description"
562 pull_request.description = u"Description"
563 pull_request.author = UserModel().get_by_username(
563 pull_request.author = UserModel().get_by_username(
564 TEST_USER_ADMIN_LOGIN)
564 TEST_USER_ADMIN_LOGIN)
565 Session().add(pull_request)
565 Session().add(pull_request)
566 Session().commit()
566 Session().commit()
567 pull_request_id = pull_request.pull_request_id
567 pull_request_id = pull_request.pull_request_id
568
568
569 # source has ancestor - change - change-2
569 # source has ancestor - change - change-2
570 backend.pull_heads(source, heads=['change-2'])
570 backend.pull_heads(source, heads=['change-2'])
571
571
572 # update PR
572 # update PR
573 self.app.post(
573 self.app.post(
574 url(controller='pullrequests', action='update',
574 url(controller='pullrequests', action='update',
575 repo_name=target.repo_name,
575 repo_name=target.repo_name,
576 pull_request_id=str(pull_request_id)),
576 pull_request_id=str(pull_request_id)),
577 params={'update_commits': 'true', '_method': 'put',
577 params={'update_commits': 'true', '_method': 'put',
578 'csrf_token': csrf_token})
578 'csrf_token': csrf_token})
579
579
580 # check that we have now both revisions
580 # check that we have now both revisions
581 pull_request = PullRequest.get(pull_request_id)
581 pull_request = PullRequest.get(pull_request_id)
582 assert pull_request.revisions == [
582 assert pull_request.revisions == [
583 commit_ids['change-2'], commit_ids['change']]
583 commit_ids['change-2'], commit_ids['change']]
584
584
585 # TODO: johbo: this should be a test on its own
585 # TODO: johbo: this should be a test on its own
586 response = self.app.get(url(
586 response = self.app.get(url(
587 controller='pullrequests', action='index',
587 controller='pullrequests', action='index',
588 repo_name=target.repo_name))
588 repo_name=target.repo_name))
589 assert response.status_int == 200
589 assert response.status_int == 200
590 assert 'Pull request updated to' in response.body
590 assert 'Pull request updated to' in response.body
591 assert 'with 1 added, 0 removed commits.' in response.body
591 assert 'with 1 added, 0 removed commits.' in response.body
592
592
593 def test_update_target_revision(self, backend, csrf_token):
593 def test_update_target_revision(self, backend, csrf_token):
594 commits = [
594 commits = [
595 {'message': 'ancestor'},
595 {'message': 'ancestor'},
596 {'message': 'change'},
596 {'message': 'change'},
597 {'message': 'ancestor-new', 'parents': ['ancestor']},
597 {'message': 'ancestor-new', 'parents': ['ancestor']},
598 {'message': 'change-rebased'},
598 {'message': 'change-rebased'},
599 ]
599 ]
600 commit_ids = backend.create_master_repo(commits)
600 commit_ids = backend.create_master_repo(commits)
601 target = backend.create_repo(heads=['ancestor'])
601 target = backend.create_repo(heads=['ancestor'])
602 source = backend.create_repo(heads=['change'])
602 source = backend.create_repo(heads=['change'])
603
603
604 # create pr from a in source to A in target
604 # create pr from a in source to A in target
605 pull_request = PullRequest()
605 pull_request = PullRequest()
606 pull_request.source_repo = source
606 pull_request.source_repo = source
607 # TODO: johbo: Make sure that we write the source ref this way!
607 # TODO: johbo: Make sure that we write the source ref this way!
608 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
608 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
609 branch=backend.default_branch_name, commit_id=commit_ids['change'])
609 branch=backend.default_branch_name, commit_id=commit_ids['change'])
610 pull_request.target_repo = target
610 pull_request.target_repo = target
611 # TODO: johbo: Target ref should be branch based, since tip can jump
611 # TODO: johbo: Target ref should be branch based, since tip can jump
612 # from branch to branch
612 # from branch to branch
613 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
613 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
614 branch=backend.default_branch_name,
614 branch=backend.default_branch_name,
615 commit_id=commit_ids['ancestor'])
615 commit_id=commit_ids['ancestor'])
616 pull_request.revisions = [commit_ids['change']]
616 pull_request.revisions = [commit_ids['change']]
617 pull_request.title = u"Test"
617 pull_request.title = u"Test"
618 pull_request.description = u"Description"
618 pull_request.description = u"Description"
619 pull_request.author = UserModel().get_by_username(
619 pull_request.author = UserModel().get_by_username(
620 TEST_USER_ADMIN_LOGIN)
620 TEST_USER_ADMIN_LOGIN)
621 Session().add(pull_request)
621 Session().add(pull_request)
622 Session().commit()
622 Session().commit()
623 pull_request_id = pull_request.pull_request_id
623 pull_request_id = pull_request.pull_request_id
624
624
625 # target has ancestor - ancestor-new
625 # target has ancestor - ancestor-new
626 # source has ancestor - ancestor-new - change-rebased
626 # source has ancestor - ancestor-new - change-rebased
627 backend.pull_heads(target, heads=['ancestor-new'])
627 backend.pull_heads(target, heads=['ancestor-new'])
628 backend.pull_heads(source, heads=['change-rebased'])
628 backend.pull_heads(source, heads=['change-rebased'])
629
629
630 # update PR
630 # update PR
631 self.app.post(
631 self.app.post(
632 url(controller='pullrequests', action='update',
632 url(controller='pullrequests', action='update',
633 repo_name=target.repo_name,
633 repo_name=target.repo_name,
634 pull_request_id=str(pull_request_id)),
634 pull_request_id=str(pull_request_id)),
635 params={'update_commits': 'true', '_method': 'put',
635 params={'update_commits': 'true', '_method': 'put',
636 'csrf_token': csrf_token},
636 'csrf_token': csrf_token},
637 status=200)
637 status=200)
638
638
639 # check that we have now both revisions
639 # check that we have now both revisions
640 pull_request = PullRequest.get(pull_request_id)
640 pull_request = PullRequest.get(pull_request_id)
641 assert pull_request.revisions == [commit_ids['change-rebased']]
641 assert pull_request.revisions == [commit_ids['change-rebased']]
642 assert pull_request.target_ref == 'branch:{branch}:{commit_id}'.format(
642 assert pull_request.target_ref == 'branch:{branch}:{commit_id}'.format(
643 branch=backend.default_branch_name,
643 branch=backend.default_branch_name,
644 commit_id=commit_ids['ancestor-new'])
644 commit_id=commit_ids['ancestor-new'])
645
645
646 # TODO: johbo: This should be a test on its own
646 # TODO: johbo: This should be a test on its own
647 response = self.app.get(url(
647 response = self.app.get(url(
648 controller='pullrequests', action='index',
648 controller='pullrequests', action='index',
649 repo_name=target.repo_name))
649 repo_name=target.repo_name))
650 assert response.status_int == 200
650 assert response.status_int == 200
651 assert 'Pull request updated to' in response.body
651 assert 'Pull request updated to' in response.body
652 assert 'with 1 added, 1 removed commits.' in response.body
652 assert 'with 1 added, 1 removed commits.' in response.body
653
653
654 def test_update_of_ancestor_reference(self, backend, csrf_token):
654 def test_update_of_ancestor_reference(self, backend, csrf_token):
655 commits = [
655 commits = [
656 {'message': 'ancestor'},
656 {'message': 'ancestor'},
657 {'message': 'change'},
657 {'message': 'change'},
658 {'message': 'change-2'},
658 {'message': 'change-2'},
659 {'message': 'ancestor-new', 'parents': ['ancestor']},
659 {'message': 'ancestor-new', 'parents': ['ancestor']},
660 {'message': 'change-rebased'},
660 {'message': 'change-rebased'},
661 ]
661 ]
662 commit_ids = backend.create_master_repo(commits)
662 commit_ids = backend.create_master_repo(commits)
663 target = backend.create_repo(heads=['ancestor'])
663 target = backend.create_repo(heads=['ancestor'])
664 source = backend.create_repo(heads=['change'])
664 source = backend.create_repo(heads=['change'])
665
665
666 # create pr from a in source to A in target
666 # create pr from a in source to A in target
667 pull_request = PullRequest()
667 pull_request = PullRequest()
668 pull_request.source_repo = source
668 pull_request.source_repo = source
669 # TODO: johbo: Make sure that we write the source ref this way!
669 # TODO: johbo: Make sure that we write the source ref this way!
670 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
670 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
671 branch=backend.default_branch_name,
671 branch=backend.default_branch_name,
672 commit_id=commit_ids['change'])
672 commit_id=commit_ids['change'])
673 pull_request.target_repo = target
673 pull_request.target_repo = target
674 # TODO: johbo: Target ref should be branch based, since tip can jump
674 # TODO: johbo: Target ref should be branch based, since tip can jump
675 # from branch to branch
675 # from branch to branch
676 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
676 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
677 branch=backend.default_branch_name,
677 branch=backend.default_branch_name,
678 commit_id=commit_ids['ancestor'])
678 commit_id=commit_ids['ancestor'])
679 pull_request.revisions = [commit_ids['change']]
679 pull_request.revisions = [commit_ids['change']]
680 pull_request.title = u"Test"
680 pull_request.title = u"Test"
681 pull_request.description = u"Description"
681 pull_request.description = u"Description"
682 pull_request.author = UserModel().get_by_username(
682 pull_request.author = UserModel().get_by_username(
683 TEST_USER_ADMIN_LOGIN)
683 TEST_USER_ADMIN_LOGIN)
684 Session().add(pull_request)
684 Session().add(pull_request)
685 Session().commit()
685 Session().commit()
686 pull_request_id = pull_request.pull_request_id
686 pull_request_id = pull_request.pull_request_id
687
687
688 # target has ancestor - ancestor-new
688 # target has ancestor - ancestor-new
689 # source has ancestor - ancestor-new - change-rebased
689 # source has ancestor - ancestor-new - change-rebased
690 backend.pull_heads(target, heads=['ancestor-new'])
690 backend.pull_heads(target, heads=['ancestor-new'])
691 backend.pull_heads(source, heads=['change-rebased'])
691 backend.pull_heads(source, heads=['change-rebased'])
692
692
693 # update PR
693 # update PR
694 self.app.post(
694 self.app.post(
695 url(controller='pullrequests', action='update',
695 url(controller='pullrequests', action='update',
696 repo_name=target.repo_name,
696 repo_name=target.repo_name,
697 pull_request_id=str(pull_request_id)),
697 pull_request_id=str(pull_request_id)),
698 params={'update_commits': 'true', '_method': 'put',
698 params={'update_commits': 'true', '_method': 'put',
699 'csrf_token': csrf_token},
699 'csrf_token': csrf_token},
700 status=200)
700 status=200)
701
701
702 # Expect the target reference to be updated correctly
702 # Expect the target reference to be updated correctly
703 pull_request = PullRequest.get(pull_request_id)
703 pull_request = PullRequest.get(pull_request_id)
704 assert pull_request.revisions == [commit_ids['change-rebased']]
704 assert pull_request.revisions == [commit_ids['change-rebased']]
705 expected_target_ref = 'branch:{branch}:{commit_id}'.format(
705 expected_target_ref = 'branch:{branch}:{commit_id}'.format(
706 branch=backend.default_branch_name,
706 branch=backend.default_branch_name,
707 commit_id=commit_ids['ancestor-new'])
707 commit_id=commit_ids['ancestor-new'])
708 assert pull_request.target_ref == expected_target_ref
708 assert pull_request.target_ref == expected_target_ref
709
709
710 def test_remove_pull_request_branch(self, backend_git, csrf_token):
710 def test_remove_pull_request_branch(self, backend_git, csrf_token):
711 branch_name = 'development'
711 branch_name = 'development'
712 commits = [
712 commits = [
713 {'message': 'initial-commit'},
713 {'message': 'initial-commit'},
714 {'message': 'old-feature'},
714 {'message': 'old-feature'},
715 {'message': 'new-feature', 'branch': branch_name},
715 {'message': 'new-feature', 'branch': branch_name},
716 ]
716 ]
717 repo = backend_git.create_repo(commits)
717 repo = backend_git.create_repo(commits)
718 commit_ids = backend_git.commit_ids
718 commit_ids = backend_git.commit_ids
719
719
720 pull_request = PullRequest()
720 pull_request = PullRequest()
721 pull_request.source_repo = repo
721 pull_request.source_repo = repo
722 pull_request.target_repo = repo
722 pull_request.target_repo = repo
723 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
723 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
724 branch=branch_name, commit_id=commit_ids['new-feature'])
724 branch=branch_name, commit_id=commit_ids['new-feature'])
725 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
725 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
726 branch=backend_git.default_branch_name,
726 branch=backend_git.default_branch_name,
727 commit_id=commit_ids['old-feature'])
727 commit_id=commit_ids['old-feature'])
728 pull_request.revisions = [commit_ids['new-feature']]
728 pull_request.revisions = [commit_ids['new-feature']]
729 pull_request.title = u"Test"
729 pull_request.title = u"Test"
730 pull_request.description = u"Description"
730 pull_request.description = u"Description"
731 pull_request.author = UserModel().get_by_username(
731 pull_request.author = UserModel().get_by_username(
732 TEST_USER_ADMIN_LOGIN)
732 TEST_USER_ADMIN_LOGIN)
733 Session().add(pull_request)
733 Session().add(pull_request)
734 Session().commit()
734 Session().commit()
735
735
736 vcs = repo.scm_instance()
736 vcs = repo.scm_instance()
737 vcs.remove_ref('refs/heads/{}'.format(branch_name))
737 vcs.remove_ref('refs/heads/{}'.format(branch_name))
738
738
739 response = self.app.get(url(
739 response = self.app.get(url(
740 controller='pullrequests', action='show',
740 controller='pullrequests', action='show',
741 repo_name=repo.repo_name,
741 repo_name=repo.repo_name,
742 pull_request_id=str(pull_request.pull_request_id)))
742 pull_request_id=str(pull_request.pull_request_id)))
743
743
744 assert response.status_int == 200
744 assert response.status_int == 200
745 assert_response = AssertResponse(response)
745 assert_response = AssertResponse(response)
746 assert_response.element_contains(
746 assert_response.element_contains(
747 '#changeset_compare_view_content .alert strong',
747 '#changeset_compare_view_content .alert strong',
748 'Missing commits')
748 'Missing commits')
749 assert_response.element_contains(
749 assert_response.element_contains(
750 '#changeset_compare_view_content .alert',
750 '#changeset_compare_view_content .alert',
751 'This pull request cannot be displayed, because one or more'
751 'This pull request cannot be displayed, because one or more'
752 ' commits no longer exist in the source repository.')
752 ' commits no longer exist in the source repository.')
753
753
754 def test_strip_commits_from_pull_request(
754 def test_strip_commits_from_pull_request(
755 self, backend, pr_util, csrf_token):
755 self, backend, pr_util, csrf_token):
756 commits = [
756 commits = [
757 {'message': 'initial-commit'},
757 {'message': 'initial-commit'},
758 {'message': 'old-feature'},
758 {'message': 'old-feature'},
759 {'message': 'new-feature', 'parents': ['initial-commit']},
759 {'message': 'new-feature', 'parents': ['initial-commit']},
760 ]
760 ]
761 pull_request = pr_util.create_pull_request(
761 pull_request = pr_util.create_pull_request(
762 commits, target_head='initial-commit', source_head='new-feature',
762 commits, target_head='initial-commit', source_head='new-feature',
763 revisions=['new-feature'])
763 revisions=['new-feature'])
764
764
765 vcs = pr_util.source_repository.scm_instance()
765 vcs = pr_util.source_repository.scm_instance()
766 if backend.alias == 'git':
766 if backend.alias == 'git':
767 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
767 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
768 else:
768 else:
769 vcs.strip(pr_util.commit_ids['new-feature'])
769 vcs.strip(pr_util.commit_ids['new-feature'])
770
770
771 response = self.app.get(url(
771 response = self.app.get(url(
772 controller='pullrequests', action='show',
772 controller='pullrequests', action='show',
773 repo_name=pr_util.target_repository.repo_name,
773 repo_name=pr_util.target_repository.repo_name,
774 pull_request_id=str(pull_request.pull_request_id)))
774 pull_request_id=str(pull_request.pull_request_id)))
775
775
776 assert response.status_int == 200
776 assert response.status_int == 200
777 assert_response = AssertResponse(response)
777 assert_response = AssertResponse(response)
778 assert_response.element_contains(
778 assert_response.element_contains(
779 '#changeset_compare_view_content .alert strong',
779 '#changeset_compare_view_content .alert strong',
780 'Missing commits')
780 'Missing commits')
781 assert_response.element_contains(
781 assert_response.element_contains(
782 '#changeset_compare_view_content .alert',
782 '#changeset_compare_view_content .alert',
783 'This pull request cannot be displayed, because one or more'
783 'This pull request cannot be displayed, because one or more'
784 ' commits no longer exist in the source repository.')
784 ' commits no longer exist in the source repository.')
785 assert_response.element_contains(
785 assert_response.element_contains(
786 '#update_commits',
786 '#update_commits',
787 'Update commits')
787 'Update commits')
788
788
789 def test_strip_commits_and_update(
789 def test_strip_commits_and_update(
790 self, backend, pr_util, csrf_token):
790 self, backend, pr_util, csrf_token):
791 commits = [
791 commits = [
792 {'message': 'initial-commit'},
792 {'message': 'initial-commit'},
793 {'message': 'old-feature'},
793 {'message': 'old-feature'},
794 {'message': 'new-feature', 'parents': ['old-feature']},
794 {'message': 'new-feature', 'parents': ['old-feature']},
795 ]
795 ]
796 pull_request = pr_util.create_pull_request(
796 pull_request = pr_util.create_pull_request(
797 commits, target_head='old-feature', source_head='new-feature',
797 commits, target_head='old-feature', source_head='new-feature',
798 revisions=['new-feature'], mergeable=True)
798 revisions=['new-feature'], mergeable=True)
799
799
800 vcs = pr_util.source_repository.scm_instance()
800 vcs = pr_util.source_repository.scm_instance()
801 if backend.alias == 'git':
801 if backend.alias == 'git':
802 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
802 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
803 else:
803 else:
804 vcs.strip(pr_util.commit_ids['new-feature'])
804 vcs.strip(pr_util.commit_ids['new-feature'])
805
805
806 response = self.app.post(
806 response = self.app.post(
807 url(controller='pullrequests', action='update',
807 url(controller='pullrequests', action='update',
808 repo_name=pull_request.target_repo.repo_name,
808 repo_name=pull_request.target_repo.repo_name,
809 pull_request_id=str(pull_request.pull_request_id)),
809 pull_request_id=str(pull_request.pull_request_id)),
810 params={'update_commits': 'true', '_method': 'put',
810 params={'update_commits': 'true', '_method': 'put',
811 'csrf_token': csrf_token})
811 'csrf_token': csrf_token})
812
812
813 assert response.status_int == 200
813 assert response.status_int == 200
814 assert response.body == 'true'
814 assert response.body == 'true'
815
815
816 # Make sure that after update, it won't raise 500 errors
816 # Make sure that after update, it won't raise 500 errors
817 response = self.app.get(url(
817 response = self.app.get(url(
818 controller='pullrequests', action='show',
818 controller='pullrequests', action='show',
819 repo_name=pr_util.target_repository.repo_name,
819 repo_name=pr_util.target_repository.repo_name,
820 pull_request_id=str(pull_request.pull_request_id)))
820 pull_request_id=str(pull_request.pull_request_id)))
821
821
822 assert response.status_int == 200
822 assert response.status_int == 200
823 assert_response = AssertResponse(response)
823 assert_response = AssertResponse(response)
824 assert_response.element_contains(
824 assert_response.element_contains(
825 '#changeset_compare_view_content .alert strong',
825 '#changeset_compare_view_content .alert strong',
826 'Missing commits')
826 'Missing commits')
827
827
828 def test_branch_is_a_link(self, pr_util):
828 def test_branch_is_a_link(self, pr_util):
829 pull_request = pr_util.create_pull_request()
829 pull_request = pr_util.create_pull_request()
830 pull_request.source_ref = 'branch:origin:1234567890abcdef'
830 pull_request.source_ref = 'branch:origin:1234567890abcdef'
831 pull_request.target_ref = 'branch:target:abcdef1234567890'
831 pull_request.target_ref = 'branch:target:abcdef1234567890'
832 Session().add(pull_request)
832 Session().add(pull_request)
833 Session().commit()
833 Session().commit()
834
834
835 response = self.app.get(url(
835 response = self.app.get(url(
836 controller='pullrequests', action='show',
836 controller='pullrequests', action='show',
837 repo_name=pull_request.target_repo.scm_instance().name,
837 repo_name=pull_request.target_repo.scm_instance().name,
838 pull_request_id=str(pull_request.pull_request_id)))
838 pull_request_id=str(pull_request.pull_request_id)))
839 assert response.status_int == 200
839 assert response.status_int == 200
840 assert_response = AssertResponse(response)
840 assert_response = AssertResponse(response)
841
841
842 origin = assert_response.get_element('.pr-origininfo .tag')
842 origin = assert_response.get_element('.pr-origininfo .tag')
843 origin_children = origin.getchildren()
843 origin_children = origin.getchildren()
844 assert len(origin_children) == 1
844 assert len(origin_children) == 1
845 target = assert_response.get_element('.pr-targetinfo .tag')
845 target = assert_response.get_element('.pr-targetinfo .tag')
846 target_children = target.getchildren()
846 target_children = target.getchildren()
847 assert len(target_children) == 1
847 assert len(target_children) == 1
848
848
849 expected_origin_link = url(
849 expected_origin_link = url(
850 'changelog_home',
850 'changelog_home',
851 repo_name=pull_request.source_repo.scm_instance().name,
851 repo_name=pull_request.source_repo.scm_instance().name,
852 branch='origin')
852 branch='origin')
853 expected_target_link = url(
853 expected_target_link = url(
854 'changelog_home',
854 'changelog_home',
855 repo_name=pull_request.target_repo.scm_instance().name,
855 repo_name=pull_request.target_repo.scm_instance().name,
856 branch='target')
856 branch='target')
857 assert origin_children[0].attrib['href'] == expected_origin_link
857 assert origin_children[0].attrib['href'] == expected_origin_link
858 assert origin_children[0].text == 'branch: origin'
858 assert origin_children[0].text == 'branch: origin'
859 assert target_children[0].attrib['href'] == expected_target_link
859 assert target_children[0].attrib['href'] == expected_target_link
860 assert target_children[0].text == 'branch: target'
860 assert target_children[0].text == 'branch: target'
861
861
862 def test_bookmark_is_not_a_link(self, pr_util):
862 def test_bookmark_is_not_a_link(self, pr_util):
863 pull_request = pr_util.create_pull_request()
863 pull_request = pr_util.create_pull_request()
864 pull_request.source_ref = 'bookmark:origin:1234567890abcdef'
864 pull_request.source_ref = 'bookmark:origin:1234567890abcdef'
865 pull_request.target_ref = 'bookmark:target:abcdef1234567890'
865 pull_request.target_ref = 'bookmark:target:abcdef1234567890'
866 Session().add(pull_request)
866 Session().add(pull_request)
867 Session().commit()
867 Session().commit()
868
868
869 response = self.app.get(url(
869 response = self.app.get(url(
870 controller='pullrequests', action='show',
870 controller='pullrequests', action='show',
871 repo_name=pull_request.target_repo.scm_instance().name,
871 repo_name=pull_request.target_repo.scm_instance().name,
872 pull_request_id=str(pull_request.pull_request_id)))
872 pull_request_id=str(pull_request.pull_request_id)))
873 assert response.status_int == 200
873 assert response.status_int == 200
874 assert_response = AssertResponse(response)
874 assert_response = AssertResponse(response)
875
875
876 origin = assert_response.get_element('.pr-origininfo .tag')
876 origin = assert_response.get_element('.pr-origininfo .tag')
877 assert origin.text.strip() == 'bookmark: origin'
877 assert origin.text.strip() == 'bookmark: origin'
878 assert origin.getchildren() == []
878 assert origin.getchildren() == []
879
879
880 target = assert_response.get_element('.pr-targetinfo .tag')
880 target = assert_response.get_element('.pr-targetinfo .tag')
881 assert target.text.strip() == 'bookmark: target'
881 assert target.text.strip() == 'bookmark: target'
882 assert target.getchildren() == []
882 assert target.getchildren() == []
883
883
884 def test_tag_is_not_a_link(self, pr_util):
884 def test_tag_is_not_a_link(self, pr_util):
885 pull_request = pr_util.create_pull_request()
885 pull_request = pr_util.create_pull_request()
886 pull_request.source_ref = 'tag:origin:1234567890abcdef'
886 pull_request.source_ref = 'tag:origin:1234567890abcdef'
887 pull_request.target_ref = 'tag:target:abcdef1234567890'
887 pull_request.target_ref = 'tag:target:abcdef1234567890'
888 Session().add(pull_request)
888 Session().add(pull_request)
889 Session().commit()
889 Session().commit()
890
890
891 response = self.app.get(url(
891 response = self.app.get(url(
892 controller='pullrequests', action='show',
892 controller='pullrequests', action='show',
893 repo_name=pull_request.target_repo.scm_instance().name,
893 repo_name=pull_request.target_repo.scm_instance().name,
894 pull_request_id=str(pull_request.pull_request_id)))
894 pull_request_id=str(pull_request.pull_request_id)))
895 assert response.status_int == 200
895 assert response.status_int == 200
896 assert_response = AssertResponse(response)
896 assert_response = AssertResponse(response)
897
897
898 origin = assert_response.get_element('.pr-origininfo .tag')
898 origin = assert_response.get_element('.pr-origininfo .tag')
899 assert origin.text.strip() == 'tag: origin'
899 assert origin.text.strip() == 'tag: origin'
900 assert origin.getchildren() == []
900 assert origin.getchildren() == []
901
901
902 target = assert_response.get_element('.pr-targetinfo .tag')
902 target = assert_response.get_element('.pr-targetinfo .tag')
903 assert target.text.strip() == 'tag: target'
903 assert target.text.strip() == 'tag: target'
904 assert target.getchildren() == []
904 assert target.getchildren() == []
905
905
906 def test_description_is_escaped_on_index_page(self, backend, pr_util):
906 def test_description_is_escaped_on_index_page(self, backend, pr_util):
907 xss_description = "<script>alert('Hi!')</script>"
907 xss_description = "<script>alert('Hi!')</script>"
908 pull_request = pr_util.create_pull_request(description=xss_description)
908 pull_request = pr_util.create_pull_request(description=xss_description)
909 response = self.app.get(url(
909 response = self.app.get(url(
910 controller='pullrequests', action='show_all',
910 controller='pullrequests', action='show_all',
911 repo_name=pull_request.target_repo.repo_name))
911 repo_name=pull_request.target_repo.repo_name))
912 response.mustcontain(
912 response.mustcontain(
913 "&lt;script&gt;alert(&#39;Hi!&#39;)&lt;/script&gt;")
913 "&lt;script&gt;alert(&#39;Hi!&#39;)&lt;/script&gt;")
914
914
915 @pytest.mark.parametrize('mergeable', [True, False])
916 def test_shadow_repository_link(
917 self, mergeable, pr_util, http_host_stub):
918 """
919 Check that the pull request summary page displays a link to the shadow
920 repository if the pull request is mergeable. If it is not mergeable
921 the link should not be displayed.
922 """
923 pull_request = pr_util.create_pull_request(
924 mergeable=mergeable, enable_notifications=False)
925 target_repo = pull_request.target_repo.scm_instance()
926 pr_id = pull_request.pull_request_id
927 shadow_url = '{host}/{repo}/pull-request/{pr_id}/repository'.format(
928 host=http_host_stub, repo=target_repo.name, pr_id=pr_id)
929
930 response = self.app.get(url(
931 controller='pullrequests', action='show',
932 repo_name=target_repo.name,
933 pull_request_id=str(pr_id)))
934
935 assertr = AssertResponse(response)
936 if mergeable:
937 assertr.element_value_contains(
938 'div.pr-mergeinfo input', shadow_url)
939 assertr.element_value_contains(
940 'div.pr-mergeinfo input', 'pr-merge')
941 else:
942 assertr.no_element_exists('div.pr-mergeinfo')
943
915
944
916 def assert_pull_request_status(pull_request, expected_status):
945 def assert_pull_request_status(pull_request, expected_status):
917 status = ChangesetStatusModel().calculated_review_status(
946 status = ChangesetStatusModel().calculated_review_status(
918 pull_request=pull_request)
947 pull_request=pull_request)
919 assert status == expected_status
948 assert status == expected_status
920
949
921
950
922 @pytest.mark.parametrize('action', ['show_all', 'index', 'create'])
951 @pytest.mark.parametrize('action', ['show_all', 'index', 'create'])
923 @pytest.mark.usefixtures("autologin_user")
952 @pytest.mark.usefixtures("autologin_user")
924 def test_redirects_to_repo_summary_for_svn_repositories(
953 def test_redirects_to_repo_summary_for_svn_repositories(
925 backend_svn, app, action):
954 backend_svn, app, action):
926 denied_actions = ['show_all', 'index', 'create']
955 denied_actions = ['show_all', 'index', 'create']
927 for action in denied_actions:
956 for action in denied_actions:
928 response = app.get(url(
957 response = app.get(url(
929 controller='pullrequests', action=action,
958 controller='pullrequests', action=action,
930 repo_name=backend_svn.repo_name))
959 repo_name=backend_svn.repo_name))
931 assert response.status_int == 302
960 assert response.status_int == 302
932
961
933 # Not allowed, redirect to the summary
962 # Not allowed, redirect to the summary
934 redirected = response.follow()
963 redirected = response.follow()
935 summary_url = url('summary_home', repo_name=backend_svn.repo_name)
964 summary_url = url('summary_home', repo_name=backend_svn.repo_name)
936
965
937 # URL adds leading slash and path doesn't have it
966 # URL adds leading slash and path doesn't have it
938 assert redirected.req.path == summary_url
967 assert redirected.req.path == summary_url
939
968
940
969
941 def test_delete_comment_returns_404_if_comment_does_not_exist(pylonsapp):
970 def test_delete_comment_returns_404_if_comment_does_not_exist(pylonsapp):
942 # TODO: johbo: Global import not possible because models.forms blows up
971 # TODO: johbo: Global import not possible because models.forms blows up
943 from rhodecode.controllers.pullrequests import PullrequestsController
972 from rhodecode.controllers.pullrequests import PullrequestsController
944 controller = PullrequestsController()
973 controller = PullrequestsController()
945 patcher = mock.patch(
974 patcher = mock.patch(
946 'rhodecode.model.db.BaseModel.get', return_value=None)
975 'rhodecode.model.db.BaseModel.get', return_value=None)
947 with pytest.raises(HTTPNotFound), patcher:
976 with pytest.raises(HTTPNotFound), patcher:
948 controller._delete_comment(1)
977 controller._delete_comment(1)
General Comments 0
You need to be logged in to leave comments. Login now