##// END OF EJS Templates
tests: fixed some tests
super-admin -
r4704:fa2afbc9 stable
parent child Browse files
Show More
@@ -1,170 +1,171 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
21 21 import pytest
22 22
23 from rhodecode.events import UserPermissionsChange
23 24 from rhodecode.lib.utils2 import StrictAttributeDict
24 25 from rhodecode.tests.events.conftest import EventCatcher
25 26
26 27 from rhodecode.lib import hooks_base, utils2
27 28 from rhodecode.model.repo import RepoModel
28 29 from rhodecode.events.repo import (
29 30 RepoPrePullEvent, RepoPullEvent,
30 31 RepoPrePushEvent, RepoPushEvent,
31 32 RepoPreCreateEvent, RepoCreateEvent,
32 33 RepoPreDeleteEvent, RepoDeleteEvent,
33 34 RepoCommitCommentEvent, RepoCommitCommentEditEvent
34 35 )
35 36
36 37
37 38 @pytest.fixture()
38 39 def scm_extras(user_regular, repo_stub):
39 40 extras = utils2.AttributeDict({
40 41 'ip': '127.0.0.1',
41 42 'username': user_regular.username,
42 43 'user_id': user_regular.user_id,
43 44 'action': '',
44 45 'repository': repo_stub.repo_name,
45 46 'scm': repo_stub.scm_instance().alias,
46 47 'config': '',
47 48 'repo_store': '',
48 49 'server_url': 'http://example.com',
49 50 'make_lock': None,
50 51 'user_agent': 'some-client',
51 52 'locked_by': [None],
52 53 'commit_ids': ['a' * 40] * 3,
53 54 'hook_type': 'scm_extras_test',
54 55 'is_shadow_repo': False,
55 56 })
56 57 return extras
57 58
58 59
59 60 # TODO: dan: make the serialization tests complete json comparisons
60 61 @pytest.mark.parametrize('EventClass', [
61 62 RepoPreCreateEvent, RepoCreateEvent,
62 63 RepoPreDeleteEvent, RepoDeleteEvent,
63 64 ])
64 65 def test_repo_events_serialized(config_stub, repo_stub, EventClass):
65 66 event = EventClass(repo_stub)
66 67 data = event.as_dict()
67 68 assert data['name'] == EventClass.name
68 69 assert data['repo']['repo_name'] == repo_stub.repo_name
69 70 assert data['repo']['url']
70 71 assert data['repo']['permalink_url']
71 72
72 73
73 74 @pytest.mark.parametrize('EventClass', [
74 75 RepoPrePullEvent, RepoPullEvent, RepoPrePushEvent
75 76 ])
76 77 def test_vcs_repo_events_serialize(config_stub, repo_stub, scm_extras, EventClass):
77 78 event = EventClass(repo_name=repo_stub.repo_name, extras=scm_extras)
78 79 data = event.as_dict()
79 80 assert data['name'] == EventClass.name
80 81 assert data['repo']['repo_name'] == repo_stub.repo_name
81 82 assert data['repo']['url']
82 83 assert data['repo']['permalink_url']
83 84
84 85
85 86 @pytest.mark.parametrize('EventClass', [RepoPushEvent])
86 87 def test_vcs_repo_push_event_serialize(config_stub, repo_stub, scm_extras, EventClass):
87 88 event = EventClass(repo_name=repo_stub.repo_name,
88 89 pushed_commit_ids=scm_extras['commit_ids'],
89 90 extras=scm_extras)
90 91 data = event.as_dict()
91 92 assert data['name'] == EventClass.name
92 93 assert data['repo']['repo_name'] == repo_stub.repo_name
93 94 assert data['repo']['url']
94 95 assert data['repo']['permalink_url']
95 96
96 97
97 98 def test_create_delete_repo_fires_events(backend):
98 99 with EventCatcher() as event_catcher:
99 100 repo = backend.create_repo()
100 assert event_catcher.events_types == [RepoPreCreateEvent, RepoCreateEvent]
101 assert event_catcher.events_types == [RepoPreCreateEvent, RepoCreateEvent, UserPermissionsChange]
101 102
102 103 with EventCatcher() as event_catcher:
103 104 RepoModel().delete(repo)
104 105 assert event_catcher.events_types == [RepoPreDeleteEvent, RepoDeleteEvent]
105 106
106 107
107 108 def test_pull_fires_events(scm_extras):
108 109 with EventCatcher() as event_catcher:
109 110 hooks_base.pre_push(scm_extras)
110 111 assert event_catcher.events_types == [RepoPrePushEvent]
111 112
112 113 with EventCatcher() as event_catcher:
113 114 hooks_base.post_push(scm_extras)
114 115 assert event_catcher.events_types == [RepoPushEvent]
115 116
116 117
117 118 def test_push_fires_events(scm_extras):
118 119 with EventCatcher() as event_catcher:
119 120 hooks_base.pre_pull(scm_extras)
120 121 assert event_catcher.events_types == [RepoPrePullEvent]
121 122
122 123 with EventCatcher() as event_catcher:
123 124 hooks_base.post_pull(scm_extras)
124 125 assert event_catcher.events_types == [RepoPullEvent]
125 126
126 127
127 128 @pytest.mark.parametrize('EventClass', [RepoCommitCommentEvent])
128 129 def test_repo_commit_event(config_stub, repo_stub, EventClass):
129 130
130 131 commit = StrictAttributeDict({
131 132 'raw_id': 'raw_id',
132 133 'message': 'message',
133 134 'branch': 'branch',
134 135 })
135 136
136 137 comment = StrictAttributeDict({
137 138 'comment_id': 'comment_id',
138 139 'text': 'text',
139 140 'comment_type': 'comment_type',
140 141 'f_path': 'f_path',
141 142 'line_no': 'line_no',
142 143 'last_version': 0,
143 144 })
144 145 event = EventClass(repo=repo_stub, commit=commit, comment=comment)
145 146 data = event.as_dict()
146 147 assert data['commit']['commit_id']
147 148 assert data['comment']['comment_id']
148 149
149 150
150 151 @pytest.mark.parametrize('EventClass', [RepoCommitCommentEditEvent])
151 152 def test_repo_commit_edit_event(config_stub, repo_stub, EventClass):
152 153
153 154 commit = StrictAttributeDict({
154 155 'raw_id': 'raw_id',
155 156 'message': 'message',
156 157 'branch': 'branch',
157 158 })
158 159
159 160 comment = StrictAttributeDict({
160 161 'comment_id': 'comment_id',
161 162 'text': 'text',
162 163 'comment_type': 'comment_type',
163 164 'f_path': 'f_path',
164 165 'line_no': 'line_no',
165 166 'last_version': 0,
166 167 })
167 168 event = EventClass(repo=repo_stub, commit=commit, comment=comment)
168 169 data = event.as_dict()
169 170 assert data['commit']['commit_id']
170 171 assert data['comment']['comment_id']
@@ -1,981 +1,981 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
21 21 import mock
22 22 import pytest
23 23 import textwrap
24 24
25 25 import rhodecode
26 26 from rhodecode.lib.utils2 import safe_unicode
27 27 from rhodecode.lib.vcs.backends import get_backend
28 28 from rhodecode.lib.vcs.backends.base import (
29 29 MergeResponse, MergeFailureReason, Reference)
30 30 from rhodecode.lib.vcs.exceptions import RepositoryError
31 31 from rhodecode.lib.vcs.nodes import FileNode
32 32 from rhodecode.model.comment import CommentsModel
33 33 from rhodecode.model.db import PullRequest, Session
34 34 from rhodecode.model.pull_request import PullRequestModel
35 35 from rhodecode.model.user import UserModel
36 36 from rhodecode.tests import TEST_USER_ADMIN_LOGIN
37 37
38 38
39 39 pytestmark = [
40 40 pytest.mark.backends("git", "hg"),
41 41 ]
42 42
43 43
44 44 @pytest.mark.usefixtures('config_stub')
45 45 class TestPullRequestModel(object):
46 46
47 47 @pytest.fixture()
48 48 def pull_request(self, request, backend, pr_util):
49 49 """
50 50 A pull request combined with multiples patches.
51 51 """
52 52 BackendClass = get_backend(backend.alias)
53 53 merge_resp = MergeResponse(
54 54 False, False, None, MergeFailureReason.UNKNOWN,
55 55 metadata={'exception': 'MockError'})
56 56 self.merge_patcher = mock.patch.object(
57 57 BackendClass, 'merge', return_value=merge_resp)
58 58 self.workspace_remove_patcher = mock.patch.object(
59 59 BackendClass, 'cleanup_merge_workspace')
60 60
61 61 self.workspace_remove_mock = self.workspace_remove_patcher.start()
62 62 self.merge_mock = self.merge_patcher.start()
63 63 self.comment_patcher = mock.patch(
64 64 'rhodecode.model.changeset_status.ChangesetStatusModel.set_status')
65 65 self.comment_patcher.start()
66 66 self.notification_patcher = mock.patch(
67 67 'rhodecode.model.notification.NotificationModel.create')
68 68 self.notification_patcher.start()
69 69 self.helper_patcher = mock.patch(
70 70 'rhodecode.lib.helpers.route_path')
71 71 self.helper_patcher.start()
72 72
73 73 self.hook_patcher = mock.patch.object(PullRequestModel,
74 74 'trigger_pull_request_hook')
75 75 self.hook_mock = self.hook_patcher.start()
76 76
77 77 self.invalidation_patcher = mock.patch(
78 78 'rhodecode.model.pull_request.ScmModel.mark_for_invalidation')
79 79 self.invalidation_mock = self.invalidation_patcher.start()
80 80
81 81 self.pull_request = pr_util.create_pull_request(
82 82 mergeable=True, name_suffix=u'Δ…Δ‡')
83 83 self.source_commit = self.pull_request.source_ref_parts.commit_id
84 84 self.target_commit = self.pull_request.target_ref_parts.commit_id
85 85 self.workspace_id = 'pr-%s' % self.pull_request.pull_request_id
86 86 self.repo_id = self.pull_request.target_repo.repo_id
87 87
88 88 @request.addfinalizer
89 89 def cleanup_pull_request():
90 90 calls = [mock.call(
91 91 self.pull_request, self.pull_request.author, 'create')]
92 92 self.hook_mock.assert_has_calls(calls)
93 93
94 94 self.workspace_remove_patcher.stop()
95 95 self.merge_patcher.stop()
96 96 self.comment_patcher.stop()
97 97 self.notification_patcher.stop()
98 98 self.helper_patcher.stop()
99 99 self.hook_patcher.stop()
100 100 self.invalidation_patcher.stop()
101 101
102 102 return self.pull_request
103 103
104 104 def test_get_all(self, pull_request):
105 105 prs = PullRequestModel().get_all(pull_request.target_repo)
106 106 assert isinstance(prs, list)
107 107 assert len(prs) == 1
108 108
109 109 def test_count_all(self, pull_request):
110 110 pr_count = PullRequestModel().count_all(pull_request.target_repo)
111 111 assert pr_count == 1
112 112
113 113 def test_get_awaiting_review(self, pull_request):
114 114 prs = PullRequestModel().get_awaiting_review(pull_request.target_repo)
115 115 assert isinstance(prs, list)
116 116 assert len(prs) == 1
117 117
118 118 def test_count_awaiting_review(self, pull_request):
119 119 pr_count = PullRequestModel().count_awaiting_review(
120 120 pull_request.target_repo)
121 121 assert pr_count == 1
122 122
123 123 def test_get_awaiting_my_review(self, pull_request):
124 124 PullRequestModel().update_reviewers(
125 125 pull_request, [(pull_request.author, ['author'], False, 'reviewer', [])],
126 126 pull_request.author)
127 127 Session().commit()
128 128
129 129 prs = PullRequestModel().get_awaiting_my_review(
130 pull_request.target_repo, user_id=pull_request.author.user_id)
130 pull_request.target_repo.repo_name, user_id=pull_request.author.user_id)
131 131 assert isinstance(prs, list)
132 132 assert len(prs) == 1
133 133
134 134 def test_count_awaiting_my_review(self, pull_request):
135 135 PullRequestModel().update_reviewers(
136 136 pull_request, [(pull_request.author, ['author'], False, 'reviewer', [])],
137 137 pull_request.author)
138 138 Session().commit()
139 139
140 140 pr_count = PullRequestModel().count_awaiting_my_review(
141 pull_request.target_repo, user_id=pull_request.author.user_id)
141 pull_request.target_repo.repo_name, user_id=pull_request.author.user_id)
142 142 assert pr_count == 1
143 143
144 144 def test_delete_calls_cleanup_merge(self, pull_request):
145 145 repo_id = pull_request.target_repo.repo_id
146 146 PullRequestModel().delete(pull_request, pull_request.author)
147 147 Session().commit()
148 148
149 149 self.workspace_remove_mock.assert_called_once_with(
150 150 repo_id, self.workspace_id)
151 151
152 152 def test_close_calls_cleanup_and_hook(self, pull_request):
153 153 PullRequestModel().close_pull_request(
154 154 pull_request, pull_request.author)
155 155 Session().commit()
156 156
157 157 repo_id = pull_request.target_repo.repo_id
158 158
159 159 self.workspace_remove_mock.assert_called_once_with(
160 160 repo_id, self.workspace_id)
161 161 self.hook_mock.assert_called_with(
162 162 self.pull_request, self.pull_request.author, 'close')
163 163
164 164 def test_merge_status(self, pull_request):
165 165 self.merge_mock.return_value = MergeResponse(
166 166 True, False, None, MergeFailureReason.NONE)
167 167
168 168 assert pull_request._last_merge_source_rev is None
169 169 assert pull_request._last_merge_target_rev is None
170 170 assert pull_request.last_merge_status is None
171 171
172 172 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
173 173 assert status is True
174 174 assert msg == 'This pull request can be automatically merged.'
175 175 self.merge_mock.assert_called_with(
176 176 self.repo_id, self.workspace_id,
177 177 pull_request.target_ref_parts,
178 178 pull_request.source_repo.scm_instance(),
179 179 pull_request.source_ref_parts, dry_run=True,
180 180 use_rebase=False, close_branch=False)
181 181
182 182 assert pull_request._last_merge_source_rev == self.source_commit
183 183 assert pull_request._last_merge_target_rev == self.target_commit
184 184 assert pull_request.last_merge_status is MergeFailureReason.NONE
185 185
186 186 self.merge_mock.reset_mock()
187 187 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
188 188 assert status is True
189 189 assert msg == 'This pull request can be automatically merged.'
190 190 assert self.merge_mock.called is False
191 191
192 192 def test_merge_status_known_failure(self, pull_request):
193 193 self.merge_mock.return_value = MergeResponse(
194 194 False, False, None, MergeFailureReason.MERGE_FAILED,
195 195 metadata={'unresolved_files': 'file1'})
196 196
197 197 assert pull_request._last_merge_source_rev is None
198 198 assert pull_request._last_merge_target_rev is None
199 199 assert pull_request.last_merge_status is None
200 200
201 201 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
202 202 assert status is False
203 203 assert msg == 'This pull request cannot be merged because of merge conflicts. file1'
204 204 self.merge_mock.assert_called_with(
205 205 self.repo_id, self.workspace_id,
206 206 pull_request.target_ref_parts,
207 207 pull_request.source_repo.scm_instance(),
208 208 pull_request.source_ref_parts, dry_run=True,
209 209 use_rebase=False, close_branch=False)
210 210
211 211 assert pull_request._last_merge_source_rev == self.source_commit
212 212 assert pull_request._last_merge_target_rev == self.target_commit
213 213 assert pull_request.last_merge_status is MergeFailureReason.MERGE_FAILED
214 214
215 215 self.merge_mock.reset_mock()
216 216 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
217 217 assert status is False
218 218 assert msg == 'This pull request cannot be merged because of merge conflicts. file1'
219 219 assert self.merge_mock.called is False
220 220
221 221 def test_merge_status_unknown_failure(self, pull_request):
222 222 self.merge_mock.return_value = MergeResponse(
223 223 False, False, None, MergeFailureReason.UNKNOWN,
224 224 metadata={'exception': 'MockError'})
225 225
226 226 assert pull_request._last_merge_source_rev is None
227 227 assert pull_request._last_merge_target_rev is None
228 228 assert pull_request.last_merge_status is None
229 229
230 230 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
231 231 assert status is False
232 232 assert msg == (
233 233 'This pull request cannot be merged because of an unhandled exception. '
234 234 'MockError')
235 235 self.merge_mock.assert_called_with(
236 236 self.repo_id, self.workspace_id,
237 237 pull_request.target_ref_parts,
238 238 pull_request.source_repo.scm_instance(),
239 239 pull_request.source_ref_parts, dry_run=True,
240 240 use_rebase=False, close_branch=False)
241 241
242 242 assert pull_request._last_merge_source_rev is None
243 243 assert pull_request._last_merge_target_rev is None
244 244 assert pull_request.last_merge_status is None
245 245
246 246 self.merge_mock.reset_mock()
247 247 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
248 248 assert status is False
249 249 assert msg == (
250 250 'This pull request cannot be merged because of an unhandled exception. '
251 251 'MockError')
252 252 assert self.merge_mock.called is True
253 253
254 254 def test_merge_status_when_target_is_locked(self, pull_request):
255 255 pull_request.target_repo.locked = [1, u'12345.50', 'lock_web']
256 256 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
257 257 assert status is False
258 258 assert msg == (
259 259 'This pull request cannot be merged because the target repository '
260 260 'is locked by user:1.')
261 261
262 262 def test_merge_status_requirements_check_target(self, pull_request):
263 263
264 264 def has_largefiles(self, repo):
265 265 return repo == pull_request.source_repo
266 266
267 267 patcher = mock.patch.object(PullRequestModel, '_has_largefiles', has_largefiles)
268 268 with patcher:
269 269 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
270 270
271 271 assert status is False
272 272 assert msg == 'Target repository large files support is disabled.'
273 273
274 274 def test_merge_status_requirements_check_source(self, pull_request):
275 275
276 276 def has_largefiles(self, repo):
277 277 return repo == pull_request.target_repo
278 278
279 279 patcher = mock.patch.object(PullRequestModel, '_has_largefiles', has_largefiles)
280 280 with patcher:
281 281 merge_response, status, msg = PullRequestModel().merge_status(pull_request)
282 282
283 283 assert status is False
284 284 assert msg == 'Source repository large files support is disabled.'
285 285
286 286 def test_merge(self, pull_request, merge_extras):
287 287 user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
288 288 merge_ref = Reference(
289 289 'type', 'name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
290 290 self.merge_mock.return_value = MergeResponse(
291 291 True, True, merge_ref, MergeFailureReason.NONE)
292 292
293 293 merge_extras['repository'] = pull_request.target_repo.repo_name
294 294 PullRequestModel().merge_repo(
295 295 pull_request, pull_request.author, extras=merge_extras)
296 296 Session().commit()
297 297
298 298 message = (
299 299 u'Merge pull request !{pr_id} from {source_repo} {source_ref_name}'
300 300 u'\n\n {pr_title}'.format(
301 301 pr_id=pull_request.pull_request_id,
302 302 source_repo=safe_unicode(
303 303 pull_request.source_repo.scm_instance().name),
304 304 source_ref_name=pull_request.source_ref_parts.name,
305 305 pr_title=safe_unicode(pull_request.title)
306 306 )
307 307 )
308 308 self.merge_mock.assert_called_with(
309 309 self.repo_id, self.workspace_id,
310 310 pull_request.target_ref_parts,
311 311 pull_request.source_repo.scm_instance(),
312 312 pull_request.source_ref_parts,
313 313 user_name=user.short_contact, user_email=user.email, message=message,
314 314 use_rebase=False, close_branch=False
315 315 )
316 316 self.invalidation_mock.assert_called_once_with(
317 317 pull_request.target_repo.repo_name)
318 318
319 319 self.hook_mock.assert_called_with(
320 320 self.pull_request, self.pull_request.author, 'merge')
321 321
322 322 pull_request = PullRequest.get(pull_request.pull_request_id)
323 323 assert pull_request.merge_rev == '6126b7bfcc82ad2d3deaee22af926b082ce54cc6'
324 324
325 325 def test_merge_with_status_lock(self, pull_request, merge_extras):
326 326 user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
327 327 merge_ref = Reference(
328 328 'type', 'name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
329 329 self.merge_mock.return_value = MergeResponse(
330 330 True, True, merge_ref, MergeFailureReason.NONE)
331 331
332 332 merge_extras['repository'] = pull_request.target_repo.repo_name
333 333
334 334 with pull_request.set_state(PullRequest.STATE_UPDATING):
335 335 assert pull_request.pull_request_state == PullRequest.STATE_UPDATING
336 336 PullRequestModel().merge_repo(
337 337 pull_request, pull_request.author, extras=merge_extras)
338 338 Session().commit()
339 339
340 340 assert pull_request.pull_request_state == PullRequest.STATE_CREATED
341 341
342 342 message = (
343 343 u'Merge pull request !{pr_id} from {source_repo} {source_ref_name}'
344 344 u'\n\n {pr_title}'.format(
345 345 pr_id=pull_request.pull_request_id,
346 346 source_repo=safe_unicode(
347 347 pull_request.source_repo.scm_instance().name),
348 348 source_ref_name=pull_request.source_ref_parts.name,
349 349 pr_title=safe_unicode(pull_request.title)
350 350 )
351 351 )
352 352 self.merge_mock.assert_called_with(
353 353 self.repo_id, self.workspace_id,
354 354 pull_request.target_ref_parts,
355 355 pull_request.source_repo.scm_instance(),
356 356 pull_request.source_ref_parts,
357 357 user_name=user.short_contact, user_email=user.email, message=message,
358 358 use_rebase=False, close_branch=False
359 359 )
360 360 self.invalidation_mock.assert_called_once_with(
361 361 pull_request.target_repo.repo_name)
362 362
363 363 self.hook_mock.assert_called_with(
364 364 self.pull_request, self.pull_request.author, 'merge')
365 365
366 366 pull_request = PullRequest.get(pull_request.pull_request_id)
367 367 assert pull_request.merge_rev == '6126b7bfcc82ad2d3deaee22af926b082ce54cc6'
368 368
369 369 def test_merge_failed(self, pull_request, merge_extras):
370 370 user = UserModel().get_by_username(TEST_USER_ADMIN_LOGIN)
371 371 merge_ref = Reference(
372 372 'type', 'name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
373 373 self.merge_mock.return_value = MergeResponse(
374 374 False, False, merge_ref, MergeFailureReason.MERGE_FAILED)
375 375
376 376 merge_extras['repository'] = pull_request.target_repo.repo_name
377 377 PullRequestModel().merge_repo(
378 378 pull_request, pull_request.author, extras=merge_extras)
379 379 Session().commit()
380 380
381 381 message = (
382 382 u'Merge pull request !{pr_id} from {source_repo} {source_ref_name}'
383 383 u'\n\n {pr_title}'.format(
384 384 pr_id=pull_request.pull_request_id,
385 385 source_repo=safe_unicode(
386 386 pull_request.source_repo.scm_instance().name),
387 387 source_ref_name=pull_request.source_ref_parts.name,
388 388 pr_title=safe_unicode(pull_request.title)
389 389 )
390 390 )
391 391 self.merge_mock.assert_called_with(
392 392 self.repo_id, self.workspace_id,
393 393 pull_request.target_ref_parts,
394 394 pull_request.source_repo.scm_instance(),
395 395 pull_request.source_ref_parts,
396 396 user_name=user.short_contact, user_email=user.email, message=message,
397 397 use_rebase=False, close_branch=False
398 398 )
399 399
400 400 pull_request = PullRequest.get(pull_request.pull_request_id)
401 401 assert self.invalidation_mock.called is False
402 402 assert pull_request.merge_rev is None
403 403
404 404 def test_get_commit_ids(self, pull_request):
405 405 # The PR has been not merged yet, so expect an exception
406 406 with pytest.raises(ValueError):
407 407 PullRequestModel()._get_commit_ids(pull_request)
408 408
409 409 # Merge revision is in the revisions list
410 410 pull_request.merge_rev = pull_request.revisions[0]
411 411 commit_ids = PullRequestModel()._get_commit_ids(pull_request)
412 412 assert commit_ids == pull_request.revisions
413 413
414 414 # Merge revision is not in the revisions list
415 415 pull_request.merge_rev = 'f000' * 10
416 416 commit_ids = PullRequestModel()._get_commit_ids(pull_request)
417 417 assert commit_ids == pull_request.revisions + [pull_request.merge_rev]
418 418
419 419 def test_get_diff_from_pr_version(self, pull_request):
420 420 source_repo = pull_request.source_repo
421 421 source_ref_id = pull_request.source_ref_parts.commit_id
422 422 target_ref_id = pull_request.target_ref_parts.commit_id
423 423 diff = PullRequestModel()._get_diff_from_pr_or_version(
424 424 source_repo, source_ref_id, target_ref_id,
425 425 hide_whitespace_changes=False, diff_context=6)
426 426 assert 'file_1' in diff.raw
427 427
428 428 def test_generate_title_returns_unicode(self):
429 429 title = PullRequestModel().generate_pullrequest_title(
430 430 source='source-dummy',
431 431 source_ref='source-ref-dummy',
432 432 target='target-dummy',
433 433 )
434 434 assert type(title) == unicode
435 435
436 436 @pytest.mark.parametrize('title, has_wip', [
437 437 ('hello', False),
438 438 ('hello wip', False),
439 439 ('hello wip: xxx', False),
440 440 ('[wip] hello', True),
441 441 ('[wip] hello', True),
442 442 ('wip: hello', True),
443 443 ('wip hello', True),
444 444
445 445 ])
446 446 def test_wip_title_marker(self, pull_request, title, has_wip):
447 447 pull_request.title = title
448 448 assert pull_request.work_in_progress == has_wip
449 449
450 450
451 451 @pytest.mark.usefixtures('config_stub')
452 452 class TestIntegrationMerge(object):
453 453 @pytest.mark.parametrize('extra_config', (
454 454 {'vcs.hooks.protocol': 'http', 'vcs.hooks.direct_calls': False},
455 455 ))
456 456 def test_merge_triggers_push_hooks(
457 457 self, pr_util, user_admin, capture_rcextensions, merge_extras,
458 458 extra_config):
459 459
460 460 pull_request = pr_util.create_pull_request(
461 461 approved=True, mergeable=True)
462 462 # TODO: johbo: Needed for sqlite, try to find an automatic way for it
463 463 merge_extras['repository'] = pull_request.target_repo.repo_name
464 464 Session().commit()
465 465
466 466 with mock.patch.dict(rhodecode.CONFIG, extra_config, clear=False):
467 467 merge_state = PullRequestModel().merge_repo(
468 468 pull_request, user_admin, extras=merge_extras)
469 469 Session().commit()
470 470
471 471 assert merge_state.executed
472 472 assert '_pre_push_hook' in capture_rcextensions
473 473 assert '_push_hook' in capture_rcextensions
474 474
475 475 def test_merge_can_be_rejected_by_pre_push_hook(
476 476 self, pr_util, user_admin, capture_rcextensions, merge_extras):
477 477 pull_request = pr_util.create_pull_request(
478 478 approved=True, mergeable=True)
479 479 # TODO: johbo: Needed for sqlite, try to find an automatic way for it
480 480 merge_extras['repository'] = pull_request.target_repo.repo_name
481 481 Session().commit()
482 482
483 483 with mock.patch('rhodecode.EXTENSIONS.PRE_PUSH_HOOK') as pre_pull:
484 484 pre_pull.side_effect = RepositoryError("Disallow push!")
485 485 merge_status = PullRequestModel().merge_repo(
486 486 pull_request, user_admin, extras=merge_extras)
487 487 Session().commit()
488 488
489 489 assert not merge_status.executed
490 490 assert 'pre_push' not in capture_rcextensions
491 491 assert 'post_push' not in capture_rcextensions
492 492
493 493 def test_merge_fails_if_target_is_locked(
494 494 self, pr_util, user_regular, merge_extras):
495 495 pull_request = pr_util.create_pull_request(
496 496 approved=True, mergeable=True)
497 497 locked_by = [user_regular.user_id + 1, 12345.50, 'lock_web']
498 498 pull_request.target_repo.locked = locked_by
499 499 # TODO: johbo: Check if this can work based on the database, currently
500 500 # all data is pre-computed, that's why just updating the DB is not
501 501 # enough.
502 502 merge_extras['locked_by'] = locked_by
503 503 merge_extras['repository'] = pull_request.target_repo.repo_name
504 504 # TODO: johbo: Needed for sqlite, try to find an automatic way for it
505 505 Session().commit()
506 506 merge_status = PullRequestModel().merge_repo(
507 507 pull_request, user_regular, extras=merge_extras)
508 508 Session().commit()
509 509
510 510 assert not merge_status.executed
511 511
512 512
513 513 @pytest.mark.parametrize('use_outdated, inlines_count, outdated_count', [
514 514 (False, 1, 0),
515 515 (True, 0, 1),
516 516 ])
517 517 def test_outdated_comments(
518 518 pr_util, use_outdated, inlines_count, outdated_count, config_stub):
519 519 pull_request = pr_util.create_pull_request()
520 520 pr_util.create_inline_comment(file_path='not_in_updated_diff')
521 521
522 522 with outdated_comments_patcher(use_outdated) as outdated_comment_mock:
523 523 pr_util.add_one_commit()
524 524 assert_inline_comments(
525 525 pull_request, visible=inlines_count, outdated=outdated_count)
526 526 outdated_comment_mock.assert_called_with(pull_request)
527 527
528 528
529 529 @pytest.mark.parametrize('mr_type, expected_msg', [
530 530 (MergeFailureReason.NONE,
531 531 'This pull request can be automatically merged.'),
532 532 (MergeFailureReason.UNKNOWN,
533 533 'This pull request cannot be merged because of an unhandled exception. CRASH'),
534 534 (MergeFailureReason.MERGE_FAILED,
535 535 'This pull request cannot be merged because of merge conflicts. CONFLICT_FILE'),
536 536 (MergeFailureReason.PUSH_FAILED,
537 537 'This pull request could not be merged because push to target:`some-repo@merge_commit` failed.'),
538 538 (MergeFailureReason.TARGET_IS_NOT_HEAD,
539 539 'This pull request cannot be merged because the target `ref_name` is not a head.'),
540 540 (MergeFailureReason.HG_SOURCE_HAS_MORE_BRANCHES,
541 541 'This pull request cannot be merged because the source contains more branches than the target.'),
542 542 (MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS,
543 543 'This pull request cannot be merged because the target `ref_name` has multiple heads: `a,b,c`.'),
544 544 (MergeFailureReason.TARGET_IS_LOCKED,
545 545 'This pull request cannot be merged because the target repository is locked by user:123.'),
546 546 (MergeFailureReason.MISSING_TARGET_REF,
547 547 'This pull request cannot be merged because the target reference `ref_name` is missing.'),
548 548 (MergeFailureReason.MISSING_SOURCE_REF,
549 549 'This pull request cannot be merged because the source reference `ref_name` is missing.'),
550 550 (MergeFailureReason.SUBREPO_MERGE_FAILED,
551 551 'This pull request cannot be merged because of conflicts related to sub repositories.'),
552 552
553 553 ])
554 554 def test_merge_response_message(mr_type, expected_msg):
555 555 merge_ref = Reference('type', 'ref_name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
556 556 metadata = {
557 557 'unresolved_files': 'CONFLICT_FILE',
558 558 'exception': "CRASH",
559 559 'target': 'some-repo',
560 560 'merge_commit': 'merge_commit',
561 561 'target_ref': merge_ref,
562 562 'source_ref': merge_ref,
563 563 'heads': ','.join(['a', 'b', 'c']),
564 564 'locked_by': 'user:123'
565 565 }
566 566
567 567 merge_response = MergeResponse(True, True, merge_ref, mr_type, metadata=metadata)
568 568 assert merge_response.merge_status_message == expected_msg
569 569
570 570
571 571 @pytest.fixture()
572 572 def merge_extras(user_regular):
573 573 """
574 574 Context for the vcs operation when running a merge.
575 575 """
576 576 extras = {
577 577 'ip': '127.0.0.1',
578 578 'username': user_regular.username,
579 579 'user_id': user_regular.user_id,
580 580 'action': 'push',
581 581 'repository': 'fake_target_repo_name',
582 582 'scm': 'git',
583 583 'config': 'fake_config_ini_path',
584 584 'repo_store': '',
585 585 'make_lock': None,
586 586 'locked_by': [None, None, None],
587 587 'server_url': 'http://test.example.com:5000',
588 588 'hooks': ['push', 'pull'],
589 589 'is_shadow_repo': False,
590 590 }
591 591 return extras
592 592
593 593
594 594 @pytest.mark.usefixtures('config_stub')
595 595 class TestUpdateCommentHandling(object):
596 596
597 597 @pytest.fixture(autouse=True, scope='class')
598 598 def enable_outdated_comments(self, request, baseapp):
599 599 config_patch = mock.patch.dict(
600 600 'rhodecode.CONFIG', {'rhodecode_use_outdated_comments': True})
601 601 config_patch.start()
602 602
603 603 @request.addfinalizer
604 604 def cleanup():
605 605 config_patch.stop()
606 606
607 607 def test_comment_stays_unflagged_on_unchanged_diff(self, pr_util):
608 608 commits = [
609 609 {'message': 'a'},
610 610 {'message': 'b', 'added': [FileNode('file_b', 'test_content\n')]},
611 611 {'message': 'c', 'added': [FileNode('file_c', 'test_content\n')]},
612 612 ]
613 613 pull_request = pr_util.create_pull_request(
614 614 commits=commits, target_head='a', source_head='b', revisions=['b'])
615 615 pr_util.create_inline_comment(file_path='file_b')
616 616 pr_util.add_one_commit(head='c')
617 617
618 618 assert_inline_comments(pull_request, visible=1, outdated=0)
619 619
620 620 def test_comment_stays_unflagged_on_change_above(self, pr_util):
621 621 original_content = ''.join(
622 622 ['line {}\n'.format(x) for x in range(1, 11)])
623 623 updated_content = 'new_line_at_top\n' + original_content
624 624 commits = [
625 625 {'message': 'a'},
626 626 {'message': 'b', 'added': [FileNode('file_b', original_content)]},
627 627 {'message': 'c', 'changed': [FileNode('file_b', updated_content)]},
628 628 ]
629 629 pull_request = pr_util.create_pull_request(
630 630 commits=commits, target_head='a', source_head='b', revisions=['b'])
631 631
632 632 with outdated_comments_patcher():
633 633 comment = pr_util.create_inline_comment(
634 634 line_no=u'n8', file_path='file_b')
635 635 pr_util.add_one_commit(head='c')
636 636
637 637 assert_inline_comments(pull_request, visible=1, outdated=0)
638 638 assert comment.line_no == u'n9'
639 639
640 640 def test_comment_stays_unflagged_on_change_below(self, pr_util):
641 641 original_content = ''.join(['line {}\n'.format(x) for x in range(10)])
642 642 updated_content = original_content + 'new_line_at_end\n'
643 643 commits = [
644 644 {'message': 'a'},
645 645 {'message': 'b', 'added': [FileNode('file_b', original_content)]},
646 646 {'message': 'c', 'changed': [FileNode('file_b', updated_content)]},
647 647 ]
648 648 pull_request = pr_util.create_pull_request(
649 649 commits=commits, target_head='a', source_head='b', revisions=['b'])
650 650 pr_util.create_inline_comment(file_path='file_b')
651 651 pr_util.add_one_commit(head='c')
652 652
653 653 assert_inline_comments(pull_request, visible=1, outdated=0)
654 654
655 655 @pytest.mark.parametrize('line_no', ['n4', 'o4', 'n10', 'o9'])
656 656 def test_comment_flagged_on_change_around_context(self, pr_util, line_no):
657 657 base_lines = ['line {}\n'.format(x) for x in range(1, 13)]
658 658 change_lines = list(base_lines)
659 659 change_lines.insert(6, 'line 6a added\n')
660 660
661 661 # Changes on the last line of sight
662 662 update_lines = list(change_lines)
663 663 update_lines[0] = 'line 1 changed\n'
664 664 update_lines[-1] = 'line 12 changed\n'
665 665
666 666 def file_b(lines):
667 667 return FileNode('file_b', ''.join(lines))
668 668
669 669 commits = [
670 670 {'message': 'a', 'added': [file_b(base_lines)]},
671 671 {'message': 'b', 'changed': [file_b(change_lines)]},
672 672 {'message': 'c', 'changed': [file_b(update_lines)]},
673 673 ]
674 674
675 675 pull_request = pr_util.create_pull_request(
676 676 commits=commits, target_head='a', source_head='b', revisions=['b'])
677 677 pr_util.create_inline_comment(line_no=line_no, file_path='file_b')
678 678
679 679 with outdated_comments_patcher():
680 680 pr_util.add_one_commit(head='c')
681 681 assert_inline_comments(pull_request, visible=0, outdated=1)
682 682
683 683 @pytest.mark.parametrize("change, content", [
684 684 ('changed', 'changed\n'),
685 685 ('removed', ''),
686 686 ], ids=['changed', 'removed'])
687 687 def test_comment_flagged_on_change(self, pr_util, change, content):
688 688 commits = [
689 689 {'message': 'a'},
690 690 {'message': 'b', 'added': [FileNode('file_b', 'test_content\n')]},
691 691 {'message': 'c', change: [FileNode('file_b', content)]},
692 692 ]
693 693 pull_request = pr_util.create_pull_request(
694 694 commits=commits, target_head='a', source_head='b', revisions=['b'])
695 695 pr_util.create_inline_comment(file_path='file_b')
696 696
697 697 with outdated_comments_patcher():
698 698 pr_util.add_one_commit(head='c')
699 699 assert_inline_comments(pull_request, visible=0, outdated=1)
700 700
701 701
702 702 @pytest.mark.usefixtures('config_stub')
703 703 class TestUpdateChangedFiles(object):
704 704
705 705 def test_no_changes_on_unchanged_diff(self, pr_util):
706 706 commits = [
707 707 {'message': 'a'},
708 708 {'message': 'b',
709 709 'added': [FileNode('file_b', 'test_content b\n')]},
710 710 {'message': 'c',
711 711 'added': [FileNode('file_c', 'test_content c\n')]},
712 712 ]
713 713 # open a PR from a to b, adding file_b
714 714 pull_request = pr_util.create_pull_request(
715 715 commits=commits, target_head='a', source_head='b', revisions=['b'],
716 716 name_suffix='per-file-review')
717 717
718 718 # modify PR adding new file file_c
719 719 pr_util.add_one_commit(head='c')
720 720
721 721 assert_pr_file_changes(
722 722 pull_request,
723 723 added=['file_c'],
724 724 modified=[],
725 725 removed=[])
726 726
727 727 def test_modify_and_undo_modification_diff(self, pr_util):
728 728 commits = [
729 729 {'message': 'a'},
730 730 {'message': 'b',
731 731 'added': [FileNode('file_b', 'test_content b\n')]},
732 732 {'message': 'c',
733 733 'changed': [FileNode('file_b', 'test_content b modified\n')]},
734 734 {'message': 'd',
735 735 'changed': [FileNode('file_b', 'test_content b\n')]},
736 736 ]
737 737 # open a PR from a to b, adding file_b
738 738 pull_request = pr_util.create_pull_request(
739 739 commits=commits, target_head='a', source_head='b', revisions=['b'],
740 740 name_suffix='per-file-review')
741 741
742 742 # modify PR modifying file file_b
743 743 pr_util.add_one_commit(head='c')
744 744
745 745 assert_pr_file_changes(
746 746 pull_request,
747 747 added=[],
748 748 modified=['file_b'],
749 749 removed=[])
750 750
751 751 # move the head again to d, which rollbacks change,
752 752 # meaning we should indicate no changes
753 753 pr_util.add_one_commit(head='d')
754 754
755 755 assert_pr_file_changes(
756 756 pull_request,
757 757 added=[],
758 758 modified=[],
759 759 removed=[])
760 760
761 761 def test_updated_all_files_in_pr(self, pr_util):
762 762 commits = [
763 763 {'message': 'a'},
764 764 {'message': 'b', 'added': [
765 765 FileNode('file_a', 'test_content a\n'),
766 766 FileNode('file_b', 'test_content b\n'),
767 767 FileNode('file_c', 'test_content c\n')]},
768 768 {'message': 'c', 'changed': [
769 769 FileNode('file_a', 'test_content a changed\n'),
770 770 FileNode('file_b', 'test_content b changed\n'),
771 771 FileNode('file_c', 'test_content c changed\n')]},
772 772 ]
773 773 # open a PR from a to b, changing 3 files
774 774 pull_request = pr_util.create_pull_request(
775 775 commits=commits, target_head='a', source_head='b', revisions=['b'],
776 776 name_suffix='per-file-review')
777 777
778 778 pr_util.add_one_commit(head='c')
779 779
780 780 assert_pr_file_changes(
781 781 pull_request,
782 782 added=[],
783 783 modified=['file_a', 'file_b', 'file_c'],
784 784 removed=[])
785 785
786 786 def test_updated_and_removed_all_files_in_pr(self, pr_util):
787 787 commits = [
788 788 {'message': 'a'},
789 789 {'message': 'b', 'added': [
790 790 FileNode('file_a', 'test_content a\n'),
791 791 FileNode('file_b', 'test_content b\n'),
792 792 FileNode('file_c', 'test_content c\n')]},
793 793 {'message': 'c', 'removed': [
794 794 FileNode('file_a', 'test_content a changed\n'),
795 795 FileNode('file_b', 'test_content b changed\n'),
796 796 FileNode('file_c', 'test_content c changed\n')]},
797 797 ]
798 798 # open a PR from a to b, removing 3 files
799 799 pull_request = pr_util.create_pull_request(
800 800 commits=commits, target_head='a', source_head='b', revisions=['b'],
801 801 name_suffix='per-file-review')
802 802
803 803 pr_util.add_one_commit(head='c')
804 804
805 805 assert_pr_file_changes(
806 806 pull_request,
807 807 added=[],
808 808 modified=[],
809 809 removed=['file_a', 'file_b', 'file_c'])
810 810
811 811
812 812 def test_update_writes_snapshot_into_pull_request_version(pr_util, config_stub):
813 813 model = PullRequestModel()
814 814 pull_request = pr_util.create_pull_request()
815 815 pr_util.update_source_repository()
816 816
817 817 model.update_commits(pull_request, pull_request.author)
818 818
819 819 # Expect that it has a version entry now
820 820 assert len(model.get_versions(pull_request)) == 1
821 821
822 822
823 823 def test_update_skips_new_version_if_unchanged(pr_util, config_stub):
824 824 pull_request = pr_util.create_pull_request()
825 825 model = PullRequestModel()
826 826 model.update_commits(pull_request, pull_request.author)
827 827
828 828 # Expect that it still has no versions
829 829 assert len(model.get_versions(pull_request)) == 0
830 830
831 831
832 832 def test_update_assigns_comments_to_the_new_version(pr_util, config_stub):
833 833 model = PullRequestModel()
834 834 pull_request = pr_util.create_pull_request()
835 835 comment = pr_util.create_comment()
836 836 pr_util.update_source_repository()
837 837
838 838 model.update_commits(pull_request, pull_request.author)
839 839
840 840 # Expect that the comment is linked to the pr version now
841 841 assert comment.pull_request_version == model.get_versions(pull_request)[0]
842 842
843 843
844 844 def test_update_adds_a_comment_to_the_pull_request_about_the_change(pr_util, config_stub):
845 845 model = PullRequestModel()
846 846 pull_request = pr_util.create_pull_request()
847 847 pr_util.update_source_repository()
848 848 pr_util.update_source_repository()
849 849
850 850 update_response = model.update_commits(pull_request, pull_request.author)
851 851
852 852 commit_id = update_response.common_ancestor_id
853 853 # Expect to find a new comment about the change
854 854 expected_message = textwrap.dedent(
855 855 """\
856 856 Pull request updated. Auto status change to |under_review|
857 857
858 858 .. role:: added
859 859 .. role:: removed
860 860 .. parsed-literal::
861 861
862 862 Changed commits:
863 863 * :added:`1 added`
864 864 * :removed:`0 removed`
865 865
866 866 Changed files:
867 867 * `A file_2 <#a_c-{}-92ed3b5f07b4>`_
868 868
869 869 .. |under_review| replace:: *"Under Review"*"""
870 870 ).format(commit_id[:12])
871 871 pull_request_comments = sorted(
872 872 pull_request.comments, key=lambda c: c.modified_at)
873 873 update_comment = pull_request_comments[-1]
874 874 assert update_comment.text == expected_message
875 875
876 876
877 877 def test_create_version_from_snapshot_updates_attributes(pr_util, config_stub):
878 878 pull_request = pr_util.create_pull_request()
879 879
880 880 # Avoiding default values
881 881 pull_request.status = PullRequest.STATUS_CLOSED
882 882 pull_request._last_merge_source_rev = "0" * 40
883 883 pull_request._last_merge_target_rev = "1" * 40
884 884 pull_request.last_merge_status = 1
885 885 pull_request.merge_rev = "2" * 40
886 886
887 887 # Remember automatic values
888 888 created_on = pull_request.created_on
889 889 updated_on = pull_request.updated_on
890 890
891 891 # Create a new version of the pull request
892 892 version = PullRequestModel()._create_version_from_snapshot(pull_request)
893 893
894 894 # Check attributes
895 895 assert version.title == pr_util.create_parameters['title']
896 896 assert version.description == pr_util.create_parameters['description']
897 897 assert version.status == PullRequest.STATUS_CLOSED
898 898
899 899 # versions get updated created_on
900 900 assert version.created_on != created_on
901 901
902 902 assert version.updated_on == updated_on
903 903 assert version.user_id == pull_request.user_id
904 904 assert version.revisions == pr_util.create_parameters['revisions']
905 905 assert version.source_repo == pr_util.source_repository
906 906 assert version.source_ref == pr_util.create_parameters['source_ref']
907 907 assert version.target_repo == pr_util.target_repository
908 908 assert version.target_ref == pr_util.create_parameters['target_ref']
909 909 assert version._last_merge_source_rev == pull_request._last_merge_source_rev
910 910 assert version._last_merge_target_rev == pull_request._last_merge_target_rev
911 911 assert version.last_merge_status == pull_request.last_merge_status
912 912 assert version.merge_rev == pull_request.merge_rev
913 913 assert version.pull_request == pull_request
914 914
915 915
916 916 def test_link_comments_to_version_only_updates_unlinked_comments(pr_util, config_stub):
917 917 version1 = pr_util.create_version_of_pull_request()
918 918 comment_linked = pr_util.create_comment(linked_to=version1)
919 919 comment_unlinked = pr_util.create_comment()
920 920 version2 = pr_util.create_version_of_pull_request()
921 921
922 922 PullRequestModel()._link_comments_to_version(version2)
923 923 Session().commit()
924 924
925 925 # Expect that only the new comment is linked to version2
926 926 assert (
927 927 comment_unlinked.pull_request_version_id ==
928 928 version2.pull_request_version_id)
929 929 assert (
930 930 comment_linked.pull_request_version_id ==
931 931 version1.pull_request_version_id)
932 932 assert (
933 933 comment_unlinked.pull_request_version_id !=
934 934 comment_linked.pull_request_version_id)
935 935
936 936
937 937 def test_calculate_commits():
938 938 old_ids = [1, 2, 3]
939 939 new_ids = [1, 3, 4, 5]
940 940 change = PullRequestModel()._calculate_commit_id_changes(old_ids, new_ids)
941 941 assert change.added == [4, 5]
942 942 assert change.common == [1, 3]
943 943 assert change.removed == [2]
944 944 assert change.total == [1, 3, 4, 5]
945 945
946 946
947 947 def assert_inline_comments(pull_request, visible=None, outdated=None):
948 948 if visible is not None:
949 949 inline_comments = CommentsModel().get_inline_comments(
950 950 pull_request.target_repo.repo_id, pull_request=pull_request)
951 951 inline_cnt = len(CommentsModel().get_inline_comments_as_list(
952 952 inline_comments))
953 953 assert inline_cnt == visible
954 954 if outdated is not None:
955 955 outdated_comments = CommentsModel().get_outdated_comments(
956 956 pull_request.target_repo.repo_id, pull_request)
957 957 assert len(outdated_comments) == outdated
958 958
959 959
960 960 def assert_pr_file_changes(
961 961 pull_request, added=None, modified=None, removed=None):
962 962 pr_versions = PullRequestModel().get_versions(pull_request)
963 963 # always use first version, ie original PR to calculate changes
964 964 pull_request_version = pr_versions[0]
965 965 old_diff_data, new_diff_data = PullRequestModel()._generate_update_diffs(
966 966 pull_request, pull_request_version)
967 967 file_changes = PullRequestModel()._calculate_file_changes(
968 968 old_diff_data, new_diff_data)
969 969
970 970 assert added == file_changes.added, \
971 971 'expected added:%s vs value:%s' % (added, file_changes.added)
972 972 assert modified == file_changes.modified, \
973 973 'expected modified:%s vs value:%s' % (modified, file_changes.modified)
974 974 assert removed == file_changes.removed, \
975 975 'expected removed:%s vs value:%s' % (removed, file_changes.removed)
976 976
977 977
978 978 def outdated_comments_patcher(use_outdated=True):
979 979 return mock.patch.object(
980 980 CommentsModel, 'use_outdated_comments',
981 981 return_value=use_outdated)
General Comments 0
You need to be logged in to leave comments. Login now