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