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