##// END OF EJS Templates
tests: fixed some broken tests
milka -
r4563:98909132 default
parent child Browse files
Show More
@@ -1,1661 +1,1658 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2020 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 import mock
21 21 import pytest
22 22
23 23 import rhodecode
24 24 from rhodecode.lib.vcs.backends.base import MergeResponse, MergeFailureReason
25 25 from rhodecode.lib.vcs.nodes import FileNode
26 26 from rhodecode.lib import helpers as h
27 27 from rhodecode.model.changeset_status import ChangesetStatusModel
28 28 from rhodecode.model.db import (
29 29 PullRequest, ChangesetStatus, UserLog, Notification, ChangesetComment, Repository)
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.model.comment import CommentsModel
34 34 from rhodecode.tests import (
35 35 assert_session_flash, TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN)
36 36
37 37
38 38 def route_path(name, params=None, **kwargs):
39 39 import urllib
40 40
41 41 base_url = {
42 42 'repo_changelog': '/{repo_name}/changelog',
43 43 'repo_changelog_file': '/{repo_name}/changelog/{commit_id}/{f_path}',
44 44 'repo_commits': '/{repo_name}/commits',
45 45 'repo_commits_file': '/{repo_name}/commits/{commit_id}/{f_path}',
46 46 'pullrequest_show': '/{repo_name}/pull-request/{pull_request_id}',
47 47 'pullrequest_show_all': '/{repo_name}/pull-request',
48 48 'pullrequest_show_all_data': '/{repo_name}/pull-request-data',
49 49 'pullrequest_repo_refs': '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
50 50 'pullrequest_repo_targets': '/{repo_name}/pull-request/repo-destinations',
51 51 'pullrequest_new': '/{repo_name}/pull-request/new',
52 52 'pullrequest_create': '/{repo_name}/pull-request/create',
53 53 'pullrequest_update': '/{repo_name}/pull-request/{pull_request_id}/update',
54 54 'pullrequest_merge': '/{repo_name}/pull-request/{pull_request_id}/merge',
55 55 'pullrequest_delete': '/{repo_name}/pull-request/{pull_request_id}/delete',
56 56 'pullrequest_comment_create': '/{repo_name}/pull-request/{pull_request_id}/comment',
57 57 'pullrequest_comment_delete': '/{repo_name}/pull-request/{pull_request_id}/comment/{comment_id}/delete',
58 58 'pullrequest_comment_edit': '/{repo_name}/pull-request/{pull_request_id}/comment/{comment_id}/edit',
59 59 }[name].format(**kwargs)
60 60
61 61 if params:
62 62 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
63 63 return base_url
64 64
65 65
66 66 @pytest.mark.usefixtures('app', 'autologin_user')
67 67 @pytest.mark.backends("git", "hg")
68 68 class TestPullrequestsView(object):
69 69
70 70 def test_index(self, backend):
71 71 self.app.get(route_path(
72 72 'pullrequest_new',
73 73 repo_name=backend.repo_name))
74 74
75 75 def test_option_menu_create_pull_request_exists(self, backend):
76 76 repo_name = backend.repo_name
77 77 response = self.app.get(h.route_path('repo_summary', repo_name=repo_name))
78 78
79 79 create_pr_link = '<a href="%s">Create Pull Request</a>' % route_path(
80 80 'pullrequest_new', repo_name=repo_name)
81 81 response.mustcontain(create_pr_link)
82 82
83 83 def test_create_pr_form_with_raw_commit_id(self, backend):
84 84 repo = backend.repo
85 85
86 86 self.app.get(
87 87 route_path('pullrequest_new', repo_name=repo.repo_name,
88 88 commit=repo.get_commit().raw_id),
89 89 status=200)
90 90
91 91 @pytest.mark.parametrize('pr_merge_enabled', [True, False])
92 92 @pytest.mark.parametrize('range_diff', ["0", "1"])
93 93 def test_show(self, pr_util, pr_merge_enabled, range_diff):
94 94 pull_request = pr_util.create_pull_request(
95 95 mergeable=pr_merge_enabled, enable_notifications=False)
96 96
97 97 response = self.app.get(route_path(
98 98 'pullrequest_show',
99 99 repo_name=pull_request.target_repo.scm_instance().name,
100 100 pull_request_id=pull_request.pull_request_id,
101 101 params={'range-diff': range_diff}))
102 102
103 103 for commit_id in pull_request.revisions:
104 104 response.mustcontain(commit_id)
105 105
106 106 response.mustcontain(pull_request.target_ref_parts.type)
107 107 response.mustcontain(pull_request.target_ref_parts.name)
108 108
109 109 response.mustcontain('class="pull-request-merge"')
110 110
111 111 if pr_merge_enabled:
112 112 response.mustcontain('Pull request reviewer approval is pending')
113 113 else:
114 114 response.mustcontain('Server-side pull request merging is disabled.')
115 115
116 116 if range_diff == "1":
117 117 response.mustcontain('Turn off: Show the diff as commit range')
118 118
119 119 def test_show_versions_of_pr(self, backend, csrf_token):
120 120 commits = [
121 121 {'message': 'initial-commit',
122 122 'added': [FileNode('test-file.txt', 'LINE1\n')]},
123 123
124 124 {'message': 'commit-1',
125 125 'changed': [FileNode('test-file.txt', 'LINE1\nLINE2\n')]},
126 126 # Above is the initial version of PR that changes a single line
127 127
128 128 # from now on we'll add 3x commit adding a nother line on each step
129 129 {'message': 'commit-2',
130 130 'changed': [FileNode('test-file.txt', 'LINE1\nLINE2\nLINE3\n')]},
131 131
132 132 {'message': 'commit-3',
133 133 'changed': [FileNode('test-file.txt', 'LINE1\nLINE2\nLINE3\nLINE4\n')]},
134 134
135 135 {'message': 'commit-4',
136 136 'changed': [FileNode('test-file.txt', 'LINE1\nLINE2\nLINE3\nLINE4\nLINE5\n')]},
137 137 ]
138 138
139 139 commit_ids = backend.create_master_repo(commits)
140 140 target = backend.create_repo(heads=['initial-commit'])
141 141 source = backend.create_repo(heads=['commit-1'])
142 142 source_repo_name = source.repo_name
143 143 target_repo_name = target.repo_name
144 144
145 145 target_ref = 'branch:{branch}:{commit_id}'.format(
146 146 branch=backend.default_branch_name, commit_id=commit_ids['initial-commit'])
147 147 source_ref = 'branch:{branch}:{commit_id}'.format(
148 148 branch=backend.default_branch_name, commit_id=commit_ids['commit-1'])
149 149
150 150 response = self.app.post(
151 151 route_path('pullrequest_create', repo_name=source.repo_name),
152 152 [
153 153 ('source_repo', source_repo_name),
154 154 ('source_ref', source_ref),
155 155 ('target_repo', target_repo_name),
156 156 ('target_ref', target_ref),
157 157 ('common_ancestor', commit_ids['initial-commit']),
158 158 ('pullrequest_title', 'Title'),
159 159 ('pullrequest_desc', 'Description'),
160 160 ('description_renderer', 'markdown'),
161 161 ('__start__', 'review_members:sequence'),
162 162 ('__start__', 'reviewer:mapping'),
163 163 ('user_id', '1'),
164 164 ('__start__', 'reasons:sequence'),
165 165 ('reason', 'Some reason'),
166 166 ('__end__', 'reasons:sequence'),
167 167 ('__start__', 'rules:sequence'),
168 168 ('__end__', 'rules:sequence'),
169 169 ('mandatory', 'False'),
170 170 ('__end__', 'reviewer:mapping'),
171 171 ('__end__', 'review_members:sequence'),
172 172 ('__start__', 'revisions:sequence'),
173 173 ('revisions', commit_ids['commit-1']),
174 174 ('__end__', 'revisions:sequence'),
175 175 ('user', ''),
176 176 ('csrf_token', csrf_token),
177 177 ],
178 178 status=302)
179 179
180 180 location = response.headers['Location']
181 181
182 182 pull_request_id = location.rsplit('/', 1)[1]
183 183 assert pull_request_id != 'new'
184 184 pull_request = PullRequest.get(int(pull_request_id))
185 185
186 186 pull_request_id = pull_request.pull_request_id
187 187
188 188 # Show initial version of PR
189 189 response = self.app.get(
190 190 route_path('pullrequest_show',
191 191 repo_name=target_repo_name,
192 192 pull_request_id=pull_request_id))
193 193
194 194 response.mustcontain('commit-1')
195 195 response.mustcontain(no=['commit-2'])
196 196 response.mustcontain(no=['commit-3'])
197 197 response.mustcontain(no=['commit-4'])
198 198
199 199 response.mustcontain('cb-addition"></span><span>LINE2</span>')
200 200 response.mustcontain(no=['LINE3'])
201 201 response.mustcontain(no=['LINE4'])
202 202 response.mustcontain(no=['LINE5'])
203 203
204 204 # update PR #1
205 205 source_repo = Repository.get_by_repo_name(source_repo_name)
206 206 backend.pull_heads(source_repo, heads=['commit-2'])
207 207 response = self.app.post(
208 208 route_path('pullrequest_update',
209 209 repo_name=target_repo_name, pull_request_id=pull_request_id),
210 210 params={'update_commits': 'true', 'csrf_token': csrf_token})
211 211
212 212 # update PR #2
213 213 source_repo = Repository.get_by_repo_name(source_repo_name)
214 214 backend.pull_heads(source_repo, heads=['commit-3'])
215 215 response = self.app.post(
216 216 route_path('pullrequest_update',
217 217 repo_name=target_repo_name, pull_request_id=pull_request_id),
218 218 params={'update_commits': 'true', 'csrf_token': csrf_token})
219 219
220 220 # update PR #3
221 221 source_repo = Repository.get_by_repo_name(source_repo_name)
222 222 backend.pull_heads(source_repo, heads=['commit-4'])
223 223 response = self.app.post(
224 224 route_path('pullrequest_update',
225 225 repo_name=target_repo_name, pull_request_id=pull_request_id),
226 226 params={'update_commits': 'true', 'csrf_token': csrf_token})
227 227
228 228 # Show final version !
229 229 response = self.app.get(
230 230 route_path('pullrequest_show',
231 231 repo_name=target_repo_name,
232 232 pull_request_id=pull_request_id))
233 233
234 234 # 3 updates, and the latest == 4
235 235 response.mustcontain('4 versions available for this pull request')
236 236 response.mustcontain(no=['rhodecode diff rendering error'])
237 237
238 238 # initial show must have 3 commits, and 3 adds
239 239 response.mustcontain('commit-1')
240 240 response.mustcontain('commit-2')
241 241 response.mustcontain('commit-3')
242 242 response.mustcontain('commit-4')
243 243
244 244 response.mustcontain('cb-addition"></span><span>LINE2</span>')
245 245 response.mustcontain('cb-addition"></span><span>LINE3</span>')
246 246 response.mustcontain('cb-addition"></span><span>LINE4</span>')
247 247 response.mustcontain('cb-addition"></span><span>LINE5</span>')
248 248
249 249 # fetch versions
250 250 pr = PullRequest.get(pull_request_id)
251 251 versions = [x.pull_request_version_id for x in pr.versions.all()]
252 252 assert len(versions) == 3
253 253
254 254 # show v1,v2,v3,v4
255 255 def cb_line(text):
256 256 return 'cb-addition"></span><span>{}</span>'.format(text)
257 257
258 258 def cb_context(text):
259 259 return '<span class="cb-code"><span class="cb-action cb-context">' \
260 260 '</span><span>{}</span></span>'.format(text)
261 261
262 262 commit_tests = {
263 263 # in response, not in response
264 264 1: (['commit-1'], ['commit-2', 'commit-3', 'commit-4']),
265 265 2: (['commit-1', 'commit-2'], ['commit-3', 'commit-4']),
266 266 3: (['commit-1', 'commit-2', 'commit-3'], ['commit-4']),
267 267 4: (['commit-1', 'commit-2', 'commit-3', 'commit-4'], []),
268 268 }
269 269 diff_tests = {
270 270 1: (['LINE2'], ['LINE3', 'LINE4', 'LINE5']),
271 271 2: (['LINE2', 'LINE3'], ['LINE4', 'LINE5']),
272 272 3: (['LINE2', 'LINE3', 'LINE4'], ['LINE5']),
273 273 4: (['LINE2', 'LINE3', 'LINE4', 'LINE5'], []),
274 274 }
275 275 for idx, ver in enumerate(versions, 1):
276 276
277 277 response = self.app.get(
278 278 route_path('pullrequest_show',
279 279 repo_name=target_repo_name,
280 280 pull_request_id=pull_request_id,
281 281 params={'version': ver}))
282 282
283 283 response.mustcontain(no=['rhodecode diff rendering error'])
284 284 response.mustcontain('Showing changes at v{}'.format(idx))
285 285
286 286 yes, no = commit_tests[idx]
287 287 for y in yes:
288 288 response.mustcontain(y)
289 289 for n in no:
290 290 response.mustcontain(no=n)
291 291
292 292 yes, no = diff_tests[idx]
293 293 for y in yes:
294 294 response.mustcontain(cb_line(y))
295 295 for n in no:
296 296 response.mustcontain(no=n)
297 297
298 298 # show diff between versions
299 299 diff_compare_tests = {
300 300 1: (['LINE3'], ['LINE1', 'LINE2']),
301 301 2: (['LINE3', 'LINE4'], ['LINE1', 'LINE2']),
302 302 3: (['LINE3', 'LINE4', 'LINE5'], ['LINE1', 'LINE2']),
303 303 }
304 304 for idx, ver in enumerate(versions, 1):
305 305 adds, context = diff_compare_tests[idx]
306 306
307 307 to_ver = ver+1
308 308 if idx == 3:
309 309 to_ver = 'latest'
310 310
311 311 response = self.app.get(
312 312 route_path('pullrequest_show',
313 313 repo_name=target_repo_name,
314 314 pull_request_id=pull_request_id,
315 315 params={'from_version': versions[0], 'version': to_ver}))
316 316
317 317 response.mustcontain(no=['rhodecode diff rendering error'])
318 318
319 319 for a in adds:
320 320 response.mustcontain(cb_line(a))
321 321 for c in context:
322 322 response.mustcontain(cb_context(c))
323 323
324 324 # test version v2 -> v3
325 325 response = self.app.get(
326 326 route_path('pullrequest_show',
327 327 repo_name=target_repo_name,
328 328 pull_request_id=pull_request_id,
329 329 params={'from_version': versions[1], 'version': versions[2]}))
330 330
331 331 response.mustcontain(cb_context('LINE1'))
332 332 response.mustcontain(cb_context('LINE2'))
333 333 response.mustcontain(cb_context('LINE3'))
334 334 response.mustcontain(cb_line('LINE4'))
335 335
336 336 def test_close_status_visibility(self, pr_util, user_util, csrf_token):
337 337 # Logout
338 338 response = self.app.post(
339 339 h.route_path('logout'),
340 340 params={'csrf_token': csrf_token})
341 341 # Login as regular user
342 342 response = self.app.post(h.route_path('login'),
343 343 {'username': TEST_USER_REGULAR_LOGIN,
344 344 'password': 'test12'})
345 345
346 346 pull_request = pr_util.create_pull_request(
347 347 author=TEST_USER_REGULAR_LOGIN)
348 348
349 349 response = self.app.get(route_path(
350 350 'pullrequest_show',
351 351 repo_name=pull_request.target_repo.scm_instance().name,
352 352 pull_request_id=pull_request.pull_request_id))
353 353
354 354 response.mustcontain('Server-side pull request merging is disabled.')
355 355
356 356 assert_response = response.assert_response()
357 357 # for regular user without a merge permissions, we don't see it
358 358 assert_response.no_element_exists('#close-pull-request-action')
359 359
360 360 user_util.grant_user_permission_to_repo(
361 361 pull_request.target_repo,
362 362 UserModel().get_by_username(TEST_USER_REGULAR_LOGIN),
363 363 'repository.write')
364 364 response = self.app.get(route_path(
365 365 'pullrequest_show',
366 366 repo_name=pull_request.target_repo.scm_instance().name,
367 367 pull_request_id=pull_request.pull_request_id))
368 368
369 369 response.mustcontain('Server-side pull request merging is disabled.')
370 370
371 371 assert_response = response.assert_response()
372 372 # now regular user has a merge permissions, we have CLOSE button
373 373 assert_response.one_element_exists('#close-pull-request-action')
374 374
375 375 def test_show_invalid_commit_id(self, pr_util):
376 376 # Simulating invalid revisions which will cause a lookup error
377 377 pull_request = pr_util.create_pull_request()
378 378 pull_request.revisions = ['invalid']
379 379 Session().add(pull_request)
380 380 Session().commit()
381 381
382 382 response = self.app.get(route_path(
383 383 'pullrequest_show',
384 384 repo_name=pull_request.target_repo.scm_instance().name,
385 385 pull_request_id=pull_request.pull_request_id))
386 386
387 387 for commit_id in pull_request.revisions:
388 388 response.mustcontain(commit_id)
389 389
390 390 def test_show_invalid_source_reference(self, pr_util):
391 391 pull_request = pr_util.create_pull_request()
392 392 pull_request.source_ref = 'branch:b:invalid'
393 393 Session().add(pull_request)
394 394 Session().commit()
395 395
396 396 self.app.get(route_path(
397 397 'pullrequest_show',
398 398 repo_name=pull_request.target_repo.scm_instance().name,
399 399 pull_request_id=pull_request.pull_request_id))
400 400
401 401 def test_edit_title_description(self, pr_util, csrf_token):
402 402 pull_request = pr_util.create_pull_request()
403 403 pull_request_id = pull_request.pull_request_id
404 404
405 405 response = self.app.post(
406 406 route_path('pullrequest_update',
407 407 repo_name=pull_request.target_repo.repo_name,
408 408 pull_request_id=pull_request_id),
409 409 params={
410 410 'edit_pull_request': 'true',
411 411 'title': 'New title',
412 412 'description': 'New description',
413 413 'csrf_token': csrf_token})
414 414
415 415 assert_session_flash(
416 416 response, u'Pull request title & description updated.',
417 417 category='success')
418 418
419 419 pull_request = PullRequest.get(pull_request_id)
420 420 assert pull_request.title == 'New title'
421 421 assert pull_request.description == 'New description'
422 422
423 423 def test_edit_title_description_closed(self, pr_util, csrf_token):
424 424 pull_request = pr_util.create_pull_request()
425 425 pull_request_id = pull_request.pull_request_id
426 426 repo_name = pull_request.target_repo.repo_name
427 427 pr_util.close()
428 428
429 429 response = self.app.post(
430 430 route_path('pullrequest_update',
431 431 repo_name=repo_name, pull_request_id=pull_request_id),
432 432 params={
433 433 'edit_pull_request': 'true',
434 434 'title': 'New title',
435 435 'description': 'New description',
436 436 'csrf_token': csrf_token}, status=200)
437 437 assert_session_flash(
438 438 response, u'Cannot update closed pull requests.',
439 439 category='error')
440 440
441 441 def test_update_invalid_source_reference(self, pr_util, csrf_token):
442 442 from rhodecode.lib.vcs.backends.base import UpdateFailureReason
443 443
444 444 pull_request = pr_util.create_pull_request()
445 445 pull_request.source_ref = 'branch:invalid-branch:invalid-commit-id'
446 446 Session().add(pull_request)
447 447 Session().commit()
448 448
449 449 pull_request_id = pull_request.pull_request_id
450 450
451 451 response = self.app.post(
452 452 route_path('pullrequest_update',
453 453 repo_name=pull_request.target_repo.repo_name,
454 454 pull_request_id=pull_request_id),
455 455 params={'update_commits': 'true', 'csrf_token': csrf_token})
456 456
457 457 expected_msg = str(PullRequestModel.UPDATE_STATUS_MESSAGES[
458 458 UpdateFailureReason.MISSING_SOURCE_REF])
459 459 assert_session_flash(response, expected_msg, category='error')
460 460
461 461 def test_missing_target_reference(self, pr_util, csrf_token):
462 462 from rhodecode.lib.vcs.backends.base import MergeFailureReason
463 463 pull_request = pr_util.create_pull_request(
464 464 approved=True, mergeable=True)
465 465 unicode_reference = u'branch:invalid-branch:invalid-commit-id'
466 466 pull_request.target_ref = unicode_reference
467 467 Session().add(pull_request)
468 468 Session().commit()
469 469
470 470 pull_request_id = pull_request.pull_request_id
471 471 pull_request_url = route_path(
472 472 'pullrequest_show',
473 473 repo_name=pull_request.target_repo.repo_name,
474 474 pull_request_id=pull_request_id)
475 475
476 476 response = self.app.get(pull_request_url)
477 477 target_ref_id = 'invalid-branch'
478 478 merge_resp = MergeResponse(
479 479 True, True, '', MergeFailureReason.MISSING_TARGET_REF,
480 480 metadata={'target_ref': PullRequest.unicode_to_reference(unicode_reference)})
481 481 response.assert_response().element_contains(
482 482 'div[data-role="merge-message"]', merge_resp.merge_status_message)
483 483
484 484 def test_comment_and_close_pull_request_custom_message_approved(
485 485 self, pr_util, csrf_token, xhr_header):
486 486
487 487 pull_request = pr_util.create_pull_request(approved=True)
488 488 pull_request_id = pull_request.pull_request_id
489 489 author = pull_request.user_id
490 490 repo = pull_request.target_repo.repo_id
491 491
492 492 self.app.post(
493 493 route_path('pullrequest_comment_create',
494 494 repo_name=pull_request.target_repo.scm_instance().name,
495 495 pull_request_id=pull_request_id),
496 496 params={
497 497 'close_pull_request': '1',
498 498 'text': 'Closing a PR',
499 499 'csrf_token': csrf_token},
500 500 extra_environ=xhr_header,)
501 501
502 502 journal = UserLog.query()\
503 503 .filter(UserLog.user_id == author)\
504 504 .filter(UserLog.repository_id == repo) \
505 505 .order_by(UserLog.user_log_id.asc()) \
506 506 .all()
507 507 assert journal[-1].action == 'repo.pull_request.close'
508 508
509 509 pull_request = PullRequest.get(pull_request_id)
510 510 assert pull_request.is_closed()
511 511
512 512 status = ChangesetStatusModel().get_status(
513 513 pull_request.source_repo, pull_request=pull_request)
514 514 assert status == ChangesetStatus.STATUS_APPROVED
515 515 comments = ChangesetComment().query() \
516 516 .filter(ChangesetComment.pull_request == pull_request) \
517 517 .order_by(ChangesetComment.comment_id.asc())\
518 518 .all()
519 519 assert comments[-1].text == 'Closing a PR'
520 520
521 521 def test_comment_force_close_pull_request_rejected(
522 522 self, pr_util, csrf_token, xhr_header):
523 523 pull_request = pr_util.create_pull_request()
524 524 pull_request_id = pull_request.pull_request_id
525 525 PullRequestModel().update_reviewers(
526 526 pull_request_id, [
527 527 (1, ['reason'], False, 'reviewer', []),
528 528 (2, ['reason2'], False, 'reviewer', [])],
529 529 pull_request.author)
530 530 author = pull_request.user_id
531 531 repo = pull_request.target_repo.repo_id
532 532
533 533 self.app.post(
534 534 route_path('pullrequest_comment_create',
535 535 repo_name=pull_request.target_repo.scm_instance().name,
536 536 pull_request_id=pull_request_id),
537 537 params={
538 538 'close_pull_request': '1',
539 539 'csrf_token': csrf_token},
540 540 extra_environ=xhr_header)
541 541
542 542 pull_request = PullRequest.get(pull_request_id)
543 543
544 544 journal = UserLog.query()\
545 545 .filter(UserLog.user_id == author, UserLog.repository_id == repo) \
546 546 .order_by(UserLog.user_log_id.asc()) \
547 547 .all()
548 548 assert journal[-1].action == 'repo.pull_request.close'
549 549
550 550 # check only the latest status, not the review status
551 551 status = ChangesetStatusModel().get_status(
552 552 pull_request.source_repo, pull_request=pull_request)
553 553 assert status == ChangesetStatus.STATUS_REJECTED
554 554
555 555 def test_comment_and_close_pull_request(
556 556 self, pr_util, csrf_token, xhr_header):
557 557 pull_request = pr_util.create_pull_request()
558 558 pull_request_id = pull_request.pull_request_id
559 559
560 560 response = self.app.post(
561 561 route_path('pullrequest_comment_create',
562 562 repo_name=pull_request.target_repo.scm_instance().name,
563 563 pull_request_id=pull_request.pull_request_id),
564 564 params={
565 565 'close_pull_request': 'true',
566 566 'csrf_token': csrf_token},
567 567 extra_environ=xhr_header)
568 568
569 569 assert response.json
570 570
571 571 pull_request = PullRequest.get(pull_request_id)
572 572 assert pull_request.is_closed()
573 573
574 574 # check only the latest status, not the review status
575 575 status = ChangesetStatusModel().get_status(
576 576 pull_request.source_repo, pull_request=pull_request)
577 577 assert status == ChangesetStatus.STATUS_REJECTED
578 578
579 579 def test_comment_and_close_pull_request_try_edit_comment(
580 580 self, pr_util, csrf_token, xhr_header
581 581 ):
582 582 pull_request = pr_util.create_pull_request()
583 583 pull_request_id = pull_request.pull_request_id
584 584 target_scm = pull_request.target_repo.scm_instance()
585 585 target_scm_name = target_scm.name
586 586
587 587 response = self.app.post(
588 588 route_path(
589 589 'pullrequest_comment_create',
590 590 repo_name=target_scm_name,
591 591 pull_request_id=pull_request_id,
592 592 ),
593 593 params={
594 594 'close_pull_request': 'true',
595 595 'csrf_token': csrf_token,
596 596 },
597 597 extra_environ=xhr_header)
598 598
599 599 assert response.json
600 600
601 601 pull_request = PullRequest.get(pull_request_id)
602 602 target_scm = pull_request.target_repo.scm_instance()
603 603 target_scm_name = target_scm.name
604 604 assert pull_request.is_closed()
605 605
606 606 # check only the latest status, not the review status
607 607 status = ChangesetStatusModel().get_status(
608 608 pull_request.source_repo, pull_request=pull_request)
609 609 assert status == ChangesetStatus.STATUS_REJECTED
610 610
611 comment_id = response.json.get('comment_id', None)
612 test_text = 'test'
613 response = self.app.post(
614 route_path(
615 'pullrequest_comment_edit',
616 repo_name=target_scm_name,
617 pull_request_id=pull_request_id,
618 comment_id=comment_id,
619 ),
620 extra_environ=xhr_header,
621 params={
622 'csrf_token': csrf_token,
623 'text': test_text,
624 },
625 status=403,
626 )
627 assert response.status_int == 403
611 for comment_id in response.json.keys():
612 test_text = 'test'
613 response = self.app.post(
614 route_path(
615 'pullrequest_comment_edit',
616 repo_name=target_scm_name,
617 pull_request_id=pull_request_id,
618 comment_id=comment_id,
619 ),
620 extra_environ=xhr_header,
621 params={
622 'csrf_token': csrf_token,
623 'text': test_text,
624 },
625 status=403,
626 )
627 assert response.status_int == 403
628 628
629 629 def test_comment_and_comment_edit(self, pr_util, csrf_token, xhr_header):
630 630 pull_request = pr_util.create_pull_request()
631 631 target_scm = pull_request.target_repo.scm_instance()
632 632 target_scm_name = target_scm.name
633 633
634 634 response = self.app.post(
635 635 route_path(
636 636 'pullrequest_comment_create',
637 637 repo_name=target_scm_name,
638 638 pull_request_id=pull_request.pull_request_id),
639 639 params={
640 640 'csrf_token': csrf_token,
641 641 'text': 'init',
642 642 },
643 643 extra_environ=xhr_header,
644 644 )
645 645 assert response.json
646 646
647 comment_id = response.json.get('comment_id', None)
648 assert comment_id
649 test_text = 'test'
650 self.app.post(
651 route_path(
652 'pullrequest_comment_edit',
653 repo_name=target_scm_name,
654 pull_request_id=pull_request.pull_request_id,
655 comment_id=comment_id,
656 ),
657 extra_environ=xhr_header,
658 params={
659 'csrf_token': csrf_token,
660 'text': test_text,
661 'version': '0',
662 },
647 for comment_id in response.json.keys():
648 assert comment_id
649 test_text = 'test'
650 self.app.post(
651 route_path(
652 'pullrequest_comment_edit',
653 repo_name=target_scm_name,
654 pull_request_id=pull_request.pull_request_id,
655 comment_id=comment_id,
656 ),
657 extra_environ=xhr_header,
658 params={
659 'csrf_token': csrf_token,
660 'text': test_text,
661 'version': '0',
662 },
663 663
664 )
665 text_form_db = ChangesetComment.query().filter(
666 ChangesetComment.comment_id == comment_id).first().text
667 assert test_text == text_form_db
664 )
665 text_form_db = ChangesetComment.query().filter(
666 ChangesetComment.comment_id == comment_id).first().text
667 assert test_text == text_form_db
668 668
669 669 def test_comment_and_comment_edit(self, pr_util, csrf_token, xhr_header):
670 670 pull_request = pr_util.create_pull_request()
671 671 target_scm = pull_request.target_repo.scm_instance()
672 672 target_scm_name = target_scm.name
673 673
674 674 response = self.app.post(
675 675 route_path(
676 676 'pullrequest_comment_create',
677 677 repo_name=target_scm_name,
678 678 pull_request_id=pull_request.pull_request_id),
679 679 params={
680 680 'csrf_token': csrf_token,
681 681 'text': 'init',
682 682 },
683 683 extra_environ=xhr_header,
684 684 )
685 685 assert response.json
686 686
687 comment_id = response.json.get('comment_id', None)
688 assert comment_id
689 test_text = 'init'
690 response = self.app.post(
691 route_path(
692 'pullrequest_comment_edit',
693 repo_name=target_scm_name,
694 pull_request_id=pull_request.pull_request_id,
695 comment_id=comment_id,
696 ),
697 extra_environ=xhr_header,
698 params={
699 'csrf_token': csrf_token,
700 'text': test_text,
701 'version': '0',
702 },
703 status=404,
687 for comment_id in response.json.keys():
688 test_text = 'init'
689 response = self.app.post(
690 route_path(
691 'pullrequest_comment_edit',
692 repo_name=target_scm_name,
693 pull_request_id=pull_request.pull_request_id,
694 comment_id=comment_id,
695 ),
696 extra_environ=xhr_header,
697 params={
698 'csrf_token': csrf_token,
699 'text': test_text,
700 'version': '0',
701 },
702 status=404,
704 703
705 )
706 assert response.status_int == 404
704 )
705 assert response.status_int == 404
707 706
708 707 def test_comment_and_try_edit_already_edited(self, pr_util, csrf_token, xhr_header):
709 708 pull_request = pr_util.create_pull_request()
710 709 target_scm = pull_request.target_repo.scm_instance()
711 710 target_scm_name = target_scm.name
712 711
713 712 response = self.app.post(
714 713 route_path(
715 714 'pullrequest_comment_create',
716 715 repo_name=target_scm_name,
717 716 pull_request_id=pull_request.pull_request_id),
718 717 params={
719 718 'csrf_token': csrf_token,
720 719 'text': 'init',
721 720 },
722 721 extra_environ=xhr_header,
723 722 )
724 723 assert response.json
725 comment_id = response.json.get('comment_id', None)
726 assert comment_id
727
728 test_text = 'test'
729 self.app.post(
730 route_path(
731 'pullrequest_comment_edit',
732 repo_name=target_scm_name,
733 pull_request_id=pull_request.pull_request_id,
734 comment_id=comment_id,
735 ),
736 extra_environ=xhr_header,
737 params={
738 'csrf_token': csrf_token,
739 'text': test_text,
740 'version': '0',
741 },
724 for comment_id in response.json.keys():
725 test_text = 'test'
726 self.app.post(
727 route_path(
728 'pullrequest_comment_edit',
729 repo_name=target_scm_name,
730 pull_request_id=pull_request.pull_request_id,
731 comment_id=comment_id,
732 ),
733 extra_environ=xhr_header,
734 params={
735 'csrf_token': csrf_token,
736 'text': test_text,
737 'version': '0',
738 },
742 739
743 )
744 test_text_v2 = 'test_v2'
745 response = self.app.post(
746 route_path(
747 'pullrequest_comment_edit',
748 repo_name=target_scm_name,
749 pull_request_id=pull_request.pull_request_id,
750 comment_id=comment_id,
751 ),
752 extra_environ=xhr_header,
753 params={
754 'csrf_token': csrf_token,
755 'text': test_text_v2,
756 'version': '0',
757 },
758 status=409,
759 )
760 assert response.status_int == 409
740 )
741 test_text_v2 = 'test_v2'
742 response = self.app.post(
743 route_path(
744 'pullrequest_comment_edit',
745 repo_name=target_scm_name,
746 pull_request_id=pull_request.pull_request_id,
747 comment_id=comment_id,
748 ),
749 extra_environ=xhr_header,
750 params={
751 'csrf_token': csrf_token,
752 'text': test_text_v2,
753 'version': '0',
754 },
755 status=409,
756 )
757 assert response.status_int == 409
761 758
762 text_form_db = ChangesetComment.query().filter(
763 ChangesetComment.comment_id == comment_id).first().text
759 text_form_db = ChangesetComment.query().filter(
760 ChangesetComment.comment_id == comment_id).first().text
764 761
765 assert test_text == text_form_db
766 assert test_text_v2 != text_form_db
762 assert test_text == text_form_db
763 assert test_text_v2 != text_form_db
767 764
768 765 def test_comment_and_comment_edit_permissions_forbidden(
769 766 self, autologin_regular_user, user_regular, user_admin, pr_util,
770 767 csrf_token, xhr_header):
771 768 pull_request = pr_util.create_pull_request(
772 769 author=user_admin.username, enable_notifications=False)
773 770 comment = CommentsModel().create(
774 771 text='test',
775 772 repo=pull_request.target_repo.scm_instance().name,
776 773 user=user_admin,
777 774 pull_request=pull_request,
778 775 )
779 776 response = self.app.post(
780 777 route_path(
781 778 'pullrequest_comment_edit',
782 779 repo_name=pull_request.target_repo.scm_instance().name,
783 780 pull_request_id=pull_request.pull_request_id,
784 781 comment_id=comment.comment_id,
785 782 ),
786 783 extra_environ=xhr_header,
787 784 params={
788 785 'csrf_token': csrf_token,
789 786 'text': 'test_text',
790 787 },
791 788 status=403,
792 789 )
793 790 assert response.status_int == 403
794 791
795 792 def test_create_pull_request(self, backend, csrf_token):
796 793 commits = [
797 794 {'message': 'ancestor'},
798 795 {'message': 'change'},
799 796 {'message': 'change2'},
800 797 ]
801 798 commit_ids = backend.create_master_repo(commits)
802 799 target = backend.create_repo(heads=['ancestor'])
803 800 source = backend.create_repo(heads=['change2'])
804 801
805 802 response = self.app.post(
806 803 route_path('pullrequest_create', repo_name=source.repo_name),
807 804 [
808 805 ('source_repo', source.repo_name),
809 806 ('source_ref', 'branch:default:' + commit_ids['change2']),
810 807 ('target_repo', target.repo_name),
811 808 ('target_ref', 'branch:default:' + commit_ids['ancestor']),
812 809 ('common_ancestor', commit_ids['ancestor']),
813 810 ('pullrequest_title', 'Title'),
814 811 ('pullrequest_desc', 'Description'),
815 812 ('description_renderer', 'markdown'),
816 813 ('__start__', 'review_members:sequence'),
817 814 ('__start__', 'reviewer:mapping'),
818 815 ('user_id', '1'),
819 816 ('__start__', 'reasons:sequence'),
820 817 ('reason', 'Some reason'),
821 818 ('__end__', 'reasons:sequence'),
822 819 ('__start__', 'rules:sequence'),
823 820 ('__end__', 'rules:sequence'),
824 821 ('mandatory', 'False'),
825 822 ('__end__', 'reviewer:mapping'),
826 823 ('__end__', 'review_members:sequence'),
827 824 ('__start__', 'revisions:sequence'),
828 825 ('revisions', commit_ids['change']),
829 826 ('revisions', commit_ids['change2']),
830 827 ('__end__', 'revisions:sequence'),
831 828 ('user', ''),
832 829 ('csrf_token', csrf_token),
833 830 ],
834 831 status=302)
835 832
836 833 location = response.headers['Location']
837 834 pull_request_id = location.rsplit('/', 1)[1]
838 835 assert pull_request_id != 'new'
839 836 pull_request = PullRequest.get(int(pull_request_id))
840 837
841 838 # check that we have now both revisions
842 839 assert pull_request.revisions == [commit_ids['change2'], commit_ids['change']]
843 840 assert pull_request.source_ref == 'branch:default:' + commit_ids['change2']
844 841 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
845 842 assert pull_request.target_ref == expected_target_ref
846 843
847 844 def test_reviewer_notifications(self, backend, csrf_token):
848 845 # We have to use the app.post for this test so it will create the
849 846 # notifications properly with the new PR
850 847 commits = [
851 848 {'message': 'ancestor',
852 849 'added': [FileNode('file_A', content='content_of_ancestor')]},
853 850 {'message': 'change',
854 851 'added': [FileNode('file_a', content='content_of_change')]},
855 852 {'message': 'change-child'},
856 853 {'message': 'ancestor-child', 'parents': ['ancestor'],
857 854 'added': [
858 855 FileNode('file_B', content='content_of_ancestor_child')]},
859 856 {'message': 'ancestor-child-2'},
860 857 ]
861 858 commit_ids = backend.create_master_repo(commits)
862 859 target = backend.create_repo(heads=['ancestor-child'])
863 860 source = backend.create_repo(heads=['change'])
864 861
865 862 response = self.app.post(
866 863 route_path('pullrequest_create', repo_name=source.repo_name),
867 864 [
868 865 ('source_repo', source.repo_name),
869 866 ('source_ref', 'branch:default:' + commit_ids['change']),
870 867 ('target_repo', target.repo_name),
871 868 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
872 869 ('common_ancestor', commit_ids['ancestor']),
873 870 ('pullrequest_title', 'Title'),
874 871 ('pullrequest_desc', 'Description'),
875 872 ('description_renderer', 'markdown'),
876 873 ('__start__', 'review_members:sequence'),
877 874 ('__start__', 'reviewer:mapping'),
878 875 ('user_id', '2'),
879 876 ('__start__', 'reasons:sequence'),
880 877 ('reason', 'Some reason'),
881 878 ('__end__', 'reasons:sequence'),
882 879 ('__start__', 'rules:sequence'),
883 880 ('__end__', 'rules:sequence'),
884 881 ('mandatory', 'False'),
885 882 ('__end__', 'reviewer:mapping'),
886 883 ('__end__', 'review_members:sequence'),
887 884 ('__start__', 'revisions:sequence'),
888 885 ('revisions', commit_ids['change']),
889 886 ('__end__', 'revisions:sequence'),
890 887 ('user', ''),
891 888 ('csrf_token', csrf_token),
892 889 ],
893 890 status=302)
894 891
895 892 location = response.headers['Location']
896 893
897 894 pull_request_id = location.rsplit('/', 1)[1]
898 895 assert pull_request_id != 'new'
899 896 pull_request = PullRequest.get(int(pull_request_id))
900 897
901 898 # Check that a notification was made
902 899 notifications = Notification.query()\
903 900 .filter(Notification.created_by == pull_request.author.user_id,
904 901 Notification.type_ == Notification.TYPE_PULL_REQUEST,
905 902 Notification.subject.contains(
906 903 "requested a pull request review. !%s" % pull_request_id))
907 904 assert len(notifications.all()) == 1
908 905
909 906 # Change reviewers and check that a notification was made
910 907 PullRequestModel().update_reviewers(
911 908 pull_request.pull_request_id, [
912 909 (1, [], False, 'reviewer', [])
913 910 ],
914 911 pull_request.author)
915 912 assert len(notifications.all()) == 2
916 913
917 914 def test_create_pull_request_stores_ancestor_commit_id(self, backend, csrf_token):
918 915 commits = [
919 916 {'message': 'ancestor',
920 917 'added': [FileNode('file_A', content='content_of_ancestor')]},
921 918 {'message': 'change',
922 919 'added': [FileNode('file_a', content='content_of_change')]},
923 920 {'message': 'change-child'},
924 921 {'message': 'ancestor-child', 'parents': ['ancestor'],
925 922 'added': [
926 923 FileNode('file_B', content='content_of_ancestor_child')]},
927 924 {'message': 'ancestor-child-2'},
928 925 ]
929 926 commit_ids = backend.create_master_repo(commits)
930 927 target = backend.create_repo(heads=['ancestor-child'])
931 928 source = backend.create_repo(heads=['change'])
932 929
933 930 response = self.app.post(
934 931 route_path('pullrequest_create', repo_name=source.repo_name),
935 932 [
936 933 ('source_repo', source.repo_name),
937 934 ('source_ref', 'branch:default:' + commit_ids['change']),
938 935 ('target_repo', target.repo_name),
939 936 ('target_ref', 'branch:default:' + commit_ids['ancestor-child']),
940 937 ('common_ancestor', commit_ids['ancestor']),
941 938 ('pullrequest_title', 'Title'),
942 939 ('pullrequest_desc', 'Description'),
943 940 ('description_renderer', 'markdown'),
944 941 ('__start__', 'review_members:sequence'),
945 942 ('__start__', 'reviewer:mapping'),
946 943 ('user_id', '1'),
947 944 ('__start__', 'reasons:sequence'),
948 945 ('reason', 'Some reason'),
949 946 ('__end__', 'reasons:sequence'),
950 947 ('__start__', 'rules:sequence'),
951 948 ('__end__', 'rules:sequence'),
952 949 ('mandatory', 'False'),
953 950 ('__end__', 'reviewer:mapping'),
954 951 ('__end__', 'review_members:sequence'),
955 952 ('__start__', 'revisions:sequence'),
956 953 ('revisions', commit_ids['change']),
957 954 ('__end__', 'revisions:sequence'),
958 955 ('user', ''),
959 956 ('csrf_token', csrf_token),
960 957 ],
961 958 status=302)
962 959
963 960 location = response.headers['Location']
964 961
965 962 pull_request_id = location.rsplit('/', 1)[1]
966 963 assert pull_request_id != 'new'
967 964 pull_request = PullRequest.get(int(pull_request_id))
968 965
969 966 # target_ref has to point to the ancestor's commit_id in order to
970 967 # show the correct diff
971 968 expected_target_ref = 'branch:default:' + commit_ids['ancestor']
972 969 assert pull_request.target_ref == expected_target_ref
973 970
974 971 # Check generated diff contents
975 972 response = response.follow()
976 973 response.mustcontain(no=['content_of_ancestor'])
977 974 response.mustcontain(no=['content_of_ancestor-child'])
978 975 response.mustcontain('content_of_change')
979 976
980 977 def test_merge_pull_request_enabled(self, pr_util, csrf_token):
981 978 # Clear any previous calls to rcextensions
982 979 rhodecode.EXTENSIONS.calls.clear()
983 980
984 981 pull_request = pr_util.create_pull_request(
985 982 approved=True, mergeable=True)
986 983 pull_request_id = pull_request.pull_request_id
987 984 repo_name = pull_request.target_repo.scm_instance().name,
988 985
989 986 url = route_path('pullrequest_merge',
990 987 repo_name=str(repo_name[0]),
991 988 pull_request_id=pull_request_id)
992 989 response = self.app.post(url, params={'csrf_token': csrf_token}).follow()
993 990
994 991 pull_request = PullRequest.get(pull_request_id)
995 992
996 993 assert response.status_int == 200
997 994 assert pull_request.is_closed()
998 995 assert_pull_request_status(
999 996 pull_request, ChangesetStatus.STATUS_APPROVED)
1000 997
1001 998 # Check the relevant log entries were added
1002 999 user_logs = UserLog.query().order_by(UserLog.user_log_id.desc()).limit(3)
1003 1000 actions = [log.action for log in user_logs]
1004 1001 pr_commit_ids = PullRequestModel()._get_commit_ids(pull_request)
1005 1002 expected_actions = [
1006 1003 u'repo.pull_request.close',
1007 1004 u'repo.pull_request.merge',
1008 1005 u'repo.pull_request.comment.create'
1009 1006 ]
1010 1007 assert actions == expected_actions
1011 1008
1012 1009 user_logs = UserLog.query().order_by(UserLog.user_log_id.desc()).limit(4)
1013 1010 actions = [log for log in user_logs]
1014 1011 assert actions[-1].action == 'user.push'
1015 1012 assert actions[-1].action_data['commit_ids'] == pr_commit_ids
1016 1013
1017 1014 # Check post_push rcextension was really executed
1018 1015 push_calls = rhodecode.EXTENSIONS.calls['_push_hook']
1019 1016 assert len(push_calls) == 1
1020 1017 unused_last_call_args, last_call_kwargs = push_calls[0]
1021 1018 assert last_call_kwargs['action'] == 'push'
1022 1019 assert last_call_kwargs['commit_ids'] == pr_commit_ids
1023 1020
1024 1021 def test_merge_pull_request_disabled(self, pr_util, csrf_token):
1025 1022 pull_request = pr_util.create_pull_request(mergeable=False)
1026 1023 pull_request_id = pull_request.pull_request_id
1027 1024 pull_request = PullRequest.get(pull_request_id)
1028 1025
1029 1026 response = self.app.post(
1030 1027 route_path('pullrequest_merge',
1031 1028 repo_name=pull_request.target_repo.scm_instance().name,
1032 1029 pull_request_id=pull_request.pull_request_id),
1033 1030 params={'csrf_token': csrf_token}).follow()
1034 1031
1035 1032 assert response.status_int == 200
1036 1033 response.mustcontain(
1037 1034 'Merge is not currently possible because of below failed checks.')
1038 1035 response.mustcontain('Server-side pull request merging is disabled.')
1039 1036
1040 1037 @pytest.mark.skip_backends('svn')
1041 1038 def test_merge_pull_request_not_approved(self, pr_util, csrf_token):
1042 1039 pull_request = pr_util.create_pull_request(mergeable=True)
1043 1040 pull_request_id = pull_request.pull_request_id
1044 1041 repo_name = pull_request.target_repo.scm_instance().name
1045 1042
1046 1043 response = self.app.post(
1047 1044 route_path('pullrequest_merge',
1048 1045 repo_name=repo_name, pull_request_id=pull_request_id),
1049 1046 params={'csrf_token': csrf_token}).follow()
1050 1047
1051 1048 assert response.status_int == 200
1052 1049
1053 1050 response.mustcontain(
1054 1051 'Merge is not currently possible because of below failed checks.')
1055 1052 response.mustcontain('Pull request reviewer approval is pending.')
1056 1053
1057 1054 def test_merge_pull_request_renders_failure_reason(
1058 1055 self, user_regular, csrf_token, pr_util):
1059 1056 pull_request = pr_util.create_pull_request(mergeable=True, approved=True)
1060 1057 pull_request_id = pull_request.pull_request_id
1061 1058 repo_name = pull_request.target_repo.scm_instance().name
1062 1059
1063 1060 merge_resp = MergeResponse(True, False, 'STUB_COMMIT_ID',
1064 1061 MergeFailureReason.PUSH_FAILED,
1065 1062 metadata={'target': 'shadow repo',
1066 1063 'merge_commit': 'xxx'})
1067 1064 model_patcher = mock.patch.multiple(
1068 1065 PullRequestModel,
1069 1066 merge_repo=mock.Mock(return_value=merge_resp),
1070 1067 merge_status=mock.Mock(return_value=(None, True, 'WRONG_MESSAGE')))
1071 1068
1072 1069 with model_patcher:
1073 1070 response = self.app.post(
1074 1071 route_path('pullrequest_merge',
1075 1072 repo_name=repo_name,
1076 1073 pull_request_id=pull_request_id),
1077 1074 params={'csrf_token': csrf_token}, status=302)
1078 1075
1079 1076 merge_resp = MergeResponse(True, True, '', MergeFailureReason.PUSH_FAILED,
1080 1077 metadata={'target': 'shadow repo',
1081 1078 'merge_commit': 'xxx'})
1082 1079 assert_session_flash(response, merge_resp.merge_status_message)
1083 1080
1084 1081 def test_update_source_revision(self, backend, csrf_token):
1085 1082 commits = [
1086 1083 {'message': 'ancestor'},
1087 1084 {'message': 'change'},
1088 1085 {'message': 'change-2'},
1089 1086 ]
1090 1087 commit_ids = backend.create_master_repo(commits)
1091 1088 target = backend.create_repo(heads=['ancestor'])
1092 1089 source = backend.create_repo(heads=['change'])
1093 1090
1094 1091 # create pr from a in source to A in target
1095 1092 pull_request = PullRequest()
1096 1093
1097 1094 pull_request.source_repo = source
1098 1095 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
1099 1096 branch=backend.default_branch_name, commit_id=commit_ids['change'])
1100 1097
1101 1098 pull_request.target_repo = target
1102 1099 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
1103 1100 branch=backend.default_branch_name, commit_id=commit_ids['ancestor'])
1104 1101
1105 1102 pull_request.revisions = [commit_ids['change']]
1106 1103 pull_request.title = u"Test"
1107 1104 pull_request.description = u"Description"
1108 1105 pull_request.author = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
1109 1106 pull_request.pull_request_state = PullRequest.STATE_CREATED
1110 1107 Session().add(pull_request)
1111 1108 Session().commit()
1112 1109 pull_request_id = pull_request.pull_request_id
1113 1110
1114 1111 # source has ancestor - change - change-2
1115 1112 backend.pull_heads(source, heads=['change-2'])
1116 1113 target_repo_name = target.repo_name
1117 1114
1118 1115 # update PR
1119 1116 self.app.post(
1120 1117 route_path('pullrequest_update',
1121 1118 repo_name=target_repo_name, pull_request_id=pull_request_id),
1122 1119 params={'update_commits': 'true', 'csrf_token': csrf_token})
1123 1120
1124 1121 response = self.app.get(
1125 1122 route_path('pullrequest_show',
1126 1123 repo_name=target_repo_name,
1127 1124 pull_request_id=pull_request.pull_request_id))
1128 1125
1129 1126 assert response.status_int == 200
1130 1127 response.mustcontain('Pull request updated to')
1131 1128 response.mustcontain('with 1 added, 0 removed commits.')
1132 1129
1133 1130 # check that we have now both revisions
1134 1131 pull_request = PullRequest.get(pull_request_id)
1135 1132 assert pull_request.revisions == [commit_ids['change-2'], commit_ids['change']]
1136 1133
1137 1134 def test_update_target_revision(self, backend, csrf_token):
1138 1135 commits = [
1139 1136 {'message': 'ancestor'},
1140 1137 {'message': 'change'},
1141 1138 {'message': 'ancestor-new', 'parents': ['ancestor']},
1142 1139 {'message': 'change-rebased'},
1143 1140 ]
1144 1141 commit_ids = backend.create_master_repo(commits)
1145 1142 target = backend.create_repo(heads=['ancestor'])
1146 1143 source = backend.create_repo(heads=['change'])
1147 1144
1148 1145 # create pr from a in source to A in target
1149 1146 pull_request = PullRequest()
1150 1147
1151 1148 pull_request.source_repo = source
1152 1149 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
1153 1150 branch=backend.default_branch_name, commit_id=commit_ids['change'])
1154 1151
1155 1152 pull_request.target_repo = target
1156 1153 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
1157 1154 branch=backend.default_branch_name, commit_id=commit_ids['ancestor'])
1158 1155
1159 1156 pull_request.revisions = [commit_ids['change']]
1160 1157 pull_request.title = u"Test"
1161 1158 pull_request.description = u"Description"
1162 1159 pull_request.author = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
1163 1160 pull_request.pull_request_state = PullRequest.STATE_CREATED
1164 1161
1165 1162 Session().add(pull_request)
1166 1163 Session().commit()
1167 1164 pull_request_id = pull_request.pull_request_id
1168 1165
1169 1166 # target has ancestor - ancestor-new
1170 1167 # source has ancestor - ancestor-new - change-rebased
1171 1168 backend.pull_heads(target, heads=['ancestor-new'])
1172 1169 backend.pull_heads(source, heads=['change-rebased'])
1173 1170 target_repo_name = target.repo_name
1174 1171
1175 1172 # update PR
1176 1173 url = route_path('pullrequest_update',
1177 1174 repo_name=target_repo_name,
1178 1175 pull_request_id=pull_request_id)
1179 1176 self.app.post(url,
1180 1177 params={'update_commits': 'true', 'csrf_token': csrf_token},
1181 1178 status=200)
1182 1179
1183 1180 # check that we have now both revisions
1184 1181 pull_request = PullRequest.get(pull_request_id)
1185 1182 assert pull_request.revisions == [commit_ids['change-rebased']]
1186 1183 assert pull_request.target_ref == 'branch:{branch}:{commit_id}'.format(
1187 1184 branch=backend.default_branch_name, commit_id=commit_ids['ancestor-new'])
1188 1185
1189 1186 response = self.app.get(
1190 1187 route_path('pullrequest_show',
1191 1188 repo_name=target_repo_name,
1192 1189 pull_request_id=pull_request.pull_request_id))
1193 1190 assert response.status_int == 200
1194 1191 response.mustcontain('Pull request updated to')
1195 1192 response.mustcontain('with 1 added, 1 removed commits.')
1196 1193
1197 1194 def test_update_target_revision_with_removal_of_1_commit_git(self, backend_git, csrf_token):
1198 1195 backend = backend_git
1199 1196 commits = [
1200 1197 {'message': 'master-commit-1'},
1201 1198 {'message': 'master-commit-2-change-1'},
1202 1199 {'message': 'master-commit-3-change-2'},
1203 1200
1204 1201 {'message': 'feat-commit-1', 'parents': ['master-commit-1']},
1205 1202 {'message': 'feat-commit-2'},
1206 1203 ]
1207 1204 commit_ids = backend.create_master_repo(commits)
1208 1205 target = backend.create_repo(heads=['master-commit-3-change-2'])
1209 1206 source = backend.create_repo(heads=['feat-commit-2'])
1210 1207
1211 1208 # create pr from a in source to A in target
1212 1209 pull_request = PullRequest()
1213 1210 pull_request.source_repo = source
1214 1211
1215 1212 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
1216 1213 branch=backend.default_branch_name,
1217 1214 commit_id=commit_ids['master-commit-3-change-2'])
1218 1215
1219 1216 pull_request.target_repo = target
1220 1217 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
1221 1218 branch=backend.default_branch_name, commit_id=commit_ids['feat-commit-2'])
1222 1219
1223 1220 pull_request.revisions = [
1224 1221 commit_ids['feat-commit-1'],
1225 1222 commit_ids['feat-commit-2']
1226 1223 ]
1227 1224 pull_request.title = u"Test"
1228 1225 pull_request.description = u"Description"
1229 1226 pull_request.author = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
1230 1227 pull_request.pull_request_state = PullRequest.STATE_CREATED
1231 1228 Session().add(pull_request)
1232 1229 Session().commit()
1233 1230 pull_request_id = pull_request.pull_request_id
1234 1231
1235 1232 # PR is created, now we simulate a force-push into target,
1236 1233 # that drops a 2 last commits
1237 1234 vcsrepo = target.scm_instance()
1238 1235 vcsrepo.config.clear_section('hooks')
1239 1236 vcsrepo.run_git_command(['reset', '--soft', 'HEAD~2'])
1240 1237 target_repo_name = target.repo_name
1241 1238
1242 1239 # update PR
1243 1240 url = route_path('pullrequest_update',
1244 1241 repo_name=target_repo_name,
1245 1242 pull_request_id=pull_request_id)
1246 1243 self.app.post(url,
1247 1244 params={'update_commits': 'true', 'csrf_token': csrf_token},
1248 1245 status=200)
1249 1246
1250 1247 response = self.app.get(route_path('pullrequest_new', repo_name=target_repo_name))
1251 1248 assert response.status_int == 200
1252 1249 response.mustcontain('Pull request updated to')
1253 1250 response.mustcontain('with 0 added, 0 removed commits.')
1254 1251
1255 1252 def test_update_of_ancestor_reference(self, backend, csrf_token):
1256 1253 commits = [
1257 1254 {'message': 'ancestor'},
1258 1255 {'message': 'change'},
1259 1256 {'message': 'change-2'},
1260 1257 {'message': 'ancestor-new', 'parents': ['ancestor']},
1261 1258 {'message': 'change-rebased'},
1262 1259 ]
1263 1260 commit_ids = backend.create_master_repo(commits)
1264 1261 target = backend.create_repo(heads=['ancestor'])
1265 1262 source = backend.create_repo(heads=['change'])
1266 1263
1267 1264 # create pr from a in source to A in target
1268 1265 pull_request = PullRequest()
1269 1266 pull_request.source_repo = source
1270 1267
1271 1268 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
1272 1269 branch=backend.default_branch_name, commit_id=commit_ids['change'])
1273 1270 pull_request.target_repo = target
1274 1271 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
1275 1272 branch=backend.default_branch_name, commit_id=commit_ids['ancestor'])
1276 1273 pull_request.revisions = [commit_ids['change']]
1277 1274 pull_request.title = u"Test"
1278 1275 pull_request.description = u"Description"
1279 1276 pull_request.author = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
1280 1277 pull_request.pull_request_state = PullRequest.STATE_CREATED
1281 1278 Session().add(pull_request)
1282 1279 Session().commit()
1283 1280 pull_request_id = pull_request.pull_request_id
1284 1281
1285 1282 # target has ancestor - ancestor-new
1286 1283 # source has ancestor - ancestor-new - change-rebased
1287 1284 backend.pull_heads(target, heads=['ancestor-new'])
1288 1285 backend.pull_heads(source, heads=['change-rebased'])
1289 1286 target_repo_name = target.repo_name
1290 1287
1291 1288 # update PR
1292 1289 self.app.post(
1293 1290 route_path('pullrequest_update',
1294 1291 repo_name=target_repo_name, pull_request_id=pull_request_id),
1295 1292 params={'update_commits': 'true', 'csrf_token': csrf_token},
1296 1293 status=200)
1297 1294
1298 1295 # Expect the target reference to be updated correctly
1299 1296 pull_request = PullRequest.get(pull_request_id)
1300 1297 assert pull_request.revisions == [commit_ids['change-rebased']]
1301 1298 expected_target_ref = 'branch:{branch}:{commit_id}'.format(
1302 1299 branch=backend.default_branch_name,
1303 1300 commit_id=commit_ids['ancestor-new'])
1304 1301 assert pull_request.target_ref == expected_target_ref
1305 1302
1306 1303 def test_remove_pull_request_branch(self, backend_git, csrf_token):
1307 1304 branch_name = 'development'
1308 1305 commits = [
1309 1306 {'message': 'initial-commit'},
1310 1307 {'message': 'old-feature'},
1311 1308 {'message': 'new-feature', 'branch': branch_name},
1312 1309 ]
1313 1310 repo = backend_git.create_repo(commits)
1314 1311 repo_name = repo.repo_name
1315 1312 commit_ids = backend_git.commit_ids
1316 1313
1317 1314 pull_request = PullRequest()
1318 1315 pull_request.source_repo = repo
1319 1316 pull_request.target_repo = repo
1320 1317 pull_request.source_ref = 'branch:{branch}:{commit_id}'.format(
1321 1318 branch=branch_name, commit_id=commit_ids['new-feature'])
1322 1319 pull_request.target_ref = 'branch:{branch}:{commit_id}'.format(
1323 1320 branch=backend_git.default_branch_name, commit_id=commit_ids['old-feature'])
1324 1321 pull_request.revisions = [commit_ids['new-feature']]
1325 1322 pull_request.title = u"Test"
1326 1323 pull_request.description = u"Description"
1327 1324 pull_request.author = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
1328 1325 pull_request.pull_request_state = PullRequest.STATE_CREATED
1329 1326 Session().add(pull_request)
1330 1327 Session().commit()
1331 1328
1332 1329 pull_request_id = pull_request.pull_request_id
1333 1330
1334 1331 vcs = repo.scm_instance()
1335 1332 vcs.remove_ref('refs/heads/{}'.format(branch_name))
1336 1333 # NOTE(marcink): run GC to ensure the commits are gone
1337 1334 vcs.run_gc()
1338 1335
1339 1336 response = self.app.get(route_path(
1340 1337 'pullrequest_show',
1341 1338 repo_name=repo_name,
1342 1339 pull_request_id=pull_request_id))
1343 1340
1344 1341 assert response.status_int == 200
1345 1342
1346 1343 response.assert_response().element_contains(
1347 1344 '#changeset_compare_view_content .alert strong',
1348 1345 'Missing commits')
1349 1346 response.assert_response().element_contains(
1350 1347 '#changeset_compare_view_content .alert',
1351 1348 'This pull request cannot be displayed, because one or more'
1352 1349 ' commits no longer exist in the source repository.')
1353 1350
1354 1351 def test_strip_commits_from_pull_request(
1355 1352 self, backend, pr_util, csrf_token):
1356 1353 commits = [
1357 1354 {'message': 'initial-commit'},
1358 1355 {'message': 'old-feature'},
1359 1356 {'message': 'new-feature', 'parents': ['initial-commit']},
1360 1357 ]
1361 1358 pull_request = pr_util.create_pull_request(
1362 1359 commits, target_head='initial-commit', source_head='new-feature',
1363 1360 revisions=['new-feature'])
1364 1361
1365 1362 vcs = pr_util.source_repository.scm_instance()
1366 1363 if backend.alias == 'git':
1367 1364 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
1368 1365 else:
1369 1366 vcs.strip(pr_util.commit_ids['new-feature'])
1370 1367
1371 1368 response = self.app.get(route_path(
1372 1369 'pullrequest_show',
1373 1370 repo_name=pr_util.target_repository.repo_name,
1374 1371 pull_request_id=pull_request.pull_request_id))
1375 1372
1376 1373 assert response.status_int == 200
1377 1374
1378 1375 response.assert_response().element_contains(
1379 1376 '#changeset_compare_view_content .alert strong',
1380 1377 'Missing commits')
1381 1378 response.assert_response().element_contains(
1382 1379 '#changeset_compare_view_content .alert',
1383 1380 'This pull request cannot be displayed, because one or more'
1384 1381 ' commits no longer exist in the source repository.')
1385 1382 response.assert_response().element_contains(
1386 1383 '#update_commits',
1387 1384 'Update commits')
1388 1385
1389 1386 def test_strip_commits_and_update(
1390 1387 self, backend, pr_util, csrf_token):
1391 1388 commits = [
1392 1389 {'message': 'initial-commit'},
1393 1390 {'message': 'old-feature'},
1394 1391 {'message': 'new-feature', 'parents': ['old-feature']},
1395 1392 ]
1396 1393 pull_request = pr_util.create_pull_request(
1397 1394 commits, target_head='old-feature', source_head='new-feature',
1398 1395 revisions=['new-feature'], mergeable=True)
1399 1396 pr_id = pull_request.pull_request_id
1400 1397 target_repo_name = pull_request.target_repo.repo_name
1401 1398
1402 1399 vcs = pr_util.source_repository.scm_instance()
1403 1400 if backend.alias == 'git':
1404 1401 vcs.strip(pr_util.commit_ids['new-feature'], branch_name='master')
1405 1402 else:
1406 1403 vcs.strip(pr_util.commit_ids['new-feature'])
1407 1404
1408 1405 url = route_path('pullrequest_update',
1409 1406 repo_name=target_repo_name,
1410 1407 pull_request_id=pr_id)
1411 1408 response = self.app.post(url,
1412 1409 params={'update_commits': 'true',
1413 1410 'csrf_token': csrf_token})
1414 1411
1415 1412 assert response.status_int == 200
1416 1413 assert response.body == '{"response": true, "redirect_url": null}'
1417 1414
1418 1415 # Make sure that after update, it won't raise 500 errors
1419 1416 response = self.app.get(route_path(
1420 1417 'pullrequest_show',
1421 1418 repo_name=target_repo_name,
1422 1419 pull_request_id=pr_id))
1423 1420
1424 1421 assert response.status_int == 200
1425 1422 response.assert_response().element_contains(
1426 1423 '#changeset_compare_view_content .alert strong',
1427 1424 'Missing commits')
1428 1425
1429 1426 def test_branch_is_a_link(self, pr_util):
1430 1427 pull_request = pr_util.create_pull_request()
1431 1428 pull_request.source_ref = 'branch:origin:1234567890abcdef'
1432 1429 pull_request.target_ref = 'branch:target:abcdef1234567890'
1433 1430 Session().add(pull_request)
1434 1431 Session().commit()
1435 1432
1436 1433 response = self.app.get(route_path(
1437 1434 'pullrequest_show',
1438 1435 repo_name=pull_request.target_repo.scm_instance().name,
1439 1436 pull_request_id=pull_request.pull_request_id))
1440 1437 assert response.status_int == 200
1441 1438
1442 1439 source = response.assert_response().get_element('.pr-source-info')
1443 1440 source_parent = source.getparent()
1444 1441 assert len(source_parent) == 1
1445 1442
1446 1443 target = response.assert_response().get_element('.pr-target-info')
1447 1444 target_parent = target.getparent()
1448 1445 assert len(target_parent) == 1
1449 1446
1450 1447 expected_origin_link = route_path(
1451 1448 'repo_commits',
1452 1449 repo_name=pull_request.source_repo.scm_instance().name,
1453 1450 params=dict(branch='origin'))
1454 1451 expected_target_link = route_path(
1455 1452 'repo_commits',
1456 1453 repo_name=pull_request.target_repo.scm_instance().name,
1457 1454 params=dict(branch='target'))
1458 1455 assert source_parent.attrib['href'] == expected_origin_link
1459 1456 assert target_parent.attrib['href'] == expected_target_link
1460 1457
1461 1458 def test_bookmark_is_not_a_link(self, pr_util):
1462 1459 pull_request = pr_util.create_pull_request()
1463 1460 pull_request.source_ref = 'bookmark:origin:1234567890abcdef'
1464 1461 pull_request.target_ref = 'bookmark:target:abcdef1234567890'
1465 1462 Session().add(pull_request)
1466 1463 Session().commit()
1467 1464
1468 1465 response = self.app.get(route_path(
1469 1466 'pullrequest_show',
1470 1467 repo_name=pull_request.target_repo.scm_instance().name,
1471 1468 pull_request_id=pull_request.pull_request_id))
1472 1469 assert response.status_int == 200
1473 1470
1474 1471 source = response.assert_response().get_element('.pr-source-info')
1475 1472 assert source.text.strip() == 'bookmark:origin'
1476 1473 assert source.getparent().attrib.get('href') is None
1477 1474
1478 1475 target = response.assert_response().get_element('.pr-target-info')
1479 1476 assert target.text.strip() == 'bookmark:target'
1480 1477 assert target.getparent().attrib.get('href') is None
1481 1478
1482 1479 def test_tag_is_not_a_link(self, pr_util):
1483 1480 pull_request = pr_util.create_pull_request()
1484 1481 pull_request.source_ref = 'tag:origin:1234567890abcdef'
1485 1482 pull_request.target_ref = 'tag:target:abcdef1234567890'
1486 1483 Session().add(pull_request)
1487 1484 Session().commit()
1488 1485
1489 1486 response = self.app.get(route_path(
1490 1487 'pullrequest_show',
1491 1488 repo_name=pull_request.target_repo.scm_instance().name,
1492 1489 pull_request_id=pull_request.pull_request_id))
1493 1490 assert response.status_int == 200
1494 1491
1495 1492 source = response.assert_response().get_element('.pr-source-info')
1496 1493 assert source.text.strip() == 'tag:origin'
1497 1494 assert source.getparent().attrib.get('href') is None
1498 1495
1499 1496 target = response.assert_response().get_element('.pr-target-info')
1500 1497 assert target.text.strip() == 'tag:target'
1501 1498 assert target.getparent().attrib.get('href') is None
1502 1499
1503 1500 @pytest.mark.parametrize('mergeable', [True, False])
1504 1501 def test_shadow_repository_link(
1505 1502 self, mergeable, pr_util, http_host_only_stub):
1506 1503 """
1507 1504 Check that the pull request summary page displays a link to the shadow
1508 1505 repository if the pull request is mergeable. If it is not mergeable
1509 1506 the link should not be displayed.
1510 1507 """
1511 1508 pull_request = pr_util.create_pull_request(
1512 1509 mergeable=mergeable, enable_notifications=False)
1513 1510 target_repo = pull_request.target_repo.scm_instance()
1514 1511 pr_id = pull_request.pull_request_id
1515 1512 shadow_url = '{host}/{repo}/pull-request/{pr_id}/repository'.format(
1516 1513 host=http_host_only_stub, repo=target_repo.name, pr_id=pr_id)
1517 1514
1518 1515 response = self.app.get(route_path(
1519 1516 'pullrequest_show',
1520 1517 repo_name=target_repo.name,
1521 1518 pull_request_id=pr_id))
1522 1519
1523 1520 if mergeable:
1524 1521 response.assert_response().element_value_contains(
1525 1522 'input.pr-mergeinfo', shadow_url)
1526 1523 response.assert_response().element_value_contains(
1527 1524 'input.pr-mergeinfo ', 'pr-merge')
1528 1525 else:
1529 1526 response.assert_response().no_element_exists('.pr-mergeinfo')
1530 1527
1531 1528
1532 1529 @pytest.mark.usefixtures('app')
1533 1530 @pytest.mark.backends("git", "hg")
1534 1531 class TestPullrequestsControllerDelete(object):
1535 1532 def test_pull_request_delete_button_permissions_admin(
1536 1533 self, autologin_user, user_admin, pr_util):
1537 1534 pull_request = pr_util.create_pull_request(
1538 1535 author=user_admin.username, enable_notifications=False)
1539 1536
1540 1537 response = self.app.get(route_path(
1541 1538 'pullrequest_show',
1542 1539 repo_name=pull_request.target_repo.scm_instance().name,
1543 1540 pull_request_id=pull_request.pull_request_id))
1544 1541
1545 1542 response.mustcontain('id="delete_pullrequest"')
1546 1543 response.mustcontain('Confirm to delete this pull request')
1547 1544
1548 1545 def test_pull_request_delete_button_permissions_owner(
1549 1546 self, autologin_regular_user, user_regular, pr_util):
1550 1547 pull_request = pr_util.create_pull_request(
1551 1548 author=user_regular.username, enable_notifications=False)
1552 1549
1553 1550 response = self.app.get(route_path(
1554 1551 'pullrequest_show',
1555 1552 repo_name=pull_request.target_repo.scm_instance().name,
1556 1553 pull_request_id=pull_request.pull_request_id))
1557 1554
1558 1555 response.mustcontain('id="delete_pullrequest"')
1559 1556 response.mustcontain('Confirm to delete this pull request')
1560 1557
1561 1558 def test_pull_request_delete_button_permissions_forbidden(
1562 1559 self, autologin_regular_user, user_regular, user_admin, pr_util):
1563 1560 pull_request = pr_util.create_pull_request(
1564 1561 author=user_admin.username, enable_notifications=False)
1565 1562
1566 1563 response = self.app.get(route_path(
1567 1564 'pullrequest_show',
1568 1565 repo_name=pull_request.target_repo.scm_instance().name,
1569 1566 pull_request_id=pull_request.pull_request_id))
1570 1567 response.mustcontain(no=['id="delete_pullrequest"'])
1571 1568 response.mustcontain(no=['Confirm to delete this pull request'])
1572 1569
1573 1570 def test_pull_request_delete_button_permissions_can_update_cannot_delete(
1574 1571 self, autologin_regular_user, user_regular, user_admin, pr_util,
1575 1572 user_util):
1576 1573
1577 1574 pull_request = pr_util.create_pull_request(
1578 1575 author=user_admin.username, enable_notifications=False)
1579 1576
1580 1577 user_util.grant_user_permission_to_repo(
1581 1578 pull_request.target_repo, user_regular,
1582 1579 'repository.write')
1583 1580
1584 1581 response = self.app.get(route_path(
1585 1582 'pullrequest_show',
1586 1583 repo_name=pull_request.target_repo.scm_instance().name,
1587 1584 pull_request_id=pull_request.pull_request_id))
1588 1585
1589 1586 response.mustcontain('id="open_edit_pullrequest"')
1590 1587 response.mustcontain('id="delete_pullrequest"')
1591 1588 response.mustcontain(no=['Confirm to delete this pull request'])
1592 1589
1593 1590 def test_delete_comment_returns_404_if_comment_does_not_exist(
1594 1591 self, autologin_user, pr_util, user_admin, csrf_token, xhr_header):
1595 1592
1596 1593 pull_request = pr_util.create_pull_request(
1597 1594 author=user_admin.username, enable_notifications=False)
1598 1595
1599 1596 self.app.post(
1600 1597 route_path(
1601 1598 'pullrequest_comment_delete',
1602 1599 repo_name=pull_request.target_repo.scm_instance().name,
1603 1600 pull_request_id=pull_request.pull_request_id,
1604 1601 comment_id=1024404),
1605 1602 extra_environ=xhr_header,
1606 1603 params={'csrf_token': csrf_token},
1607 1604 status=404
1608 1605 )
1609 1606
1610 1607 def test_delete_comment(
1611 1608 self, autologin_user, pr_util, user_admin, csrf_token, xhr_header):
1612 1609
1613 1610 pull_request = pr_util.create_pull_request(
1614 1611 author=user_admin.username, enable_notifications=False)
1615 1612 comment = pr_util.create_comment()
1616 1613 comment_id = comment.comment_id
1617 1614
1618 1615 response = self.app.post(
1619 1616 route_path(
1620 1617 'pullrequest_comment_delete',
1621 1618 repo_name=pull_request.target_repo.scm_instance().name,
1622 1619 pull_request_id=pull_request.pull_request_id,
1623 1620 comment_id=comment_id),
1624 1621 extra_environ=xhr_header,
1625 1622 params={'csrf_token': csrf_token},
1626 1623 status=200
1627 1624 )
1628 1625 assert response.body == 'true'
1629 1626
1630 1627 @pytest.mark.parametrize('url_type', [
1631 1628 'pullrequest_new',
1632 1629 'pullrequest_create',
1633 1630 'pullrequest_update',
1634 1631 'pullrequest_merge',
1635 1632 ])
1636 1633 def test_pull_request_is_forbidden_on_archived_repo(
1637 1634 self, autologin_user, backend, xhr_header, user_util, url_type):
1638 1635
1639 1636 # create a temporary repo
1640 1637 source = user_util.create_repo(repo_type=backend.alias)
1641 1638 repo_name = source.repo_name
1642 1639 repo = Repository.get_by_repo_name(repo_name)
1643 1640 repo.archived = True
1644 1641 Session().commit()
1645 1642
1646 1643 response = self.app.get(
1647 1644 route_path(url_type, repo_name=repo_name, pull_request_id=1), status=302)
1648 1645
1649 1646 msg = 'Action not supported for archived repository.'
1650 1647 assert_session_flash(response, msg)
1651 1648
1652 1649
1653 1650 def assert_pull_request_status(pull_request, expected_status):
1654 1651 status = ChangesetStatusModel().calculated_review_status(pull_request=pull_request)
1655 1652 assert status == expected_status
1656 1653
1657 1654
1658 1655 @pytest.mark.parametrize('route', ['pullrequest_new', 'pullrequest_create'])
1659 1656 @pytest.mark.usefixtures("autologin_user")
1660 1657 def test_forbidde_to_repo_summary_for_svn_repositories(backend_svn, app, route):
1661 1658 app.get(route_path(route, repo_name=backend_svn.repo_name), status=404)
General Comments 0
You need to be logged in to leave comments. Login now