##// END OF EJS Templates
tests: functional tests for diff 2 way
lisaq -
r622:79a1b51c default
parent child Browse files
Show More
@@ -1,942 +1,1078 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22
23 23 import mock
24 24 import pytest
25 25
26 26 from rhodecode.controllers.files import FilesController
27 27 from rhodecode.lib import helpers as h
28 28 from rhodecode.lib.compat import OrderedDict
29 29 from rhodecode.lib.ext_json import json
30 30 from rhodecode.lib.vcs import nodes
31 from rhodecode.lib.vcs.backends.base import EmptyCommit
31 32 from rhodecode.lib.vcs.conf import settings
33 from rhodecode.lib.vcs.nodes import FileNode
34 from rhodecode.model.db import Repository
35 from rhodecode.model.scm import ScmModel
32 36 from rhodecode.tests import (
33 url, assert_session_flash, assert_not_in_session_flash)
37 url, TEST_USER_ADMIN_LOGIN, assert_session_flash, assert_not_in_session_flash)
34 38 from rhodecode.tests.fixture import Fixture
35 39 from rhodecode.tests.utils import AssertResponse
36 40
37 41 fixture = Fixture()
38 42
39 43 NODE_HISTORY = {
40 44 'hg': json.loads(fixture.load_resource('hg_node_history_response.json')),
41 45 'git': json.loads(fixture.load_resource('git_node_history_response.json')),
42 46 'svn': json.loads(fixture.load_resource('svn_node_history_response.json')),
43 47 }
44 48
45 49
50
51 def _commit_change(
52 repo, filename, content, message, vcs_type, parent=None,
53 newfile=False):
54 repo = Repository.get_by_repo_name(repo)
55 _commit = parent
56 if not parent:
57 _commit = EmptyCommit(alias=vcs_type)
58
59 if newfile:
60 nodes = {
61 filename: {
62 'content': content
63 }
64 }
65 commit = ScmModel().create_nodes(
66 user=TEST_USER_ADMIN_LOGIN, repo=repo,
67 message=message,
68 nodes=nodes,
69 parent_commit=_commit,
70 author=TEST_USER_ADMIN_LOGIN,
71 )
72 else:
73 commit = ScmModel().commit_change(
74 repo=repo.scm_instance(), repo_name=repo.repo_name,
75 commit=parent, user=TEST_USER_ADMIN_LOGIN,
76 author=TEST_USER_ADMIN_LOGIN,
77 message=message,
78 content=content,
79 f_path=filename
80 )
81 return commit
82
83
84
46 85 @pytest.mark.usefixtures("app")
47 86 class TestFilesController:
48 87
49 88 def test_index(self, backend):
50 89 response = self.app.get(url(
51 90 controller='files', action='index',
52 91 repo_name=backend.repo_name, revision='tip', f_path='/'))
53 92 commit = backend.repo.get_commit()
54 93
55 94 params = {
56 95 'repo_name': backend.repo_name,
57 96 'commit_id': commit.raw_id,
58 97 'date': commit.date
59 98 }
60 99 assert_dirs_in_response(response, ['docs', 'vcs'], params)
61 100 files = [
62 101 '.gitignore',
63 102 '.hgignore',
64 103 '.hgtags',
65 104 # TODO: missing in Git
66 105 # '.travis.yml',
67 106 'MANIFEST.in',
68 107 'README.rst',
69 108 # TODO: File is missing in svn repository
70 109 # 'run_test_and_report.sh',
71 110 'setup.cfg',
72 111 'setup.py',
73 112 'test_and_report.sh',
74 113 'tox.ini',
75 114 ]
76 115 assert_files_in_response(response, files, params)
77 116 assert_timeago_in_response(response, files, params)
78 117
79 118 def test_index_links_submodules_with_absolute_url(self, backend_hg):
80 119 repo = backend_hg['subrepos']
81 120 response = self.app.get(url(
82 121 controller='files', action='index',
83 122 repo_name=repo.repo_name, revision='tip', f_path='/'))
84 123 assert_response = AssertResponse(response)
85 124 assert_response.contains_one_link(
86 125 'absolute-path @ 000000000000', 'http://example.com/absolute-path')
87 126
88 127 def test_index_links_submodules_with_absolute_url_subpaths(
89 128 self, backend_hg):
90 129 repo = backend_hg['subrepos']
91 130 response = self.app.get(url(
92 131 controller='files', action='index',
93 132 repo_name=repo.repo_name, revision='tip', f_path='/'))
94 133 assert_response = AssertResponse(response)
95 134 assert_response.contains_one_link(
96 135 'subpaths-path @ 000000000000',
97 136 'http://sub-base.example.com/subpaths-path')
98 137
99 138 @pytest.mark.xfail_backends("svn", reason="Depends on branch support")
100 139 def test_files_menu(self, backend):
101 140 new_branch = "temp_branch_name"
102 141 commits = [
103 142 {'message': 'a'},
104 143 {'message': 'b', 'branch': new_branch}
105 144 ]
106 145 backend.create_repo(commits)
107 146
108 147 backend.repo.landing_rev = "branch:%s" % new_branch
109 148
110 149 # get response based on tip and not new revision
111 150 response = self.app.get(url(
112 151 controller='files', action='index',
113 152 repo_name=backend.repo_name, revision='tip', f_path='/'),
114 153 status=200)
115 154
116 155 # make sure Files menu url is not tip but new revision
117 156 landing_rev = backend.repo.landing_rev[1]
118 157 files_url = url('files_home', repo_name=backend.repo_name,
119 158 revision=landing_rev)
120 159
121 160 assert landing_rev != 'tip'
122 161 response.mustcontain('<li class="active"><a class="menulink" href="%s">' % files_url)
123 162
124 163 def test_index_commit(self, backend):
125 164 commit = backend.repo.get_commit(commit_idx=32)
126 165
127 166 response = self.app.get(url(
128 167 controller='files', action='index',
129 168 repo_name=backend.repo_name,
130 169 revision=commit.raw_id,
131 170 f_path='/')
132 171 )
133 172
134 173 dirs = ['docs', 'tests']
135 174 files = ['README.rst']
136 175 params = {
137 176 'repo_name': backend.repo_name,
138 177 'commit_id': commit.raw_id,
139 178 }
140 179 assert_dirs_in_response(response, dirs, params)
141 180 assert_files_in_response(response, files, params)
142 181
143 182 @pytest.mark.xfail_backends("git", reason="Missing branches in git repo")
144 183 @pytest.mark.xfail_backends("svn", reason="Depends on branch support")
145 184 def test_index_different_branch(self, backend):
146 185 # TODO: Git test repository does not contain branches
147 186 # TODO: Branch support in Subversion
148 187
149 188 commit = backend.repo.get_commit(commit_idx=150)
150 189 response = self.app.get(url(
151 190 controller='files', action='index',
152 191 repo_name=backend.repo_name,
153 192 revision=commit.raw_id,
154 193 f_path='/'))
155 194 assert_response = AssertResponse(response)
156 195 assert_response.element_contains(
157 196 '.tags .branchtag', 'git')
158 197
159 198 def test_index_paging(self, backend):
160 199 repo = backend.repo
161 200 indexes = [73, 92, 109, 1, 0]
162 201 idx_map = [(rev, repo.get_commit(commit_idx=rev).raw_id)
163 202 for rev in indexes]
164 203
165 204 for idx in idx_map:
166 205 response = self.app.get(url(
167 206 controller='files', action='index',
168 207 repo_name=backend.repo_name,
169 208 revision=idx[1],
170 209 f_path='/'))
171 210
172 211 response.mustcontain("""r%s:%s""" % (idx[0], idx[1][:8]))
173 212
174 213 def test_file_source(self, backend):
175 214 commit = backend.repo.get_commit(commit_idx=167)
176 215 response = self.app.get(url(
177 216 controller='files', action='index',
178 217 repo_name=backend.repo_name,
179 218 revision=commit.raw_id,
180 219 f_path='vcs/nodes.py'))
181 220
182 221 msgbox = """<div class="commit right-content">%s</div>"""
183 222 response.mustcontain(msgbox % (commit.message, ))
184 223
185 224 assert_response = AssertResponse(response)
186 225 if commit.branch:
187 226 assert_response.element_contains('.tags.tags-main .branchtag', commit.branch)
188 227 if commit.tags:
189 228 for tag in commit.tags:
190 229 assert_response.element_contains('.tags.tags-main .tagtag', tag)
191 230
192 231 def test_file_source_history(self, backend):
193 232 response = self.app.get(
194 233 url(
195 234 controller='files', action='history',
196 235 repo_name=backend.repo_name,
197 236 revision='tip',
198 237 f_path='vcs/nodes.py'),
199 238 extra_environ={'HTTP_X_PARTIAL_XHR': '1'})
200 239 assert NODE_HISTORY[backend.alias] == json.loads(response.body)
201 240
202 241 def test_file_source_history_svn(self, backend_svn):
203 242 simple_repo = backend_svn['svn-simple-layout']
204 243 response = self.app.get(
205 244 url(
206 245 controller='files', action='history',
207 246 repo_name=simple_repo.repo_name,
208 247 revision='tip',
209 248 f_path='trunk/example.py'),
210 249 extra_environ={'HTTP_X_PARTIAL_XHR': '1'})
211 250
212 251 expected_data = json.loads(
213 252 fixture.load_resource('svn_node_history_branches.json'))
214 253 assert expected_data == response.json
215 254
216 255 def test_file_annotation_history(self, backend):
217 256 response = self.app.get(
218 257 url(
219 258 controller='files', action='history',
220 259 repo_name=backend.repo_name,
221 260 revision='tip',
222 261 f_path='vcs/nodes.py',
223 262 annotate=True),
224 263 extra_environ={'HTTP_X_PARTIAL_XHR': '1'})
225 264 assert NODE_HISTORY[backend.alias] == json.loads(response.body)
226 265
227 266 def test_file_annotation(self, backend):
228 267 response = self.app.get(url(
229 268 controller='files', action='index',
230 269 repo_name=backend.repo_name, revision='tip', f_path='vcs/nodes.py',
231 270 annotate=True))
232 271
233 272 expected_revisions = {
234 273 'hg': 'r356:25213a5fbb04',
235 274 'git': 'r345:c994f0de03b2',
236 275 'svn': 'r208:209',
237 276 }
238 277 response.mustcontain(expected_revisions[backend.alias])
239 278
240 279 def test_file_authors(self, backend):
241 280 response = self.app.get(url(
242 281 controller='files', action='authors',
243 282 repo_name=backend.repo_name,
244 283 revision='tip',
245 284 f_path='vcs/nodes.py',
246 285 annotate=True))
247 286
248 287 expected_authors = {
249 288 'hg': ('Marcin Kuzminski', 'Lukasz Balcerzak'),
250 289 'git': ('Marcin Kuzminski', 'Lukasz Balcerzak'),
251 290 'svn': ('marcin', 'lukasz'),
252 291 }
253 292
254 293 for author in expected_authors[backend.alias]:
255 294 response.mustcontain(author)
256 295
257 296 def test_tree_search_top_level(self, backend, xhr_header):
258 297 commit = backend.repo.get_commit(commit_idx=173)
259 298 response = self.app.get(
260 299 url('files_nodelist_home', repo_name=backend.repo_name,
261 300 revision=commit.raw_id, f_path='/'),
262 301 extra_environ=xhr_header)
263 302 assert 'nodes' in response.json
264 303 assert {'name': 'docs', 'type': 'dir'} in response.json['nodes']
265 304
266 305 def test_tree_search_at_path(self, backend, xhr_header):
267 306 commit = backend.repo.get_commit(commit_idx=173)
268 307 response = self.app.get(
269 308 url('files_nodelist_home', repo_name=backend.repo_name,
270 309 revision=commit.raw_id, f_path='/docs'),
271 310 extra_environ=xhr_header)
272 311 assert 'nodes' in response.json
273 312 nodes = response.json['nodes']
274 313 assert {'name': 'docs/api', 'type': 'dir'} in nodes
275 314 assert {'name': 'docs/index.rst', 'type': 'file'} in nodes
276 315
277 316 def test_tree_search_at_path_missing_xhr(self, backend):
278 317 self.app.get(
279 318 url('files_nodelist_home', repo_name=backend.repo_name,
280 319 revision='tip', f_path=''), status=400)
281 320
282 321 def test_tree_view_list(self, backend, xhr_header):
283 322 commit = backend.repo.get_commit(commit_idx=173)
284 323 response = self.app.get(
285 324 url('files_nodelist_home', repo_name=backend.repo_name,
286 325 f_path='/', revision=commit.raw_id),
287 326 extra_environ=xhr_header,
288 327 )
289 328 response.mustcontain("vcs/web/simplevcs/views/repository.py")
290 329
291 330 def test_tree_view_list_at_path(self, backend, xhr_header):
292 331 commit = backend.repo.get_commit(commit_idx=173)
293 332 response = self.app.get(
294 333 url('files_nodelist_home', repo_name=backend.repo_name,
295 334 f_path='/docs', revision=commit.raw_id),
296 335 extra_environ=xhr_header,
297 336 )
298 337 response.mustcontain("docs/index.rst")
299 338
300 339 def test_tree_view_list_missing_xhr(self, backend):
301 340 self.app.get(
302 341 url('files_nodelist_home', repo_name=backend.repo_name,
303 342 f_path='/', revision='tip'), status=400)
304 343
305 344 def test_nodetree_full_success(self, backend, xhr_header):
306 345 commit = backend.repo.get_commit(commit_idx=173)
307 346 response = self.app.get(
308 347 url('files_nodetree_full', repo_name=backend.repo_name,
309 348 f_path='/', commit_id=commit.raw_id),
310 349 extra_environ=xhr_header)
311 350
312 351 assert_response = AssertResponse(response)
313 352
314 353 for attr in ['data-commit-id', 'data-date', 'data-author']:
315 354 elements = assert_response.get_elements('[{}]'.format(attr))
316 355 assert len(elements) > 1
317 356
318 357 for element in elements:
319 358 assert element.get(attr)
320 359
321 360 def test_nodetree_full_if_file(self, backend, xhr_header):
322 361 commit = backend.repo.get_commit(commit_idx=173)
323 362 response = self.app.get(
324 363 url('files_nodetree_full', repo_name=backend.repo_name,
325 364 f_path='README.rst', commit_id=commit.raw_id),
326 365 extra_environ=xhr_header)
327 366 assert response.body == ''
328 367
329 368 def test_tree_metadata_list_missing_xhr(self, backend):
330 369 self.app.get(
331 370 url('files_nodetree_full', repo_name=backend.repo_name,
332 371 f_path='/', commit_id='tip'), status=400)
333 372
334 373 def test_access_empty_repo_redirect_to_summary_with_alert_write_perms(
335 374 self, app, backend_stub, autologin_regular_user, user_regular,
336 375 user_util):
337 376 repo = backend_stub.create_repo()
338 377 user_util.grant_user_permission_to_repo(
339 378 repo, user_regular, 'repository.write')
340 379 response = self.app.get(url(
341 380 controller='files', action='index',
342 381 repo_name=repo.repo_name, revision='tip', f_path='/'))
343 382 assert_session_flash(
344 383 response,
345 384 'There are no files yet. <a class="alert-link" '
346 385 'href="/%s/add/0/#edit">Click here to add a new file.</a>'
347 386 % (repo.repo_name))
348 387
349 388 def test_access_empty_repo_redirect_to_summary_with_alert_no_write_perms(
350 389 self, backend_stub, user_util):
351 390 repo = backend_stub.create_repo()
352 391 repo_file_url = url(
353 392 'files_add_home',
354 393 repo_name=repo.repo_name,
355 394 revision=0, f_path='', anchor='edit')
356 395 response = self.app.get(url(
357 396 controller='files', action='index',
358 397 repo_name=repo.repo_name, revision='tip', f_path='/'))
359 398 assert_not_in_session_flash(response, repo_file_url)
360 399
361 400
362 401 # TODO: johbo: Think about a better place for these tests. Either controller
363 402 # specific unit tests or we move down the whole logic further towards the vcs
364 403 # layer
365 404 class TestAdjustFilePathForSvn:
366 405 """SVN specific adjustments of node history in FileController."""
367 406
368 407 def test_returns_path_relative_to_matched_reference(self):
369 408 repo = self._repo(branches=['trunk'])
370 409 self.assert_file_adjustment('trunk/file', 'file', repo)
371 410
372 411 def test_does_not_modify_file_if_no_reference_matches(self):
373 412 repo = self._repo(branches=['trunk'])
374 413 self.assert_file_adjustment('notes/file', 'notes/file', repo)
375 414
376 415 def test_does_not_adjust_partial_directory_names(self):
377 416 repo = self._repo(branches=['trun'])
378 417 self.assert_file_adjustment('trunk/file', 'trunk/file', repo)
379 418
380 419 def test_is_robust_to_patterns_which_prefix_other_patterns(self):
381 420 repo = self._repo(branches=['trunk', 'trunk/new', 'trunk/old'])
382 421 self.assert_file_adjustment('trunk/new/file', 'file', repo)
383 422
384 423 def assert_file_adjustment(self, f_path, expected, repo):
385 424 controller = FilesController()
386 425 result = controller._adjust_file_path_for_svn(f_path, repo)
387 426 assert result == expected
388 427
389 428 def _repo(self, branches=None):
390 429 repo = mock.Mock()
391 430 repo.branches = OrderedDict((name, '0') for name in branches or [])
392 431 repo.tags = {}
393 432 return repo
394 433
395 434
396 435 @pytest.mark.usefixtures("app")
397 436 class TestRepositoryArchival:
398 437
399 438 def test_archival(self, backend):
400 439 backend.enable_downloads()
401 440 commit = backend.repo.get_commit(commit_idx=173)
402 441 for archive, info in settings.ARCHIVE_SPECS.items():
403 442 mime_type, arch_ext = info
404 443 short = commit.short_id + arch_ext
405 444 fname = commit.raw_id + arch_ext
406 445 filename = '%s-%s' % (backend.repo_name, short)
407 446 response = self.app.get(url(controller='files',
408 447 action='archivefile',
409 448 repo_name=backend.repo_name,
410 449 fname=fname))
411 450
412 451 assert response.status == '200 OK'
413 452 headers = {
414 453 'Pragma': 'no-cache',
415 454 'Cache-Control': 'no-cache',
416 455 'Content-Disposition': 'attachment; filename=%s' % filename,
417 456 'Content-Type': '%s; charset=utf-8' % mime_type,
418 457 }
419 458 if 'Set-Cookie' in response.response.headers:
420 459 del response.response.headers['Set-Cookie']
421 460 assert response.response.headers == headers
422 461
423 462 def test_archival_wrong_ext(self, backend):
424 463 backend.enable_downloads()
425 464 commit = backend.repo.get_commit(commit_idx=173)
426 465 for arch_ext in ['tar', 'rar', 'x', '..ax', '.zipz']:
427 466 fname = commit.raw_id + arch_ext
428 467
429 468 response = self.app.get(url(controller='files',
430 469 action='archivefile',
431 470 repo_name=backend.repo_name,
432 471 fname=fname))
433 472 response.mustcontain('Unknown archive type')
434 473
435 474 def test_archival_wrong_commit_id(self, backend):
436 475 backend.enable_downloads()
437 476 for commit_id in ['00x000000', 'tar', 'wrong', '@##$@$42413232',
438 477 '232dffcd']:
439 478 fname = '%s.zip' % commit_id
440 479
441 480 response = self.app.get(url(controller='files',
442 481 action='archivefile',
443 482 repo_name=backend.repo_name,
444 483 fname=fname))
445 484 response.mustcontain('Unknown revision')
446 485
447 486
448 487 @pytest.mark.usefixtures("app", "autologin_user")
449 488 class TestRawFileHandling:
450 489
451 490 def test_raw_file_ok(self, backend):
452 491 commit = backend.repo.get_commit(commit_idx=173)
453 492 response = self.app.get(url(controller='files', action='rawfile',
454 493 repo_name=backend.repo_name,
455 494 revision=commit.raw_id,
456 495 f_path='vcs/nodes.py'))
457 496
458 497 assert response.content_disposition == "attachment; filename=nodes.py"
459 498 assert response.content_type == "text/x-python"
460 499
461 500 def test_raw_file_wrong_cs(self, backend):
462 501 commit_id = u'ERRORce30c96924232dffcd24178a07ffeb5dfc'
463 502 f_path = 'vcs/nodes.py'
464 503
465 504 response = self.app.get(url(controller='files', action='rawfile',
466 505 repo_name=backend.repo_name,
467 506 revision=commit_id,
468 507 f_path=f_path), status=404)
469 508
470 509 msg = """No such commit exists for this repository"""
471 510 response.mustcontain(msg)
472 511
473 512 def test_raw_file_wrong_f_path(self, backend):
474 513 commit = backend.repo.get_commit(commit_idx=173)
475 514 f_path = 'vcs/ERRORnodes.py'
476 515 response = self.app.get(url(controller='files', action='rawfile',
477 516 repo_name=backend.repo_name,
478 517 revision=commit.raw_id,
479 518 f_path=f_path), status=404)
480 519
481 520 msg = (
482 521 "There is no file nor directory at the given path: "
483 522 "&#39;%s&#39; at commit %s" % (f_path, commit.short_id))
484 523 response.mustcontain(msg)
485 524
486 525 def test_raw_ok(self, backend):
487 526 commit = backend.repo.get_commit(commit_idx=173)
488 527 response = self.app.get(url(controller='files', action='raw',
489 528 repo_name=backend.repo_name,
490 529 revision=commit.raw_id,
491 530 f_path='vcs/nodes.py'))
492 531
493 532 assert response.content_type == "text/plain"
494 533
495 534 def test_raw_wrong_cs(self, backend):
496 535 commit_id = u'ERRORcce30c96924232dffcd24178a07ffeb5dfc'
497 536 f_path = 'vcs/nodes.py'
498 537
499 538 response = self.app.get(url(controller='files', action='raw',
500 539 repo_name=backend.repo_name,
501 540 revision=commit_id,
502 541 f_path=f_path), status=404)
503 542
504 543 msg = """No such commit exists for this repository"""
505 544 response.mustcontain(msg)
506 545
507 546 def test_raw_wrong_f_path(self, backend):
508 547 commit = backend.repo.get_commit(commit_idx=173)
509 548 f_path = 'vcs/ERRORnodes.py'
510 549 response = self.app.get(url(controller='files', action='raw',
511 550 repo_name=backend.repo_name,
512 551 revision=commit.raw_id,
513 552 f_path=f_path), status=404)
514 553 msg = (
515 554 "There is no file nor directory at the given path: "
516 555 "&#39;%s&#39; at commit %s" % (f_path, commit.short_id))
517 556 response.mustcontain(msg)
518 557
519 558 def test_raw_svg_should_not_be_rendered(self, backend):
520 559 backend.create_repo()
521 560 backend.ensure_file("xss.svg")
522 561 response = self.app.get(url(controller='files', action='raw',
523 562 repo_name=backend.repo_name,
524 563 revision='tip',
525 564 f_path='xss.svg'))
526 565
527 566 # If the content type is image/svg+xml then it allows to render HTML
528 567 # and malicious SVG.
529 568 assert response.content_type == "text/plain"
530 569
531 570
532 571 @pytest.mark.usefixtures("app")
533 572 class TestFilesDiff:
534 573
535 574 @pytest.mark.parametrize("diff", ['diff', 'download', 'raw'])
536 575 def test_file_full_diff(self, backend, diff):
537 576 commit1 = backend.repo.get_commit(commit_idx=-1)
538 577 commit2 = backend.repo.get_commit(commit_idx=-2)
539 578 response = self.app.get(
540 579 url(
541 580 controller='files',
542 581 action='diff',
543 582 repo_name=backend.repo_name,
544 583 f_path='README'),
545 584 params={
546 585 'diff1': commit1.raw_id,
547 586 'diff2': commit2.raw_id,
548 587 'fulldiff': '1',
549 588 'diff': diff,
550 589 })
551 590 response.mustcontain('README.rst')
552 591 response.mustcontain('No newline at end of file')
553 592
554 593 def test_file_binary_diff(self, backend):
555 594 commits = [
556 595 {'message': 'First commit'},
557 596 {'message': 'Commit with binary',
558 597 'added': [nodes.FileNode('file.bin', content='\0BINARY\0')]},
559 598 ]
560 599 repo = backend.create_repo(commits=commits)
561 600
562 601 response = self.app.get(
563 602 url(
564 603 controller='files',
565 604 action='diff',
566 605 repo_name=backend.repo_name,
567 606 f_path='file.bin'),
568 607 params={
569 608 'diff1': repo.get_commit(commit_idx=0).raw_id,
570 609 'diff2': repo.get_commit(commit_idx=1).raw_id,
571 610 'fulldiff': '1',
572 611 'diff': 'diff',
573 612 })
574 613 response.mustcontain('Cannot diff binary files')
575 614
576 615 def test_diff_2way(self, backend):
577 616 commit1 = backend.repo.get_commit(commit_idx=-1)
578 617 commit2 = backend.repo.get_commit(commit_idx=-2)
579 618 response = self.app.get(
580 619 url(
581 620 controller='files',
582 621 action='diff_2way',
583 622 repo_name=backend.repo_name,
584 623 f_path='README'),
585 624 params={
586 625 'diff1': commit1.raw_id,
587 626 'diff2': commit2.raw_id,
588 627 })
589 628
590 629 # Expecting links to both variants of the file. Links are used
591 630 # to load the content dynamically.
592 631 response.mustcontain('/%s/README' % commit1.raw_id)
593 632 response.mustcontain('/%s/README' % commit2.raw_id)
594 633
595 634 def test_requires_one_commit_id(self, backend, autologin_user):
596 635 response = self.app.get(
597 636 url(
598 637 controller='files',
599 638 action='diff',
600 639 repo_name=backend.repo_name,
601 640 f_path='README.rst'),
602 641 status=400)
603 642 response.mustcontain(
604 643 'Need query parameter', 'diff1', 'diff2', 'to generate a diff.')
605 644
606 645 def test_returns_not_found_if_file_does_not_exist(self, vcsbackend):
607 646 repo = vcsbackend.repo
608 647 self.app.get(
609 648 url(
610 649 controller='files',
611 650 action='diff',
612 651 repo_name=repo.name,
613 652 f_path='does-not-exist-in-any-commit',
614 653 diff1=repo[0].raw_id,
615 654 diff2=repo[1].raw_id),
616 655 status=404)
617 656
618 657 def test_returns_redirect_if_file_not_changed(self, backend):
619 658 commit = backend.repo.get_commit(commit_idx=-1)
620 659 f_path= 'README'
621 660 response = self.app.get(
622 661 url(
623 662 controller='files',
624 663 action='diff_2way',
625 664 repo_name=backend.repo_name,
626 665 f_path=f_path,
627 666 diff1=commit.raw_id,
628 667 diff2=commit.raw_id,
629 668 ),
630 669 status=302
631 670 )
632 671 assert response.headers['Location'].endswith(f_path)
633 672 redirected = response.follow()
634 673 redirected.mustcontain('has not changed between')
635 674
636 675 def test_supports_diff_to_different_path_svn(self, backend_svn):
637 676 repo = backend_svn['svn-simple-layout'].scm_instance()
638 677 commit_id = repo[-1].raw_id
639 678 response = self.app.get(
640 679 url(
641 680 controller='files',
642 681 action='diff',
643 682 repo_name=repo.name,
644 683 f_path='trunk/example.py',
645 684 diff1='tags/v0.2/example.py@' + commit_id,
646 685 diff2=commit_id),
647 686 status=200)
648 687 response.mustcontain(
649 688 "Will print out a useful message on invocation.")
650 689
651 690 # Note: Expecting that we indicate the user what's being compared
652 691 response.mustcontain("trunk/example.py")
653 692 response.mustcontain("tags/v0.2/example.py")
654 693
655 694 def test_show_rev_redirects_to_svn_path(self, backend_svn):
656 695 repo = backend_svn['svn-simple-layout'].scm_instance()
657 696 commit_id = repo[-1].raw_id
658 697 response = self.app.get(
659 698 url(
660 699 controller='files',
661 700 action='diff',
662 701 repo_name=repo.name,
663 702 f_path='trunk/example.py',
664 703 diff1='branches/argparse/example.py@' + commit_id,
665 704 diff2=commit_id),
666 705 params={'show_rev': 'Show at Revision'},
667 706 status=302)
668 707 assert response.headers['Location'].endswith(
669 708 'svn-svn-simple-layout/files/26/branches/argparse/example.py')
670 709
671 710 def test_show_rev_and_annotate_redirects_to_svn_path(self, backend_svn):
672 711 repo = backend_svn['svn-simple-layout'].scm_instance()
673 712 commit_id = repo[-1].raw_id
674 713 response = self.app.get(
675 714 url(
676 715 controller='files',
677 716 action='diff',
678 717 repo_name=repo.name,
679 718 f_path='trunk/example.py',
680 719 diff1='branches/argparse/example.py@' + commit_id,
681 720 diff2=commit_id),
682 721 params={
683 722 'show_rev': 'Show at Revision',
684 723 'annotate': 'true',
685 724 },
686 725 status=302)
687 726 assert response.headers['Location'].endswith(
688 727 'svn-svn-simple-layout/annotate/26/branches/argparse/example.py')
689 728
690 729
691 730 @pytest.mark.usefixtures("app", "autologin_user")
692 731 class TestChangingFiles:
693 732
694 733 def test_add_file_view(self, backend):
695 734 self.app.get(url(
696 735 'files_add_home',
697 736 repo_name=backend.repo_name,
698 737 revision='tip', f_path='/'))
699 738
700 739 @pytest.mark.xfail_backends("svn", reason="Depends on online editing")
701 740 def test_add_file_into_repo_missing_content(self, backend, csrf_token):
702 741 repo = backend.create_repo()
703 742 filename = 'init.py'
704 743 response = self.app.post(
705 744 url(
706 745 'files_add',
707 746 repo_name=repo.repo_name,
708 747 revision='tip', f_path='/'),
709 748 params={
710 749 'content': "",
711 750 'filename': filename,
712 751 'location': "",
713 752 'csrf_token': csrf_token,
714 753 },
715 754 status=302)
716 755 assert_session_flash(
717 756 response, 'Successfully committed to %s'
718 757 % os.path.join(filename))
719 758
720 759 def test_add_file_into_repo_missing_filename(self, backend, csrf_token):
721 760 response = self.app.post(
722 761 url(
723 762 'files_add',
724 763 repo_name=backend.repo_name,
725 764 revision='tip', f_path='/'),
726 765 params={
727 766 'content': "foo",
728 767 'csrf_token': csrf_token,
729 768 },
730 769 status=302)
731 770
732 771 assert_session_flash(response, 'No filename')
733 772
734 773 def test_add_file_into_repo_errors_and_no_commits(
735 774 self, backend, csrf_token):
736 775 repo = backend.create_repo()
737 776 # Create a file with no filename, it will display an error but
738 777 # the repo has no commits yet
739 778 response = self.app.post(
740 779 url(
741 780 'files_add',
742 781 repo_name=repo.repo_name,
743 782 revision='tip', f_path='/'),
744 783 params={
745 784 'content': "foo",
746 785 'csrf_token': csrf_token,
747 786 },
748 787 status=302)
749 788
750 789 assert_session_flash(response, 'No filename')
751 790
752 791 # Not allowed, redirect to the summary
753 792 redirected = response.follow()
754 793 summary_url = url('summary_home', repo_name=repo.repo_name)
755 794
756 795 # As there are no commits, displays the summary page with the error of
757 796 # creating a file with no filename
758 797 assert redirected.req.path == summary_url
759 798
760 799 @pytest.mark.parametrize("location, filename", [
761 800 ('/abs', 'foo'),
762 801 ('../rel', 'foo'),
763 802 ('file/../foo', 'foo'),
764 803 ])
765 804 def test_add_file_into_repo_bad_filenames(
766 805 self, location, filename, backend, csrf_token):
767 806 response = self.app.post(
768 807 url(
769 808 'files_add',
770 809 repo_name=backend.repo_name,
771 810 revision='tip', f_path='/'),
772 811 params={
773 812 'content': "foo",
774 813 'filename': filename,
775 814 'location': location,
776 815 'csrf_token': csrf_token,
777 816 },
778 817 status=302)
779 818
780 819 assert_session_flash(
781 820 response,
782 821 'The location specified must be a relative path and must not '
783 822 'contain .. in the path')
784 823
785 824 @pytest.mark.parametrize("cnt, location, filename", [
786 825 (1, '', 'foo.txt'),
787 826 (2, 'dir', 'foo.rst'),
788 827 (3, 'rel/dir', 'foo.bar'),
789 828 ])
790 829 def test_add_file_into_repo(self, cnt, location, filename, backend,
791 830 csrf_token):
792 831 repo = backend.create_repo()
793 832 response = self.app.post(
794 833 url(
795 834 'files_add',
796 835 repo_name=repo.repo_name,
797 836 revision='tip', f_path='/'),
798 837 params={
799 838 'content': "foo",
800 839 'filename': filename,
801 840 'location': location,
802 841 'csrf_token': csrf_token,
803 842 },
804 843 status=302)
805 844 assert_session_flash(
806 845 response, 'Successfully committed to %s'
807 846 % os.path.join(location, filename))
808 847
809 848 def test_edit_file_view(self, backend):
810 849 response = self.app.get(
811 850 url(
812 851 'files_edit_home',
813 852 repo_name=backend.repo_name,
814 853 revision=backend.default_head_id,
815 854 f_path='vcs/nodes.py'),
816 855 status=200)
817 856 response.mustcontain("Module holding everything related to vcs nodes.")
818 857
819 858 def test_edit_file_view_not_on_branch(self, backend):
820 859 repo = backend.create_repo()
821 860 backend.ensure_file("vcs/nodes.py")
822 861
823 862 response = self.app.get(
824 863 url(
825 864 'files_edit_home',
826 865 repo_name=repo.repo_name,
827 866 revision='tip', f_path='vcs/nodes.py'),
828 867 status=302)
829 868 assert_session_flash(
830 869 response,
831 870 'You can only edit files with revision being a valid branch')
832 871
833 872 def test_edit_file_view_commit_changes(self, backend, csrf_token):
834 873 repo = backend.create_repo()
835 874 backend.ensure_file("vcs/nodes.py", content="print 'hello'")
836 875
837 876 response = self.app.post(
838 877 url(
839 878 'files_edit',
840 879 repo_name=repo.repo_name,
841 880 revision=backend.default_head_id,
842 881 f_path='vcs/nodes.py'),
843 882 params={
844 883 'content': "print 'hello world'",
845 884 'message': 'I committed',
846 885 'filename': "vcs/nodes.py",
847 886 'csrf_token': csrf_token,
848 887 },
849 888 status=302)
850 889 assert_session_flash(
851 890 response, 'Successfully committed to vcs/nodes.py')
852 891 tip = repo.get_commit(commit_idx=-1)
853 892 assert tip.message == 'I committed'
854 893
855 894 def test_edit_file_view_commit_changes_default_message(self, backend,
856 895 csrf_token):
857 896 repo = backend.create_repo()
858 897 backend.ensure_file("vcs/nodes.py", content="print 'hello'")
859 898
860 899 commit_id = (
861 900 backend.default_branch_name or
862 901 backend.repo.scm_instance().commit_ids[-1])
863 902
864 903 response = self.app.post(
865 904 url(
866 905 'files_edit',
867 906 repo_name=repo.repo_name,
868 907 revision=commit_id,
869 908 f_path='vcs/nodes.py'),
870 909 params={
871 910 'content': "print 'hello world'",
872 911 'message': '',
873 912 'filename': "vcs/nodes.py",
874 913 'csrf_token': csrf_token,
875 914 },
876 915 status=302)
877 916 assert_session_flash(
878 917 response, 'Successfully committed to vcs/nodes.py')
879 918 tip = repo.get_commit(commit_idx=-1)
880 919 assert tip.message == 'Edited file vcs/nodes.py via RhodeCode Enterprise'
881 920
882 921 def test_delete_file_view(self, backend):
883 922 self.app.get(url(
884 923 'files_delete_home',
885 924 repo_name=backend.repo_name,
886 925 revision='tip', f_path='vcs/nodes.py'))
887 926
888 927 def test_delete_file_view_not_on_branch(self, backend):
889 928 repo = backend.create_repo()
890 929 backend.ensure_file('vcs/nodes.py')
891 930
892 931 response = self.app.get(
893 932 url(
894 933 'files_delete_home',
895 934 repo_name=repo.repo_name,
896 935 revision='tip', f_path='vcs/nodes.py'),
897 936 status=302)
898 937 assert_session_flash(
899 938 response,
900 939 'You can only delete files with revision being a valid branch')
901 940
902 941 def test_delete_file_view_commit_changes(self, backend, csrf_token):
903 942 repo = backend.create_repo()
904 943 backend.ensure_file("vcs/nodes.py")
905 944
906 945 response = self.app.post(
907 946 url(
908 947 'files_delete_home',
909 948 repo_name=repo.repo_name,
910 949 revision=backend.default_head_id,
911 950 f_path='vcs/nodes.py'),
912 951 params={
913 952 'message': 'i commited',
914 953 'csrf_token': csrf_token,
915 954 },
916 955 status=302)
917 956 assert_session_flash(
918 957 response, 'Successfully deleted file vcs/nodes.py')
919 958
920 959
921 960 def assert_files_in_response(response, files, params):
922 961 template = (
923 962 'href="/%(repo_name)s/files/%(commit_id)s/%(name)s"')
924 963 _assert_items_in_response(response, files, template, params)
925 964
926 965
927 966 def assert_dirs_in_response(response, dirs, params):
928 967 template = (
929 968 'href="/%(repo_name)s/files/%(commit_id)s/%(name)s"')
930 969 _assert_items_in_response(response, dirs, template, params)
931 970
932 971
933 972 def _assert_items_in_response(response, items, template, params):
934 973 for item in items:
935 974 item_params = {'name': item}
936 975 item_params.update(params)
937 976 response.mustcontain(template % item_params)
938 977
939 978
940 979 def assert_timeago_in_response(response, items, params):
941 980 for item in items:
942 981 response.mustcontain(h.age_component(params['date']))
982
983
984
985 @pytest.mark.usefixtures("autologin_user", "app")
986 class TestSideBySideDiff:
987
988 def test_diff2way(self, app, backend, backend_stub):
989 f_path = 'content'
990 commit1_content = 'content-25d7e49c18b159446c'
991 commit2_content = 'content-603d6c72c46d953420'
992 repo = backend.create_repo()
993
994 commit1 = _commit_change(
995 repo.repo_name, filename=f_path, content=commit1_content,
996 message='A', vcs_type=backend.alias, parent=None, newfile=True)
997
998 commit2 = _commit_change(
999 repo.repo_name, filename=f_path, content=commit2_content,
1000 message='B, child of A', vcs_type=backend.alias, parent=commit1)
1001
1002 response = self.app.get(url(
1003 controller='files', action='diff_2way',
1004 repo_name=repo.repo_name,
1005 diff1=commit1.raw_id,
1006 diff2=commit2.raw_id,
1007 f_path=f_path))
1008
1009 assert_response = AssertResponse(response)
1010 response.mustcontain(
1011 ('Side-by-side Diff r0:%s ... r1:%s') % ( commit1.short_id, commit2.short_id ))
1012 response.mustcontain('id="compare"')
1013 response.mustcontain((
1014 "var orig1_url = '/%s/raw/%s/%s';\n"
1015 "var orig2_url = '/%s/raw/%s/%s';") %
1016 ( repo.repo_name, commit1.raw_id, f_path,
1017 repo.repo_name, commit2.raw_id, f_path))
1018
1019
1020 def test_diff2way_with_empty_file(self, app, backend, backend_stub):
1021 commits = [
1022 {'message': 'First commit'},
1023 {'message': 'Commit with binary',
1024 'added': [nodes.FileNode('file.empty', content='')]},
1025 ]
1026 f_path='file.empty'
1027 repo = backend.create_repo(commits=commits)
1028 commit_id1 = repo.get_commit(commit_idx=0).raw_id
1029 commit_id2 = repo.get_commit(commit_idx=1).raw_id
1030
1031 response = self.app.get(url(
1032 controller='files', action='diff_2way',
1033 repo_name=repo.repo_name,
1034 diff1=commit_id1,
1035 diff2=commit_id2,
1036 f_path=f_path))
1037
1038 assert_response = AssertResponse(response)
1039 if backend.alias == 'svn':
1040 assert_session_flash( response,
1041 ('%(file_path)s has not changed') % { 'file_path': 'file.empty' })
1042 else:
1043 response.mustcontain(
1044 ('Side-by-side Diff r0:%s ... r1:%s') % ( repo.get_commit(commit_idx=0).short_id, repo.get_commit(commit_idx=1).short_id ))
1045 response.mustcontain('id="compare"')
1046 response.mustcontain((
1047 "var orig1_url = '/%s/raw/%s/%s';\n"
1048 "var orig2_url = '/%s/raw/%s/%s';") %
1049 ( repo.repo_name, commit_id1, f_path,
1050 repo.repo_name, commit_id2, f_path))
1051
1052
1053 def test_empty_diff_2way_redirect_to_summary_with_alert(self, app, backend):
1054 commit_id_range = {
1055 'hg': (
1056 '25d7e49c18b159446cadfa506a5cf8ad1cb04067',
1057 '603d6c72c46d953420c89d36372f08d9f305f5dd'),
1058 'git': (
1059 '6fc9270775aaf5544c1deb014f4ddd60c952fcbb',
1060 '03fa803d7e9fb14daa9a3089e0d1494eda75d986'),
1061 'svn': (
1062 '335',
1063 '337'),
1064 }
1065 f_path = 'setup.py'
1066
1067 commit_ids = commit_id_range[backend.alias]
1068
1069 response = self.app.get(url(
1070 controller='files', action='diff_2way',
1071 repo_name=backend.repo_name,
1072 diff2=commit_ids[0],
1073 diff1=commit_ids[1],
1074 f_path=f_path))
1075
1076 assert_response = AssertResponse(response)
1077 assert_session_flash( response,
1078 ('%(file_path)s has not changed') % { 'file_path': f_path })
General Comments 0
You need to be logged in to leave comments. Login now