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