Veiko Aasa c136f27707
gitweb: Add ability to change default branch
Now it is possible to change default branch when editing a repository.

Gitweb site shows default branch as a main branch and the 'git clone'
command checks out to default branch.

Added unit and functional tests. Splitted one large 'test_actions'
into multiple tests.

Tests performed:
- All gitweb unit and functional tests pass.
- Created a repository from a remote repository which has default
  branch other than master. Confirmed that the 'Edit repository'
  page shows correct branch and gitweb site shows this branch as
  a default branch

Closes #1925

Signed-off-by: Veiko Aasa <veiko17@disroot.org>
Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
2020-09-09 14:37:17 -07:00

363 lines
12 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Tests for gitweb views.
"""
import json
from unittest.mock import patch
import pytest
from django import urls
from django.contrib.messages.storage.fallback import FallbackStorage
from django.http.response import Http404
from plinth import module_loader
from plinth.errors import ActionError
from plinth.modules.gitweb import views
# For all tests, use plinth.urls instead of urls configured for testing
pytestmark = pytest.mark.urls('plinth.urls')
EXISTING_REPOS = [
{
'name': 'something',
'description': '',
'owner': '',
'access': 'public',
'is_private': False,
'default_branch': 'master',
},
{
'name': 'something2',
'description': '',
'owner': '',
'access': 'private',
'is_private': True,
'default_branch': 'master',
},
]
@pytest.fixture(autouse=True, scope='module')
def fixture_gitweb_urls():
"""Make sure gitweb app's URLs are part of plinth.urls."""
with patch('plinth.module_loader._modules_to_load', new=[]) as modules, \
patch('plinth.urls.urlpatterns', new=[]):
modules.append('plinth.modules.gitweb')
module_loader.include_urls()
yield
def action_run(*args, **kwargs):
"""Action return values."""
subcommand = args[1][0]
if subcommand == 'repo-info':
return json.dumps(EXISTING_REPOS[0])
elif subcommand == 'check-repo-exists':
return True
elif subcommand == 'get-branches':
return json.dumps({
"default_branch": "master",
"branches": ["master", "branch1"]
})
return None
@pytest.fixture(autouse=True)
def gitweb_patch():
"""Patch gitweb."""
with patch('plinth.modules.gitweb.get_repo_list') as get_repo_list, \
patch('plinth.modules.gitweb.app') as gitweb_app, \
patch('plinth.actions.superuser_run', side_effect=action_run), \
patch('plinth.actions.run', side_effect=action_run):
get_repo_list.return_value = [{
'name': EXISTING_REPOS[0]['name']
}, {
'name': EXISTING_REPOS[1]['name']
}]
gitweb_app.update_service_access.return_value = None
yield
def make_request(request, view, **kwargs):
"""Make request with a message storage."""
setattr(request, 'session', 'session')
messages = FallbackStorage(request)
setattr(request, '_messages', messages)
response = view(request, **kwargs)
return response, messages
def test_repos_view(rf):
"""Test that a repo list has correct view data."""
with patch('plinth.views.AppView.get_context_data',
return_value={'is_enabled': True}):
view = views.GitwebAppView.as_view()
response, _ = make_request(rf.get(''), view)
assert response.context_data['repos'] == [{
'name': EXISTING_REPOS[0]['name']
}, {
'name': EXISTING_REPOS[1]['name']
}]
assert response.status_code == 200
def test_create_repo_view(rf):
"""Test that repo create view sends correct success message."""
form_data = {
'gitweb-name': 'something_other',
'gitweb-description': 'test description',
'gitweb-owner': 'test owner',
'gitweb-is_private': True
}
request = rf.post(urls.reverse('gitweb:create'), data=form_data)
view = views.CreateRepoView.as_view()
response, messages = make_request(request, view)
assert list(messages)[0].message == 'Repository created.'
assert response.status_code == 302
def test_create_repo_duplicate_name_view(rf):
"""Test that repo create view shows correct error message."""
form_data = {
'gitweb-name': EXISTING_REPOS[0]['name'],
'gitweb-description': '',
'gitweb-owner': ''
}
request = rf.post(urls.reverse('gitweb:create'), data=form_data)
view = views.CreateRepoView.as_view()
response, _ = make_request(request, view)
assert response.context_data['form'].errors['name'][
0] == 'A repository with this name already exists.'
assert response.status_code == 200
def test_create_repo_invalid_name_view(rf):
"""Test that repo create view shows correct error message."""
form_data = {
'gitweb-name': '.something_other',
'gitweb-description': '',
'gitweb-owner': ''
}
request = rf.post(urls.reverse('gitweb:create'), data=form_data)
view = views.CreateRepoView.as_view()
response, _ = make_request(request, view)
assert response.context_data['form'].errors['name'][
0] == 'Invalid repository name.'
assert response.status_code == 200
def test_create_repo_failed_view(rf):
"""Test that repo creation failure sends correct error message."""
general_error_message = "An error occurred while creating the repository."
error_description = 'some error'
with patch('plinth.modules.gitweb.create_repo',
side_effect=ActionError('gitweb', '', error_description)):
form_data = {
'gitweb-name': 'something_other',
'gitweb-description': '',
'gitweb-owner': ''
}
request = rf.post(urls.reverse('gitweb:create'), data=form_data)
view = views.CreateRepoView.as_view()
response, messages = make_request(request, view)
assert list(messages)[0].message == '{0} {1}'.format(
general_error_message, error_description)
assert response.status_code == 302
def test_clone_repo_view(rf):
"""Test that cloning repo sends correct succcess message."""
form_data = {
'gitweb-name': 'https://example.com/test.git',
'gitweb-description': '',
'gitweb-owner': ''
}
request = rf.post(urls.reverse('gitweb:create'), data=form_data)
view = views.CreateRepoView.as_view()
response, messages = make_request(request, view)
with pytest.raises(AttributeError):
getattr(response.context_data['form'], 'errors')
assert list(messages)[0].message == 'Repository created.'
assert response.status_code == 302
def test_clone_repo_missing_remote_view(rf):
"""Test that cloning non-existing repo shows correct error message."""
with patch('plinth.modules.gitweb.repo_exists', return_value=False):
form_data = {
'gitweb-name': 'https://example.com/test.git',
'gitweb-description': '',
'gitweb-owner': ''
}
request = rf.post(urls.reverse('gitweb:create'), data=form_data)
view = views.CreateRepoView.as_view()
response, _ = make_request(request, view)
assert response.context_data['form'].errors['name'][
0] == 'Remote repository is not available.'
assert response.status_code == 200
def test_edit_repository_view(rf):
"""Test that editing repo sends correct success message."""
form_data = {
'gitweb-name': 'something_other.git',
'gitweb-description': 'test-description',
'gitweb-owner': 'test-owner',
'gitweb-is_private': True,
'gitweb-default_branch': 'branch1',
}
url = urls.reverse('gitweb:edit',
kwargs={'name': EXISTING_REPOS[0]['name']})
request = rf.post(url, data=form_data)
view = views.EditRepoView.as_view()
response, messages = make_request(request, view,
name=EXISTING_REPOS[0]['name'])
assert list(messages)[0].message == 'Repository edited.'
assert response.status_code == 302
def test_edit_nonexisting_repository_view(rf):
"""Test that trying to edit non-existing repository raises 404."""
non_existing_repo = {'name': 'something_other'}
request = rf.post(urls.reverse('gitweb:edit', kwargs=non_existing_repo),
data={})
view = views.EditRepoView.as_view()
with pytest.raises(Http404):
make_request(request, view, **non_existing_repo)
def test_edit_repository_duplicate_name_view(rf):
"""Test that renaming to already existing repo name shows correct error
message.
"""
form_data = {
'gitweb-name': EXISTING_REPOS[1]['name'],
'gitweb-description': 'test-description',
'gitweb-owner': 'test-owner'
}
url = urls.reverse('gitweb:edit',
kwargs={'name': EXISTING_REPOS[0]['name']})
request = rf.post(url, data=form_data)
view = views.EditRepoView.as_view()
response, _ = make_request(request, view, **EXISTING_REPOS[0])
assert response.context_data['form'].errors['name'][
0] == 'A repository with this name already exists.'
assert response.status_code == 200
def test_edit_repository_invalid_name_view(rf):
"""Test that renaming repo to invalid name shows correct error message."""
form_data = {
'gitweb-name': '.something',
'gitweb-description': 'test-description',
'gitweb-owner': 'test-owner'
}
url = urls.reverse('gitweb:edit',
kwargs={'name': EXISTING_REPOS[0]['name']})
request = rf.post(url, data=form_data)
view = views.EditRepoView.as_view()
response, _ = make_request(request, view, **EXISTING_REPOS[0])
assert response.context_data['form'].errors['name'][
0] == 'Invalid repository name.'
assert response.status_code == 200
def test_edit_repository_no_change_view(rf):
"""Test that not changing any values don't edit the repo."""
with patch('plinth.modules.gitweb.edit_repo') as edit_repo:
form_data = {
'gitweb-name': EXISTING_REPOS[0]['name'],
'gitweb-description': EXISTING_REPOS[0]['description'],
'gitweb-owner': EXISTING_REPOS[0]['owner'],
'gitweb-default_branch': EXISTING_REPOS[0]['default_branch'],
}
request = rf.post(
urls.reverse('gitweb:edit',
kwargs={'name': EXISTING_REPOS[0]['name']}),
data=form_data)
view = views.EditRepoView.as_view()
response, _ = make_request(request, view, **EXISTING_REPOS[0])
assert not edit_repo.called, 'method should not have been called'
assert response.status_code == 302
def test_edit_repository_failed_view(rf):
"""Test that failed repo editing sends correct error message."""
with patch('plinth.modules.gitweb.edit_repo',
side_effect=ActionError('Error')):
form_data = {
'gitweb-name': 'something_other',
'gitweb-description': 'test-description',
'gitweb-owner': 'test-owner',
'gitweb-default_branch': 'master',
}
request = rf.post(
urls.reverse('gitweb:edit',
kwargs={'name': EXISTING_REPOS[0]['name']}),
data=form_data)
view = views.EditRepoView.as_view()
response, messages = make_request(request, view, **EXISTING_REPOS[0])
assert list(
messages)[0].message == 'An error occurred during configuration.'
assert response.status_code == 302
def test_delete_repository_confirmation_view(rf):
"""Test that repo deletion confirmation shows correct repo name."""
response, _ = make_request(rf.get(''), views.delete,
name=EXISTING_REPOS[0]['name'])
assert response.context_data['name'] == EXISTING_REPOS[0]['name']
assert response.status_code == 200
def test_delete_repository_view(rf):
"""Test that repo deletion sends correct success message."""
response, messages = make_request(rf.post(''), views.delete,
name=EXISTING_REPOS[0]['name'])
assert list(messages)[0].message == '{} deleted.'.format(
EXISTING_REPOS[0]['name'])
assert response.status_code == 302
def test_delete_repository_fail_view(rf):
"""Test that failed repository deletion sends correct error message."""
with patch('plinth.modules.gitweb.delete_repo',
side_effect=ActionError('Error')):
response, messages = make_request(rf.post(''), views.delete,
name=EXISTING_REPOS[0]['name'])
assert list(
messages)[0].message == 'Could not delete {}: Error'.format(
EXISTING_REPOS[0]['name'])
assert response.status_code == 302
def test_delete_non_existing_repository_view(rf):
"""Test that deleting non-existing repository raises 404."""
with pytest.raises(Http404):
make_request(rf.post(''), views.delete, name='unknown_repo')