##// END OF EJS Templates
tests: Add test to check PR page when target reference is missing....
Martin Bornhold -
r1079:02683dd7 default
parent child Browse files
Show More
@@ -1,979 +1,1001 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 from rhodecode.lib.vcs.backends.base import UpdateFailureReason
190 from rhodecode.lib.vcs.backends.base import UpdateFailureReason
191
191
192 pull_request = pr_util.create_pull_request()
192 pull_request = pr_util.create_pull_request()
193 pull_request.source_ref = 'branch:invalid-branch:invalid-commit-id'
193 pull_request.source_ref = 'branch:invalid-branch:invalid-commit-id'
194 Session().add(pull_request)
194 Session().add(pull_request)
195 Session().commit()
195 Session().commit()
196
196
197 pull_request_id = pull_request.pull_request_id
197 pull_request_id = pull_request.pull_request_id
198
198
199 response = self.app.post(
199 response = self.app.post(
200 url(controller='pullrequests', action='update',
200 url(controller='pullrequests', action='update',
201 repo_name=pull_request.target_repo.repo_name,
201 repo_name=pull_request.target_repo.repo_name,
202 pull_request_id=str(pull_request_id)),
202 pull_request_id=str(pull_request_id)),
203 params={'update_commits': 'true', '_method': 'put',
203 params={'update_commits': 'true', '_method': 'put',
204 'csrf_token': csrf_token})
204 'csrf_token': csrf_token})
205
205
206 expected_msg = PullRequestModel.UPDATE_STATUS_MESSAGES[
206 expected_msg = PullRequestModel.UPDATE_STATUS_MESSAGES[
207 UpdateFailureReason.MISSING_SOURCE_REF]
207 UpdateFailureReason.MISSING_SOURCE_REF]
208 assert_session_flash(response, expected_msg, category='error')
208 assert_session_flash(response, expected_msg, category='error')
209
209
210 def test_missing_target_reference(self, pr_util, csrf_token):
211 from rhodecode.lib.vcs.backends.base import MergeFailureReason
212 pull_request = pr_util.create_pull_request(
213 approved=True, mergeable=True)
214 pull_request.target_ref = 'branch:invalid-branch:invalid-commit-id'
215 Session().add(pull_request)
216 Session().commit()
217
218 pull_request_id = pull_request.pull_request_id
219 pull_request_url = url(
220 controller='pullrequests', action='show',
221 repo_name=pull_request.target_repo.repo_name,
222 pull_request_id=str(pull_request_id))
223
224 response = self.app.get(pull_request_url)
225
226 assertr = AssertResponse(response)
227 expected_msg = PullRequestModel.MERGE_STATUS_MESSAGES[
228 MergeFailureReason.MISSING_TARGET_REF]
229 assertr.element_contains(
230 'span[data-role="merge-message"]', str(expected_msg))
231
210 def test_comment_and_close_pull_request(self, pr_util, csrf_token):
232 def test_comment_and_close_pull_request(self, pr_util, csrf_token):
211 pull_request = pr_util.create_pull_request(approved=True)
233 pull_request = pr_util.create_pull_request(approved=True)
212 pull_request_id = pull_request.pull_request_id
234 pull_request_id = pull_request.pull_request_id
213 author = pull_request.user_id
235 author = pull_request.user_id
214 repo = pull_request.target_repo.repo_id
236 repo = pull_request.target_repo.repo_id
215
237
216 self.app.post(
238 self.app.post(
217 url(controller='pullrequests',
239 url(controller='pullrequests',
218 action='comment',
240 action='comment',
219 repo_name=pull_request.target_repo.scm_instance().name,
241 repo_name=pull_request.target_repo.scm_instance().name,
220 pull_request_id=str(pull_request_id)),
242 pull_request_id=str(pull_request_id)),
221 params={
243 params={
222 'changeset_status':
244 'changeset_status':
223 ChangesetStatus.STATUS_APPROVED + '_closed',
245 ChangesetStatus.STATUS_APPROVED + '_closed',
224 'change_changeset_status': 'on',
246 'change_changeset_status': 'on',
225 'text': '',
247 'text': '',
226 'csrf_token': csrf_token},
248 'csrf_token': csrf_token},
227 status=302)
249 status=302)
228
250
229 action = 'user_closed_pull_request:%d' % pull_request_id
251 action = 'user_closed_pull_request:%d' % pull_request_id
230 journal = UserLog.query()\
252 journal = UserLog.query()\
231 .filter(UserLog.user_id == author)\
253 .filter(UserLog.user_id == author)\
232 .filter(UserLog.repository_id == repo)\
254 .filter(UserLog.repository_id == repo)\
233 .filter(UserLog.action == action)\
255 .filter(UserLog.action == action)\
234 .all()
256 .all()
235 assert len(journal) == 1
257 assert len(journal) == 1
236
258
237 def test_reject_and_close_pull_request(self, pr_util, csrf_token):
259 def test_reject_and_close_pull_request(self, pr_util, csrf_token):
238 pull_request = pr_util.create_pull_request()
260 pull_request = pr_util.create_pull_request()
239 pull_request_id = pull_request.pull_request_id
261 pull_request_id = pull_request.pull_request_id
240 response = self.app.post(
262 response = self.app.post(
241 url(controller='pullrequests',
263 url(controller='pullrequests',
242 action='update',
264 action='update',
243 repo_name=pull_request.target_repo.scm_instance().name,
265 repo_name=pull_request.target_repo.scm_instance().name,
244 pull_request_id=str(pull_request.pull_request_id)),
266 pull_request_id=str(pull_request.pull_request_id)),
245 params={'close_pull_request': 'true', '_method': 'put',
267 params={'close_pull_request': 'true', '_method': 'put',
246 'csrf_token': csrf_token})
268 'csrf_token': csrf_token})
247
269
248 pull_request = PullRequest.get(pull_request_id)
270 pull_request = PullRequest.get(pull_request_id)
249
271
250 assert response.json is True
272 assert response.json is True
251 assert pull_request.is_closed()
273 assert pull_request.is_closed()
252
274
253 # check only the latest status, not the review status
275 # check only the latest status, not the review status
254 status = ChangesetStatusModel().get_status(
276 status = ChangesetStatusModel().get_status(
255 pull_request.source_repo, pull_request=pull_request)
277 pull_request.source_repo, pull_request=pull_request)
256 assert status == ChangesetStatus.STATUS_REJECTED
278 assert status == ChangesetStatus.STATUS_REJECTED
257
279
258 def test_comment_force_close_pull_request(self, pr_util, csrf_token):
280 def test_comment_force_close_pull_request(self, pr_util, csrf_token):
259 pull_request = pr_util.create_pull_request()
281 pull_request = pr_util.create_pull_request()
260 pull_request_id = pull_request.pull_request_id
282 pull_request_id = pull_request.pull_request_id
261 reviewers_data = [(1, ['reason']), (2, ['reason2'])]
283 reviewers_data = [(1, ['reason']), (2, ['reason2'])]
262 PullRequestModel().update_reviewers(pull_request_id, reviewers_data)
284 PullRequestModel().update_reviewers(pull_request_id, reviewers_data)
263 author = pull_request.user_id
285 author = pull_request.user_id
264 repo = pull_request.target_repo.repo_id
286 repo = pull_request.target_repo.repo_id
265 self.app.post(
287 self.app.post(
266 url(controller='pullrequests',
288 url(controller='pullrequests',
267 action='comment',
289 action='comment',
268 repo_name=pull_request.target_repo.scm_instance().name,
290 repo_name=pull_request.target_repo.scm_instance().name,
269 pull_request_id=str(pull_request_id)),
291 pull_request_id=str(pull_request_id)),
270 params={
292 params={
271 'changeset_status': 'forced_closed',
293 'changeset_status': 'forced_closed',
272 'csrf_token': csrf_token},
294 'csrf_token': csrf_token},
273 status=302)
295 status=302)
274
296
275 pull_request = PullRequest.get(pull_request_id)
297 pull_request = PullRequest.get(pull_request_id)
276
298
277 action = 'user_closed_pull_request:%d' % pull_request_id
299 action = 'user_closed_pull_request:%d' % pull_request_id
278 journal = UserLog.query().filter(
300 journal = UserLog.query().filter(
279 UserLog.user_id == author,
301 UserLog.user_id == author,
280 UserLog.repository_id == repo,
302 UserLog.repository_id == repo,
281 UserLog.action == action).all()
303 UserLog.action == action).all()
282 assert len(journal) == 1
304 assert len(journal) == 1
283
305
284 # check only the latest status, not the review status
306 # check only the latest status, not the review status
285 status = ChangesetStatusModel().get_status(
307 status = ChangesetStatusModel().get_status(
286 pull_request.source_repo, pull_request=pull_request)
308 pull_request.source_repo, pull_request=pull_request)
287 assert status == ChangesetStatus.STATUS_REJECTED
309 assert status == ChangesetStatus.STATUS_REJECTED
288
310
289 def test_create_pull_request(self, backend, csrf_token):
311 def test_create_pull_request(self, backend, csrf_token):
290 commits = [
312 commits = [
291 {'message': 'ancestor'},
313 {'message': 'ancestor'},
292 {'message': 'change'},
314 {'message': 'change'},
293 {'message': 'change2'},
315 {'message': 'change2'},
294 ]
316 ]
295 commit_ids = backend.create_master_repo(commits)
317 commit_ids = backend.create_master_repo(commits)
296 target = backend.create_repo(heads=['ancestor'])
318 target = backend.create_repo(heads=['ancestor'])
297 source = backend.create_repo(heads=['change2'])
319 source = backend.create_repo(heads=['change2'])
298
320
299 response = self.app.post(
321 response = self.app.post(
300 url(
322 url(
301 controller='pullrequests',
323 controller='pullrequests',
302 action='create',
324 action='create',
303 repo_name=source.repo_name
325 repo_name=source.repo_name
304 ),
326 ),
305 [
327 [
306 ('source_repo', source.repo_name),
328 ('source_repo', source.repo_name),
307 ('source_ref', 'branch:default:' + commit_ids['change2']),
329 ('source_ref', 'branch:default:' + commit_ids['change2']),
308 ('target_repo', target.repo_name),
330 ('target_repo', target.repo_name),
309 ('target_ref', 'branch:default:' + commit_ids['ancestor']),
331 ('target_ref', 'branch:default:' + commit_ids['ancestor']),
310 ('pullrequest_desc', 'Description'),
332 ('pullrequest_desc', 'Description'),
311 ('pullrequest_title', 'Title'),
333 ('pullrequest_title', 'Title'),
312 ('__start__', 'review_members:sequence'),
334 ('__start__', 'review_members:sequence'),
313 ('__start__', 'reviewer:mapping'),
335 ('__start__', 'reviewer:mapping'),
314 ('user_id', '1'),
336 ('user_id', '1'),
315 ('__start__', 'reasons:sequence'),
337 ('__start__', 'reasons:sequence'),
316 ('reason', 'Some reason'),
338 ('reason', 'Some reason'),
317 ('__end__', 'reasons:sequence'),
339 ('__end__', 'reasons:sequence'),
318 ('__end__', 'reviewer:mapping'),
340 ('__end__', 'reviewer:mapping'),
319 ('__end__', 'review_members:sequence'),
341 ('__end__', 'review_members:sequence'),
320 ('__start__', 'revisions:sequence'),
342 ('__start__', 'revisions:sequence'),
321 ('revisions', commit_ids['change']),
343 ('revisions', commit_ids['change']),
322 ('revisions', commit_ids['change2']),
344 ('revisions', commit_ids['change2']),
323 ('__end__', 'revisions:sequence'),
345 ('__end__', 'revisions:sequence'),
324 ('user', ''),
346 ('user', ''),
325 ('csrf_token', csrf_token),
347 ('csrf_token', csrf_token),
326 ],
348 ],
327 status=302)
349 status=302)
328
350
329 location = response.headers['Location']
351 location = response.headers['Location']
330 pull_request_id = int(location.rsplit('/', 1)[1])
352 pull_request_id = int(location.rsplit('/', 1)[1])
331 pull_request = PullRequest.get(pull_request_id)
353 pull_request = PullRequest.get(pull_request_id)
332
354
333 # check that we have now both revisions
355 # check that we have now both revisions
334 assert pull_request.revisions == [commit_ids['change2'], commit_ids['change']]
356 assert pull_request.revisions == [commit_ids['change2'], commit_ids['change']]
335 assert pull_request.source_ref == 'branch:default:' + commit_ids['change2']
357 assert pull_request.source_ref == 'branch:default:' + commit_ids['change2']
336 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
358 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
337 assert pull_request.target_ref == expected_target_ref
359 assert pull_request.target_ref == expected_target_ref
338
360
339 def test_reviewer_notifications(self, backend, csrf_token):
361 def test_reviewer_notifications(self, backend, csrf_token):
340 # We have to use the app.post for this test so it will create the
362 # We have to use the app.post for this test so it will create the
341 # notifications properly with the new PR
363 # notifications properly with the new PR
342 commits = [
364 commits = [
343 {'message': 'ancestor',
365 {'message': 'ancestor',
344 'added': [FileNode('file_A', content='content_of_ancestor')]},
366 'added': [FileNode('file_A', content='content_of_ancestor')]},
345 {'message': 'change',
367 {'message': 'change',
346 'added': [FileNode('file_a', content='content_of_change')]},
368 'added': [FileNode('file_a', content='content_of_change')]},
347 {'message': 'change-child'},
369 {'message': 'change-child'},
348 {'message': 'ancestor-child', 'parents': ['ancestor'],
370 {'message': 'ancestor-child', 'parents': ['ancestor'],
349 'added': [
371 'added': [
350 FileNode('file_B', content='content_of_ancestor_child')]},
372 FileNode('file_B', content='content_of_ancestor_child')]},
351 {'message': 'ancestor-child-2'},
373 {'message': 'ancestor-child-2'},
352 ]
374 ]
353 commit_ids = backend.create_master_repo(commits)
375 commit_ids = backend.create_master_repo(commits)
354 target = backend.create_repo(heads=['ancestor-child'])
376 target = backend.create_repo(heads=['ancestor-child'])
355 source = backend.create_repo(heads=['change'])
377 source = backend.create_repo(heads=['change'])
356
378
357 response = self.app.post(
379 response = self.app.post(
358 url(
380 url(
359 controller='pullrequests',
381 controller='pullrequests',
360 action='create',
382 action='create',
361 repo_name=source.repo_name
383 repo_name=source.repo_name
362 ),
384 ),
363 [
385 [
364 ('source_repo', source.repo_name),
386 ('source_repo', source.repo_name),
365 ('source_ref', 'branch:default:' + commit_ids['change']),
387 ('source_ref', 'branch:default:' + commit_ids['change']),
366 ('target_repo', target.repo_name),
388 ('target_repo', target.repo_name),
367 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
389 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
368 ('pullrequest_desc', 'Description'),
390 ('pullrequest_desc', 'Description'),
369 ('pullrequest_title', 'Title'),
391 ('pullrequest_title', 'Title'),
370 ('__start__', 'review_members:sequence'),
392 ('__start__', 'review_members:sequence'),
371 ('__start__', 'reviewer:mapping'),
393 ('__start__', 'reviewer:mapping'),
372 ('user_id', '2'),
394 ('user_id', '2'),
373 ('__start__', 'reasons:sequence'),
395 ('__start__', 'reasons:sequence'),
374 ('reason', 'Some reason'),
396 ('reason', 'Some reason'),
375 ('__end__', 'reasons:sequence'),
397 ('__end__', 'reasons:sequence'),
376 ('__end__', 'reviewer:mapping'),
398 ('__end__', 'reviewer:mapping'),
377 ('__end__', 'review_members:sequence'),
399 ('__end__', 'review_members:sequence'),
378 ('__start__', 'revisions:sequence'),
400 ('__start__', 'revisions:sequence'),
379 ('revisions', commit_ids['change']),
401 ('revisions', commit_ids['change']),
380 ('__end__', 'revisions:sequence'),
402 ('__end__', 'revisions:sequence'),
381 ('user', ''),
403 ('user', ''),
382 ('csrf_token', csrf_token),
404 ('csrf_token', csrf_token),
383 ],
405 ],
384 status=302)
406 status=302)
385
407
386 location = response.headers['Location']
408 location = response.headers['Location']
387 pull_request_id = int(location.rsplit('/', 1)[1])
409 pull_request_id = int(location.rsplit('/', 1)[1])
388 pull_request = PullRequest.get(pull_request_id)
410 pull_request = PullRequest.get(pull_request_id)
389
411
390 # Check that a notification was made
412 # Check that a notification was made
391 notifications = Notification.query()\
413 notifications = Notification.query()\
392 .filter(Notification.created_by == pull_request.author.user_id,
414 .filter(Notification.created_by == pull_request.author.user_id,
393 Notification.type_ == Notification.TYPE_PULL_REQUEST,
415 Notification.type_ == Notification.TYPE_PULL_REQUEST,
394 Notification.subject.contains("wants you to review "
416 Notification.subject.contains("wants you to review "
395 "pull request #%d"
417 "pull request #%d"
396 % pull_request_id))
418 % pull_request_id))
397 assert len(notifications.all()) == 1
419 assert len(notifications.all()) == 1
398
420
399 # Change reviewers and check that a notification was made
421 # Change reviewers and check that a notification was made
400 PullRequestModel().update_reviewers(
422 PullRequestModel().update_reviewers(
401 pull_request.pull_request_id, [(1, [])])
423 pull_request.pull_request_id, [(1, [])])
402 assert len(notifications.all()) == 2
424 assert len(notifications.all()) == 2
403
425
404 def test_create_pull_request_stores_ancestor_commit_id(self, backend,
426 def test_create_pull_request_stores_ancestor_commit_id(self, backend,
405 csrf_token):
427 csrf_token):
406 commits = [
428 commits = [
407 {'message': 'ancestor',
429 {'message': 'ancestor',
408 'added': [FileNode('file_A', content='content_of_ancestor')]},
430 'added': [FileNode('file_A', content='content_of_ancestor')]},
409 {'message': 'change',
431 {'message': 'change',
410 'added': [FileNode('file_a', content='content_of_change')]},
432 'added': [FileNode('file_a', content='content_of_change')]},
411 {'message': 'change-child'},
433 {'message': 'change-child'},
412 {'message': 'ancestor-child', 'parents': ['ancestor'],
434 {'message': 'ancestor-child', 'parents': ['ancestor'],
413 'added': [
435 'added': [
414 FileNode('file_B', content='content_of_ancestor_child')]},
436 FileNode('file_B', content='content_of_ancestor_child')]},
415 {'message': 'ancestor-child-2'},
437 {'message': 'ancestor-child-2'},
416 ]
438 ]
417 commit_ids = backend.create_master_repo(commits)
439 commit_ids = backend.create_master_repo(commits)
418 target = backend.create_repo(heads=['ancestor-child'])
440 target = backend.create_repo(heads=['ancestor-child'])
419 source = backend.create_repo(heads=['change'])
441 source = backend.create_repo(heads=['change'])
420
442
421 response = self.app.post(
443 response = self.app.post(
422 url(
444 url(
423 controller='pullrequests',
445 controller='pullrequests',
424 action='create',
446 action='create',
425 repo_name=source.repo_name
447 repo_name=source.repo_name
426 ),
448 ),
427 [
449 [
428 ('source_repo', source.repo_name),
450 ('source_repo', source.repo_name),
429 ('source_ref', 'branch:default:' + commit_ids['change']),
451 ('source_ref', 'branch:default:' + commit_ids['change']),
430 ('target_repo', target.repo_name),
452 ('target_repo', target.repo_name),
431 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
453 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
432 ('pullrequest_desc', 'Description'),
454 ('pullrequest_desc', 'Description'),
433 ('pullrequest_title', 'Title'),
455 ('pullrequest_title', 'Title'),
434 ('__start__', 'review_members:sequence'),
456 ('__start__', 'review_members:sequence'),
435 ('__start__', 'reviewer:mapping'),
457 ('__start__', 'reviewer:mapping'),
436 ('user_id', '1'),
458 ('user_id', '1'),
437 ('__start__', 'reasons:sequence'),
459 ('__start__', 'reasons:sequence'),
438 ('reason', 'Some reason'),
460 ('reason', 'Some reason'),
439 ('__end__', 'reasons:sequence'),
461 ('__end__', 'reasons:sequence'),
440 ('__end__', 'reviewer:mapping'),
462 ('__end__', 'reviewer:mapping'),
441 ('__end__', 'review_members:sequence'),
463 ('__end__', 'review_members:sequence'),
442 ('__start__', 'revisions:sequence'),
464 ('__start__', 'revisions:sequence'),
443 ('revisions', commit_ids['change']),
465 ('revisions', commit_ids['change']),
444 ('__end__', 'revisions:sequence'),
466 ('__end__', 'revisions:sequence'),
445 ('user', ''),
467 ('user', ''),
446 ('csrf_token', csrf_token),
468 ('csrf_token', csrf_token),
447 ],
469 ],
448 status=302)
470 status=302)
449
471
450 location = response.headers['Location']
472 location = response.headers['Location']
451 pull_request_id = int(location.rsplit('/', 1)[1])
473 pull_request_id = int(location.rsplit('/', 1)[1])
452 pull_request = PullRequest.get(pull_request_id)
474 pull_request = PullRequest.get(pull_request_id)
453
475
454 # target_ref has to point to the ancestor's commit_id in order to
476 # target_ref has to point to the ancestor's commit_id in order to
455 # show the correct diff
477 # show the correct diff
456 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
478 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
457 assert pull_request.target_ref == expected_target_ref
479 assert pull_request.target_ref == expected_target_ref
458
480
459 # Check generated diff contents
481 # Check generated diff contents
460 response = response.follow()
482 response = response.follow()
461 assert 'content_of_ancestor' not in response.body
483 assert 'content_of_ancestor' not in response.body
462 assert 'content_of_ancestor-child' not in response.body
484 assert 'content_of_ancestor-child' not in response.body
463 assert 'content_of_change' in response.body
485 assert 'content_of_change' in response.body
464
486
465 def test_merge_pull_request_enabled(self, pr_util, csrf_token):
487 def test_merge_pull_request_enabled(self, pr_util, csrf_token):
466 # Clear any previous calls to rcextensions
488 # Clear any previous calls to rcextensions
467 rhodecode.EXTENSIONS.calls.clear()
489 rhodecode.EXTENSIONS.calls.clear()
468
490
469 pull_request = pr_util.create_pull_request(
491 pull_request = pr_util.create_pull_request(
470 approved=True, mergeable=True)
492 approved=True, mergeable=True)
471 pull_request_id = pull_request.pull_request_id
493 pull_request_id = pull_request.pull_request_id
472 repo_name = pull_request.target_repo.scm_instance().name,
494 repo_name = pull_request.target_repo.scm_instance().name,
473
495
474 response = self.app.post(
496 response = self.app.post(
475 url(controller='pullrequests',
497 url(controller='pullrequests',
476 action='merge',
498 action='merge',
477 repo_name=str(repo_name[0]),
499 repo_name=str(repo_name[0]),
478 pull_request_id=str(pull_request_id)),
500 pull_request_id=str(pull_request_id)),
479 params={'csrf_token': csrf_token}).follow()
501 params={'csrf_token': csrf_token}).follow()
480
502
481 pull_request = PullRequest.get(pull_request_id)
503 pull_request = PullRequest.get(pull_request_id)
482
504
483 assert response.status_int == 200
505 assert response.status_int == 200
484 assert pull_request.is_closed()
506 assert pull_request.is_closed()
485 assert_pull_request_status(
507 assert_pull_request_status(
486 pull_request, ChangesetStatus.STATUS_APPROVED)
508 pull_request, ChangesetStatus.STATUS_APPROVED)
487
509
488 # Check the relevant log entries were added
510 # Check the relevant log entries were added
489 user_logs = UserLog.query().order_by('-user_log_id').limit(4)
511 user_logs = UserLog.query().order_by('-user_log_id').limit(4)
490 actions = [log.action for log in user_logs]
512 actions = [log.action for log in user_logs]
491 pr_commit_ids = PullRequestModel()._get_commit_ids(pull_request)
513 pr_commit_ids = PullRequestModel()._get_commit_ids(pull_request)
492 expected_actions = [
514 expected_actions = [
493 u'user_closed_pull_request:%d' % pull_request_id,
515 u'user_closed_pull_request:%d' % pull_request_id,
494 u'user_merged_pull_request:%d' % pull_request_id,
516 u'user_merged_pull_request:%d' % pull_request_id,
495 # The action below reflect that the post push actions were executed
517 # The action below reflect that the post push actions were executed
496 u'user_commented_pull_request:%d' % pull_request_id,
518 u'user_commented_pull_request:%d' % pull_request_id,
497 u'push:%s' % ','.join(pr_commit_ids),
519 u'push:%s' % ','.join(pr_commit_ids),
498 ]
520 ]
499 assert actions == expected_actions
521 assert actions == expected_actions
500
522
501 # Check post_push rcextension was really executed
523 # Check post_push rcextension was really executed
502 push_calls = rhodecode.EXTENSIONS.calls['post_push']
524 push_calls = rhodecode.EXTENSIONS.calls['post_push']
503 assert len(push_calls) == 1
525 assert len(push_calls) == 1
504 unused_last_call_args, last_call_kwargs = push_calls[0]
526 unused_last_call_args, last_call_kwargs = push_calls[0]
505 assert last_call_kwargs['action'] == 'push'
527 assert last_call_kwargs['action'] == 'push'
506 assert last_call_kwargs['pushed_revs'] == pr_commit_ids
528 assert last_call_kwargs['pushed_revs'] == pr_commit_ids
507
529
508 def test_merge_pull_request_disabled(self, pr_util, csrf_token):
530 def test_merge_pull_request_disabled(self, pr_util, csrf_token):
509 pull_request = pr_util.create_pull_request(mergeable=False)
531 pull_request = pr_util.create_pull_request(mergeable=False)
510 pull_request_id = pull_request.pull_request_id
532 pull_request_id = pull_request.pull_request_id
511 pull_request = PullRequest.get(pull_request_id)
533 pull_request = PullRequest.get(pull_request_id)
512
534
513 response = self.app.post(
535 response = self.app.post(
514 url(controller='pullrequests',
536 url(controller='pullrequests',
515 action='merge',
537 action='merge',
516 repo_name=pull_request.target_repo.scm_instance().name,
538 repo_name=pull_request.target_repo.scm_instance().name,
517 pull_request_id=str(pull_request.pull_request_id)),
539 pull_request_id=str(pull_request.pull_request_id)),
518 params={'csrf_token': csrf_token}).follow()
540 params={'csrf_token': csrf_token}).follow()
519
541
520 assert response.status_int == 200
542 assert response.status_int == 200
521 assert 'Server-side pull request merging is disabled.' in response.body
543 assert 'Server-side pull request merging is disabled.' in response.body
522
544
523 @pytest.mark.skip_backends('svn')
545 @pytest.mark.skip_backends('svn')
524 def test_merge_pull_request_not_approved(self, pr_util, csrf_token):
546 def test_merge_pull_request_not_approved(self, pr_util, csrf_token):
525 pull_request = pr_util.create_pull_request(mergeable=True)
547 pull_request = pr_util.create_pull_request(mergeable=True)
526 pull_request_id = pull_request.pull_request_id
548 pull_request_id = pull_request.pull_request_id
527 repo_name = pull_request.target_repo.scm_instance().name,
549 repo_name = pull_request.target_repo.scm_instance().name,
528
550
529 response = self.app.post(
551 response = self.app.post(
530 url(controller='pullrequests',
552 url(controller='pullrequests',
531 action='merge',
553 action='merge',
532 repo_name=str(repo_name[0]),
554 repo_name=str(repo_name[0]),
533 pull_request_id=str(pull_request_id)),
555 pull_request_id=str(pull_request_id)),
534 params={'csrf_token': csrf_token}).follow()
556 params={'csrf_token': csrf_token}).follow()
535
557
536 pull_request = PullRequest.get(pull_request_id)
558 pull_request = PullRequest.get(pull_request_id)
537
559
538 assert response.status_int == 200
560 assert response.status_int == 200
539 assert ' Reviewer approval is pending.' in response.body
561 assert ' Reviewer approval is pending.' in response.body
540
562
541 def test_update_source_revision(self, backend, csrf_token):
563 def test_update_source_revision(self, backend, csrf_token):
542 commits = [
564 commits = [
543 {'message': 'ancestor'},
565 {'message': 'ancestor'},
544 {'message': 'change'},
566 {'message': 'change'},
545 {'message': 'change-2'},
567 {'message': 'change-2'},
546 ]
568 ]
547 commit_ids = backend.create_master_repo(commits)
569 commit_ids = backend.create_master_repo(commits)
548 target = backend.create_repo(heads=['ancestor'])
570 target = backend.create_repo(heads=['ancestor'])
549 source = backend.create_repo(heads=['change'])
571 source = backend.create_repo(heads=['change'])
550
572
551 # create pr from a in source to A in target
573 # create pr from a in source to A in target
552 pull_request = PullRequest()
574 pull_request = PullRequest()
553 pull_request.source_repo = source
575 pull_request.source_repo = source
554 # TODO: johbo: Make sure that we write the source ref this way!
576 # TODO: johbo: Make sure that we write the source ref this way!
555 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
577 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
556 branch=backend.default_branch_name, commit_id=commit_ids['change'])
578 branch=backend.default_branch_name, commit_id=commit_ids['change'])
557 pull_request.target_repo = target
579 pull_request.target_repo = target
558
580
559 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
581 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
560 branch=backend.default_branch_name,
582 branch=backend.default_branch_name,
561 commit_id=commit_ids['ancestor'])
583 commit_id=commit_ids['ancestor'])
562 pull_request.revisions = [commit_ids['change']]
584 pull_request.revisions = [commit_ids['change']]
563 pull_request.title = u"Test"
585 pull_request.title = u"Test"
564 pull_request.description = u"Description"
586 pull_request.description = u"Description"
565 pull_request.author = UserModel().get_by_username(
587 pull_request.author = UserModel().get_by_username(
566 TEST_USER_ADMIN_LOGIN)
588 TEST_USER_ADMIN_LOGIN)
567 Session().add(pull_request)
589 Session().add(pull_request)
568 Session().commit()
590 Session().commit()
569 pull_request_id = pull_request.pull_request_id
591 pull_request_id = pull_request.pull_request_id
570
592
571 # source has ancestor - change - change-2
593 # source has ancestor - change - change-2
572 backend.pull_heads(source, heads=['change-2'])
594 backend.pull_heads(source, heads=['change-2'])
573
595
574 # update PR
596 # update PR
575 self.app.post(
597 self.app.post(
576 url(controller='pullrequests', action='update',
598 url(controller='pullrequests', action='update',
577 repo_name=target.repo_name,
599 repo_name=target.repo_name,
578 pull_request_id=str(pull_request_id)),
600 pull_request_id=str(pull_request_id)),
579 params={'update_commits': 'true', '_method': 'put',
601 params={'update_commits': 'true', '_method': 'put',
580 'csrf_token': csrf_token})
602 'csrf_token': csrf_token})
581
603
582 # check that we have now both revisions
604 # check that we have now both revisions
583 pull_request = PullRequest.get(pull_request_id)
605 pull_request = PullRequest.get(pull_request_id)
584 assert pull_request.revisions == [
606 assert pull_request.revisions == [
585 commit_ids['change-2'], commit_ids['change']]
607 commit_ids['change-2'], commit_ids['change']]
586
608
587 # TODO: johbo: this should be a test on its own
609 # TODO: johbo: this should be a test on its own
588 response = self.app.get(url(
610 response = self.app.get(url(
589 controller='pullrequests', action='index',
611 controller='pullrequests', action='index',
590 repo_name=target.repo_name))
612 repo_name=target.repo_name))
591 assert response.status_int == 200
613 assert response.status_int == 200
592 assert 'Pull request updated to' in response.body
614 assert 'Pull request updated to' in response.body
593 assert 'with 1 added, 0 removed commits.' in response.body
615 assert 'with 1 added, 0 removed commits.' in response.body
594
616
595 def test_update_target_revision(self, backend, csrf_token):
617 def test_update_target_revision(self, backend, csrf_token):
596 commits = [
618 commits = [
597 {'message': 'ancestor'},
619 {'message': 'ancestor'},
598 {'message': 'change'},
620 {'message': 'change'},
599 {'message': 'ancestor-new', 'parents': ['ancestor']},
621 {'message': 'ancestor-new', 'parents': ['ancestor']},
600 {'message': 'change-rebased'},
622 {'message': 'change-rebased'},
601 ]
623 ]
602 commit_ids = backend.create_master_repo(commits)
624 commit_ids = backend.create_master_repo(commits)
603 target = backend.create_repo(heads=['ancestor'])
625 target = backend.create_repo(heads=['ancestor'])
604 source = backend.create_repo(heads=['change'])
626 source = backend.create_repo(heads=['change'])
605
627
606 # create pr from a in source to A in target
628 # create pr from a in source to A in target
607 pull_request = PullRequest()
629 pull_request = PullRequest()
608 pull_request.source_repo = source
630 pull_request.source_repo = source
609 # TODO: johbo: Make sure that we write the source ref this way!
631 # TODO: johbo: Make sure that we write the source ref this way!
610 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
632 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
611 branch=backend.default_branch_name, commit_id=commit_ids['change'])
633 branch=backend.default_branch_name, commit_id=commit_ids['change'])
612 pull_request.target_repo = target
634 pull_request.target_repo = target
613 # TODO: johbo: Target ref should be branch based, since tip can jump
635 # TODO: johbo: Target ref should be branch based, since tip can jump
614 # from branch to branch
636 # from branch to branch
615 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
637 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
616 branch=backend.default_branch_name,
638 branch=backend.default_branch_name,
617 commit_id=commit_ids['ancestor'])
639 commit_id=commit_ids['ancestor'])
618 pull_request.revisions = [commit_ids['change']]
640 pull_request.revisions = [commit_ids['change']]
619 pull_request.title = u"Test"
641 pull_request.title = u"Test"
620 pull_request.description = u"Description"
642 pull_request.description = u"Description"
621 pull_request.author = UserModel().get_by_username(
643 pull_request.author = UserModel().get_by_username(
622 TEST_USER_ADMIN_LOGIN)
644 TEST_USER_ADMIN_LOGIN)
623 Session().add(pull_request)
645 Session().add(pull_request)
624 Session().commit()
646 Session().commit()
625 pull_request_id = pull_request.pull_request_id
647 pull_request_id = pull_request.pull_request_id
626
648
627 # target has ancestor - ancestor-new
649 # target has ancestor - ancestor-new
628 # source has ancestor - ancestor-new - change-rebased
650 # source has ancestor - ancestor-new - change-rebased
629 backend.pull_heads(target, heads=['ancestor-new'])
651 backend.pull_heads(target, heads=['ancestor-new'])
630 backend.pull_heads(source, heads=['change-rebased'])
652 backend.pull_heads(source, heads=['change-rebased'])
631
653
632 # update PR
654 # update PR
633 self.app.post(
655 self.app.post(
634 url(controller='pullrequests', action='update',
656 url(controller='pullrequests', action='update',
635 repo_name=target.repo_name,
657 repo_name=target.repo_name,
636 pull_request_id=str(pull_request_id)),
658 pull_request_id=str(pull_request_id)),
637 params={'update_commits': 'true', '_method': 'put',
659 params={'update_commits': 'true', '_method': 'put',
638 'csrf_token': csrf_token},
660 'csrf_token': csrf_token},
639 status=200)
661 status=200)
640
662
641 # check that we have now both revisions
663 # check that we have now both revisions
642 pull_request = PullRequest.get(pull_request_id)
664 pull_request = PullRequest.get(pull_request_id)
643 assert pull_request.revisions == [commit_ids['change-rebased']]
665 assert pull_request.revisions == [commit_ids['change-rebased']]
644 assert pull_request.target_ref == 'branch:{branch}:{commit_id}'.format(
666 assert pull_request.target_ref == 'branch:{branch}:{commit_id}'.format(
645 branch=backend.default_branch_name,
667 branch=backend.default_branch_name,
646 commit_id=commit_ids['ancestor-new'])
668 commit_id=commit_ids['ancestor-new'])
647
669
648 # TODO: johbo: This should be a test on its own
670 # TODO: johbo: This should be a test on its own
649 response = self.app.get(url(
671 response = self.app.get(url(
650 controller='pullrequests', action='index',
672 controller='pullrequests', action='index',
651 repo_name=target.repo_name))
673 repo_name=target.repo_name))
652 assert response.status_int == 200
674 assert response.status_int == 200
653 assert 'Pull request updated to' in response.body
675 assert 'Pull request updated to' in response.body
654 assert 'with 1 added, 1 removed commits.' in response.body
676 assert 'with 1 added, 1 removed commits.' in response.body
655
677
656 def test_update_of_ancestor_reference(self, backend, csrf_token):
678 def test_update_of_ancestor_reference(self, backend, csrf_token):
657 commits = [
679 commits = [
658 {'message': 'ancestor'},
680 {'message': 'ancestor'},
659 {'message': 'change'},
681 {'message': 'change'},
660 {'message': 'change-2'},
682 {'message': 'change-2'},
661 {'message': 'ancestor-new', 'parents': ['ancestor']},
683 {'message': 'ancestor-new', 'parents': ['ancestor']},
662 {'message': 'change-rebased'},
684 {'message': 'change-rebased'},
663 ]
685 ]
664 commit_ids = backend.create_master_repo(commits)
686 commit_ids = backend.create_master_repo(commits)
665 target = backend.create_repo(heads=['ancestor'])
687 target = backend.create_repo(heads=['ancestor'])
666 source = backend.create_repo(heads=['change'])
688 source = backend.create_repo(heads=['change'])
667
689
668 # create pr from a in source to A in target
690 # create pr from a in source to A in target
669 pull_request = PullRequest()
691 pull_request = PullRequest()
670 pull_request.source_repo = source
692 pull_request.source_repo = source
671 # TODO: johbo: Make sure that we write the source ref this way!
693 # TODO: johbo: Make sure that we write the source ref this way!
672 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
694 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
673 branch=backend.default_branch_name,
695 branch=backend.default_branch_name,
674 commit_id=commit_ids['change'])
696 commit_id=commit_ids['change'])
675 pull_request.target_repo = target
697 pull_request.target_repo = target
676 # TODO: johbo: Target ref should be branch based, since tip can jump
698 # TODO: johbo: Target ref should be branch based, since tip can jump
677 # from branch to branch
699 # from branch to branch
678 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
700 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
679 branch=backend.default_branch_name,
701 branch=backend.default_branch_name,
680 commit_id=commit_ids['ancestor'])
702 commit_id=commit_ids['ancestor'])
681 pull_request.revisions = [commit_ids['change']]
703 pull_request.revisions = [commit_ids['change']]
682 pull_request.title = u"Test"
704 pull_request.title = u"Test"
683 pull_request.description = u"Description"
705 pull_request.description = u"Description"
684 pull_request.author = UserModel().get_by_username(
706 pull_request.author = UserModel().get_by_username(
685 TEST_USER_ADMIN_LOGIN)
707 TEST_USER_ADMIN_LOGIN)
686 Session().add(pull_request)
708 Session().add(pull_request)
687 Session().commit()
709 Session().commit()
688 pull_request_id = pull_request.pull_request_id
710 pull_request_id = pull_request.pull_request_id
689
711
690 # target has ancestor - ancestor-new
712 # target has ancestor - ancestor-new
691 # source has ancestor - ancestor-new - change-rebased
713 # source has ancestor - ancestor-new - change-rebased
692 backend.pull_heads(target, heads=['ancestor-new'])
714 backend.pull_heads(target, heads=['ancestor-new'])
693 backend.pull_heads(source, heads=['change-rebased'])
715 backend.pull_heads(source, heads=['change-rebased'])
694
716
695 # update PR
717 # update PR
696 self.app.post(
718 self.app.post(
697 url(controller='pullrequests', action='update',
719 url(controller='pullrequests', action='update',
698 repo_name=target.repo_name,
720 repo_name=target.repo_name,
699 pull_request_id=str(pull_request_id)),
721 pull_request_id=str(pull_request_id)),
700 params={'update_commits': 'true', '_method': 'put',
722 params={'update_commits': 'true', '_method': 'put',
701 'csrf_token': csrf_token},
723 'csrf_token': csrf_token},
702 status=200)
724 status=200)
703
725
704 # Expect the target reference to be updated correctly
726 # Expect the target reference to be updated correctly
705 pull_request = PullRequest.get(pull_request_id)
727 pull_request = PullRequest.get(pull_request_id)
706 assert pull_request.revisions == [commit_ids['change-rebased']]
728 assert pull_request.revisions == [commit_ids['change-rebased']]
707 expected_target_ref = 'branch:{branch}:{commit_id}'.format(
729 expected_target_ref = 'branch:{branch}:{commit_id}'.format(
708 branch=backend.default_branch_name,
730 branch=backend.default_branch_name,
709 commit_id=commit_ids['ancestor-new'])
731 commit_id=commit_ids['ancestor-new'])
710 assert pull_request.target_ref == expected_target_ref
732 assert pull_request.target_ref == expected_target_ref
711
733
712 def test_remove_pull_request_branch(self, backend_git, csrf_token):
734 def test_remove_pull_request_branch(self, backend_git, csrf_token):
713 branch_name = 'development'
735 branch_name = 'development'
714 commits = [
736 commits = [
715 {'message': 'initial-commit'},
737 {'message': 'initial-commit'},
716 {'message': 'old-feature'},
738 {'message': 'old-feature'},
717 {'message': 'new-feature', 'branch': branch_name},
739 {'message': 'new-feature', 'branch': branch_name},
718 ]
740 ]
719 repo = backend_git.create_repo(commits)
741 repo = backend_git.create_repo(commits)
720 commit_ids = backend_git.commit_ids
742 commit_ids = backend_git.commit_ids
721
743
722 pull_request = PullRequest()
744 pull_request = PullRequest()
723 pull_request.source_repo = repo
745 pull_request.source_repo = repo
724 pull_request.target_repo = repo
746 pull_request.target_repo = repo
725 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
747 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
726 branch=branch_name, commit_id=commit_ids['new-feature'])
748 branch=branch_name, commit_id=commit_ids['new-feature'])
727 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
749 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
728 branch=backend_git.default_branch_name,
750 branch=backend_git.default_branch_name,
729 commit_id=commit_ids['old-feature'])
751 commit_id=commit_ids['old-feature'])
730 pull_request.revisions = [commit_ids['new-feature']]
752 pull_request.revisions = [commit_ids['new-feature']]
731 pull_request.title = u"Test"
753 pull_request.title = u"Test"
732 pull_request.description = u"Description"
754 pull_request.description = u"Description"
733 pull_request.author = UserModel().get_by_username(
755 pull_request.author = UserModel().get_by_username(
734 TEST_USER_ADMIN_LOGIN)
756 TEST_USER_ADMIN_LOGIN)
735 Session().add(pull_request)
757 Session().add(pull_request)
736 Session().commit()
758 Session().commit()
737
759
738 vcs = repo.scm_instance()
760 vcs = repo.scm_instance()
739 vcs.remove_ref('refs/heads/{}'.format(branch_name))
761 vcs.remove_ref('refs/heads/{}'.format(branch_name))
740
762
741 response = self.app.get(url(
763 response = self.app.get(url(
742 controller='pullrequests', action='show',
764 controller='pullrequests', action='show',
743 repo_name=repo.repo_name,
765 repo_name=repo.repo_name,
744 pull_request_id=str(pull_request.pull_request_id)))
766 pull_request_id=str(pull_request.pull_request_id)))
745
767
746 assert response.status_int == 200
768 assert response.status_int == 200
747 assert_response = AssertResponse(response)
769 assert_response = AssertResponse(response)
748 assert_response.element_contains(
770 assert_response.element_contains(
749 '#changeset_compare_view_content .alert strong',
771 '#changeset_compare_view_content .alert strong',
750 'Missing commits')
772 'Missing commits')
751 assert_response.element_contains(
773 assert_response.element_contains(
752 '#changeset_compare_view_content .alert',
774 '#changeset_compare_view_content .alert',
753 'This pull request cannot be displayed, because one or more'
775 'This pull request cannot be displayed, because one or more'
754 ' commits no longer exist in the source repository.')
776 ' commits no longer exist in the source repository.')
755
777
756 def test_strip_commits_from_pull_request(
778 def test_strip_commits_from_pull_request(
757 self, backend, pr_util, csrf_token):
779 self, backend, pr_util, csrf_token):
758 commits = [
780 commits = [
759 {'message': 'initial-commit'},
781 {'message': 'initial-commit'},
760 {'message': 'old-feature'},
782 {'message': 'old-feature'},
761 {'message': 'new-feature', 'parents': ['initial-commit']},
783 {'message': 'new-feature', 'parents': ['initial-commit']},
762 ]
784 ]
763 pull_request = pr_util.create_pull_request(
785 pull_request = pr_util.create_pull_request(
764 commits, target_head='initial-commit', source_head='new-feature',
786 commits, target_head='initial-commit', source_head='new-feature',
765 revisions=['new-feature'])
787 revisions=['new-feature'])
766
788
767 vcs = pr_util.source_repository.scm_instance()
789 vcs = pr_util.source_repository.scm_instance()
768 if backend.alias == 'git':
790 if backend.alias == 'git':
769 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
791 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
770 else:
792 else:
771 vcs.strip(pr_util.commit_ids['new-feature'])
793 vcs.strip(pr_util.commit_ids['new-feature'])
772
794
773 response = self.app.get(url(
795 response = self.app.get(url(
774 controller='pullrequests', action='show',
796 controller='pullrequests', action='show',
775 repo_name=pr_util.target_repository.repo_name,
797 repo_name=pr_util.target_repository.repo_name,
776 pull_request_id=str(pull_request.pull_request_id)))
798 pull_request_id=str(pull_request.pull_request_id)))
777
799
778 assert response.status_int == 200
800 assert response.status_int == 200
779 assert_response = AssertResponse(response)
801 assert_response = AssertResponse(response)
780 assert_response.element_contains(
802 assert_response.element_contains(
781 '#changeset_compare_view_content .alert strong',
803 '#changeset_compare_view_content .alert strong',
782 'Missing commits')
804 'Missing commits')
783 assert_response.element_contains(
805 assert_response.element_contains(
784 '#changeset_compare_view_content .alert',
806 '#changeset_compare_view_content .alert',
785 'This pull request cannot be displayed, because one or more'
807 'This pull request cannot be displayed, because one or more'
786 ' commits no longer exist in the source repository.')
808 ' commits no longer exist in the source repository.')
787 assert_response.element_contains(
809 assert_response.element_contains(
788 '#update_commits',
810 '#update_commits',
789 'Update commits')
811 'Update commits')
790
812
791 def test_strip_commits_and_update(
813 def test_strip_commits_and_update(
792 self, backend, pr_util, csrf_token):
814 self, backend, pr_util, csrf_token):
793 commits = [
815 commits = [
794 {'message': 'initial-commit'},
816 {'message': 'initial-commit'},
795 {'message': 'old-feature'},
817 {'message': 'old-feature'},
796 {'message': 'new-feature', 'parents': ['old-feature']},
818 {'message': 'new-feature', 'parents': ['old-feature']},
797 ]
819 ]
798 pull_request = pr_util.create_pull_request(
820 pull_request = pr_util.create_pull_request(
799 commits, target_head='old-feature', source_head='new-feature',
821 commits, target_head='old-feature', source_head='new-feature',
800 revisions=['new-feature'], mergeable=True)
822 revisions=['new-feature'], mergeable=True)
801
823
802 vcs = pr_util.source_repository.scm_instance()
824 vcs = pr_util.source_repository.scm_instance()
803 if backend.alias == 'git':
825 if backend.alias == 'git':
804 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
826 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
805 else:
827 else:
806 vcs.strip(pr_util.commit_ids['new-feature'])
828 vcs.strip(pr_util.commit_ids['new-feature'])
807
829
808 response = self.app.post(
830 response = self.app.post(
809 url(controller='pullrequests', action='update',
831 url(controller='pullrequests', action='update',
810 repo_name=pull_request.target_repo.repo_name,
832 repo_name=pull_request.target_repo.repo_name,
811 pull_request_id=str(pull_request.pull_request_id)),
833 pull_request_id=str(pull_request.pull_request_id)),
812 params={'update_commits': 'true', '_method': 'put',
834 params={'update_commits': 'true', '_method': 'put',
813 'csrf_token': csrf_token})
835 'csrf_token': csrf_token})
814
836
815 assert response.status_int == 200
837 assert response.status_int == 200
816 assert response.body == 'true'
838 assert response.body == 'true'
817
839
818 # Make sure that after update, it won't raise 500 errors
840 # Make sure that after update, it won't raise 500 errors
819 response = self.app.get(url(
841 response = self.app.get(url(
820 controller='pullrequests', action='show',
842 controller='pullrequests', action='show',
821 repo_name=pr_util.target_repository.repo_name,
843 repo_name=pr_util.target_repository.repo_name,
822 pull_request_id=str(pull_request.pull_request_id)))
844 pull_request_id=str(pull_request.pull_request_id)))
823
845
824 assert response.status_int == 200
846 assert response.status_int == 200
825 assert_response = AssertResponse(response)
847 assert_response = AssertResponse(response)
826 assert_response.element_contains(
848 assert_response.element_contains(
827 '#changeset_compare_view_content .alert strong',
849 '#changeset_compare_view_content .alert strong',
828 'Missing commits')
850 'Missing commits')
829
851
830 def test_branch_is_a_link(self, pr_util):
852 def test_branch_is_a_link(self, pr_util):
831 pull_request = pr_util.create_pull_request()
853 pull_request = pr_util.create_pull_request()
832 pull_request.source_ref = 'branch:origin:1234567890abcdef'
854 pull_request.source_ref = 'branch:origin:1234567890abcdef'
833 pull_request.target_ref = 'branch:target:abcdef1234567890'
855 pull_request.target_ref = 'branch:target:abcdef1234567890'
834 Session().add(pull_request)
856 Session().add(pull_request)
835 Session().commit()
857 Session().commit()
836
858
837 response = self.app.get(url(
859 response = self.app.get(url(
838 controller='pullrequests', action='show',
860 controller='pullrequests', action='show',
839 repo_name=pull_request.target_repo.scm_instance().name,
861 repo_name=pull_request.target_repo.scm_instance().name,
840 pull_request_id=str(pull_request.pull_request_id)))
862 pull_request_id=str(pull_request.pull_request_id)))
841 assert response.status_int == 200
863 assert response.status_int == 200
842 assert_response = AssertResponse(response)
864 assert_response = AssertResponse(response)
843
865
844 origin = assert_response.get_element('.pr-origininfo .tag')
866 origin = assert_response.get_element('.pr-origininfo .tag')
845 origin_children = origin.getchildren()
867 origin_children = origin.getchildren()
846 assert len(origin_children) == 1
868 assert len(origin_children) == 1
847 target = assert_response.get_element('.pr-targetinfo .tag')
869 target = assert_response.get_element('.pr-targetinfo .tag')
848 target_children = target.getchildren()
870 target_children = target.getchildren()
849 assert len(target_children) == 1
871 assert len(target_children) == 1
850
872
851 expected_origin_link = url(
873 expected_origin_link = url(
852 'changelog_home',
874 'changelog_home',
853 repo_name=pull_request.source_repo.scm_instance().name,
875 repo_name=pull_request.source_repo.scm_instance().name,
854 branch='origin')
876 branch='origin')
855 expected_target_link = url(
877 expected_target_link = url(
856 'changelog_home',
878 'changelog_home',
857 repo_name=pull_request.target_repo.scm_instance().name,
879 repo_name=pull_request.target_repo.scm_instance().name,
858 branch='target')
880 branch='target')
859 assert origin_children[0].attrib['href'] == expected_origin_link
881 assert origin_children[0].attrib['href'] == expected_origin_link
860 assert origin_children[0].text == 'branch: origin'
882 assert origin_children[0].text == 'branch: origin'
861 assert target_children[0].attrib['href'] == expected_target_link
883 assert target_children[0].attrib['href'] == expected_target_link
862 assert target_children[0].text == 'branch: target'
884 assert target_children[0].text == 'branch: target'
863
885
864 def test_bookmark_is_not_a_link(self, pr_util):
886 def test_bookmark_is_not_a_link(self, pr_util):
865 pull_request = pr_util.create_pull_request()
887 pull_request = pr_util.create_pull_request()
866 pull_request.source_ref = 'bookmark:origin:1234567890abcdef'
888 pull_request.source_ref = 'bookmark:origin:1234567890abcdef'
867 pull_request.target_ref = 'bookmark:target:abcdef1234567890'
889 pull_request.target_ref = 'bookmark:target:abcdef1234567890'
868 Session().add(pull_request)
890 Session().add(pull_request)
869 Session().commit()
891 Session().commit()
870
892
871 response = self.app.get(url(
893 response = self.app.get(url(
872 controller='pullrequests', action='show',
894 controller='pullrequests', action='show',
873 repo_name=pull_request.target_repo.scm_instance().name,
895 repo_name=pull_request.target_repo.scm_instance().name,
874 pull_request_id=str(pull_request.pull_request_id)))
896 pull_request_id=str(pull_request.pull_request_id)))
875 assert response.status_int == 200
897 assert response.status_int == 200
876 assert_response = AssertResponse(response)
898 assert_response = AssertResponse(response)
877
899
878 origin = assert_response.get_element('.pr-origininfo .tag')
900 origin = assert_response.get_element('.pr-origininfo .tag')
879 assert origin.text.strip() == 'bookmark: origin'
901 assert origin.text.strip() == 'bookmark: origin'
880 assert origin.getchildren() == []
902 assert origin.getchildren() == []
881
903
882 target = assert_response.get_element('.pr-targetinfo .tag')
904 target = assert_response.get_element('.pr-targetinfo .tag')
883 assert target.text.strip() == 'bookmark: target'
905 assert target.text.strip() == 'bookmark: target'
884 assert target.getchildren() == []
906 assert target.getchildren() == []
885
907
886 def test_tag_is_not_a_link(self, pr_util):
908 def test_tag_is_not_a_link(self, pr_util):
887 pull_request = pr_util.create_pull_request()
909 pull_request = pr_util.create_pull_request()
888 pull_request.source_ref = 'tag:origin:1234567890abcdef'
910 pull_request.source_ref = 'tag:origin:1234567890abcdef'
889 pull_request.target_ref = 'tag:target:abcdef1234567890'
911 pull_request.target_ref = 'tag:target:abcdef1234567890'
890 Session().add(pull_request)
912 Session().add(pull_request)
891 Session().commit()
913 Session().commit()
892
914
893 response = self.app.get(url(
915 response = self.app.get(url(
894 controller='pullrequests', action='show',
916 controller='pullrequests', action='show',
895 repo_name=pull_request.target_repo.scm_instance().name,
917 repo_name=pull_request.target_repo.scm_instance().name,
896 pull_request_id=str(pull_request.pull_request_id)))
918 pull_request_id=str(pull_request.pull_request_id)))
897 assert response.status_int == 200
919 assert response.status_int == 200
898 assert_response = AssertResponse(response)
920 assert_response = AssertResponse(response)
899
921
900 origin = assert_response.get_element('.pr-origininfo .tag')
922 origin = assert_response.get_element('.pr-origininfo .tag')
901 assert origin.text.strip() == 'tag: origin'
923 assert origin.text.strip() == 'tag: origin'
902 assert origin.getchildren() == []
924 assert origin.getchildren() == []
903
925
904 target = assert_response.get_element('.pr-targetinfo .tag')
926 target = assert_response.get_element('.pr-targetinfo .tag')
905 assert target.text.strip() == 'tag: target'
927 assert target.text.strip() == 'tag: target'
906 assert target.getchildren() == []
928 assert target.getchildren() == []
907
929
908 def test_description_is_escaped_on_index_page(self, backend, pr_util):
930 def test_description_is_escaped_on_index_page(self, backend, pr_util):
909 xss_description = "<script>alert('Hi!')</script>"
931 xss_description = "<script>alert('Hi!')</script>"
910 pull_request = pr_util.create_pull_request(description=xss_description)
932 pull_request = pr_util.create_pull_request(description=xss_description)
911 response = self.app.get(url(
933 response = self.app.get(url(
912 controller='pullrequests', action='show_all',
934 controller='pullrequests', action='show_all',
913 repo_name=pull_request.target_repo.repo_name))
935 repo_name=pull_request.target_repo.repo_name))
914 response.mustcontain(
936 response.mustcontain(
915 "&lt;script&gt;alert(&#39;Hi!&#39;)&lt;/script&gt;")
937 "&lt;script&gt;alert(&#39;Hi!&#39;)&lt;/script&gt;")
916
938
917 @pytest.mark.parametrize('mergeable', [True, False])
939 @pytest.mark.parametrize('mergeable', [True, False])
918 def test_shadow_repository_link(
940 def test_shadow_repository_link(
919 self, mergeable, pr_util, http_host_stub):
941 self, mergeable, pr_util, http_host_stub):
920 """
942 """
921 Check that the pull request summary page displays a link to the shadow
943 Check that the pull request summary page displays a link to the shadow
922 repository if the pull request is mergeable. If it is not mergeable
944 repository if the pull request is mergeable. If it is not mergeable
923 the link should not be displayed.
945 the link should not be displayed.
924 """
946 """
925 pull_request = pr_util.create_pull_request(
947 pull_request = pr_util.create_pull_request(
926 mergeable=mergeable, enable_notifications=False)
948 mergeable=mergeable, enable_notifications=False)
927 target_repo = pull_request.target_repo.scm_instance()
949 target_repo = pull_request.target_repo.scm_instance()
928 pr_id = pull_request.pull_request_id
950 pr_id = pull_request.pull_request_id
929 shadow_url = '{host}/{repo}/pull-request/{pr_id}/repository'.format(
951 shadow_url = '{host}/{repo}/pull-request/{pr_id}/repository'.format(
930 host=http_host_stub, repo=target_repo.name, pr_id=pr_id)
952 host=http_host_stub, repo=target_repo.name, pr_id=pr_id)
931
953
932 response = self.app.get(url(
954 response = self.app.get(url(
933 controller='pullrequests', action='show',
955 controller='pullrequests', action='show',
934 repo_name=target_repo.name,
956 repo_name=target_repo.name,
935 pull_request_id=str(pr_id)))
957 pull_request_id=str(pr_id)))
936
958
937 assertr = AssertResponse(response)
959 assertr = AssertResponse(response)
938 if mergeable:
960 if mergeable:
939 assertr.element_value_contains(
961 assertr.element_value_contains(
940 'div.pr-mergeinfo input', shadow_url)
962 'div.pr-mergeinfo input', shadow_url)
941 assertr.element_value_contains(
963 assertr.element_value_contains(
942 'div.pr-mergeinfo input', 'pr-merge')
964 'div.pr-mergeinfo input', 'pr-merge')
943 else:
965 else:
944 assertr.no_element_exists('div.pr-mergeinfo')
966 assertr.no_element_exists('div.pr-mergeinfo')
945
967
946
968
947 def assert_pull_request_status(pull_request, expected_status):
969 def assert_pull_request_status(pull_request, expected_status):
948 status = ChangesetStatusModel().calculated_review_status(
970 status = ChangesetStatusModel().calculated_review_status(
949 pull_request=pull_request)
971 pull_request=pull_request)
950 assert status == expected_status
972 assert status == expected_status
951
973
952
974
953 @pytest.mark.parametrize('action', ['show_all', 'index', 'create'])
975 @pytest.mark.parametrize('action', ['show_all', 'index', 'create'])
954 @pytest.mark.usefixtures("autologin_user")
976 @pytest.mark.usefixtures("autologin_user")
955 def test_redirects_to_repo_summary_for_svn_repositories(
977 def test_redirects_to_repo_summary_for_svn_repositories(
956 backend_svn, app, action):
978 backend_svn, app, action):
957 denied_actions = ['show_all', 'index', 'create']
979 denied_actions = ['show_all', 'index', 'create']
958 for action in denied_actions:
980 for action in denied_actions:
959 response = app.get(url(
981 response = app.get(url(
960 controller='pullrequests', action=action,
982 controller='pullrequests', action=action,
961 repo_name=backend_svn.repo_name))
983 repo_name=backend_svn.repo_name))
962 assert response.status_int == 302
984 assert response.status_int == 302
963
985
964 # Not allowed, redirect to the summary
986 # Not allowed, redirect to the summary
965 redirected = response.follow()
987 redirected = response.follow()
966 summary_url = url('summary_home', repo_name=backend_svn.repo_name)
988 summary_url = url('summary_home', repo_name=backend_svn.repo_name)
967
989
968 # URL adds leading slash and path doesn't have it
990 # URL adds leading slash and path doesn't have it
969 assert redirected.req.path == summary_url
991 assert redirected.req.path == summary_url
970
992
971
993
972 def test_delete_comment_returns_404_if_comment_does_not_exist(pylonsapp):
994 def test_delete_comment_returns_404_if_comment_does_not_exist(pylonsapp):
973 # TODO: johbo: Global import not possible because models.forms blows up
995 # TODO: johbo: Global import not possible because models.forms blows up
974 from rhodecode.controllers.pullrequests import PullrequestsController
996 from rhodecode.controllers.pullrequests import PullrequestsController
975 controller = PullrequestsController()
997 controller = PullrequestsController()
976 patcher = mock.patch(
998 patcher = mock.patch(
977 'rhodecode.model.db.BaseModel.get', return_value=None)
999 'rhodecode.model.db.BaseModel.get', return_value=None)
978 with pytest.raises(HTTPNotFound), patcher:
1000 with pytest.raises(HTTPNotFound), patcher:
979 controller._delete_comment(1)
1001 controller._delete_comment(1)
General Comments 0
You need to be logged in to leave comments. Login now