diff --git a/swh/web/api/apiresponse.py b/swh/web/api/apiresponse.py index e88348cf..48dd4ca1 100644 --- a/swh/web/api/apiresponse.py +++ b/swh/web/api/apiresponse.py @@ -1,173 +1,177 @@ # Copyright (C) 2017 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information import json from rest_framework.response import Response from swh.storage.exc import StorageDBError, StorageAPIError from swh.web.common.exc import NotFoundExc, ForbiddenExc from swh.web.common.utils import shorten_path from swh.web.api import utils def compute_link_header(rv, options): """Add Link header in returned value results. Args: rv (dict): dictionary with keys: - headers: potential headers with 'link-next' and 'link-prev' keys - results: containing the result to return options (dict): the initial dict to update with result if any Returns: dict: dictionary with optional keys 'link-next' and 'link-prev' """ link_headers = [] if 'headers' not in rv: return {} rv_headers = rv['headers'] if 'link-next' in rv_headers: link_headers.append('<%s>; rel="next"' % ( rv_headers['link-next'])) if 'link-prev' in rv_headers: link_headers.append('<%s>; rel="previous"' % ( rv_headers['link-prev'])) if link_headers: link_header_str = ','.join(link_headers) headers = options.get('headers', {}) headers.update({ 'Link': link_header_str }) return headers return {} def filter_by_fields(request, data): """Extract a request parameter 'fields' if it exists to permit the filtering on he data dict's keys. If such field is not provided, returns the data as is. """ fields = request.query_params.get('fields') if fields: fields = set(fields.split(',')) data = utils.filter_field_keys(data, fields) return data def transform(rv): """Transform an eventual returned value with multiple layer of information with only what's necessary. If the returned value rv contains the 'results' key, this is the associated value which is returned. Otherwise, return the initial dict without the potential 'headers' key. """ if 'results' in rv: return rv['results'] if 'headers' in rv: rv.pop('headers') return rv def make_api_response(request, data, doc_data={}, options={}): """Generates an API response based on the requested mimetype. Args: request: a DRF Request object data: raw data to return in the API response doc_data: documentation data for HTML response options: optionnal data that can be used to generate the response Returns: a DRF Response a object """ if data: options['headers'] = compute_link_header(data, options) data = transform(data) data = filter_by_fields(request, data) doc_env = doc_data headers = {} if 'headers' in options: doc_env['headers_data'] = options['headers'] headers = options['headers'] # get request status code doc_env['status_code'] = options.get('status', 200) response_args = {'status': doc_env['status_code'], 'headers': headers, 'content_type': request.accepted_media_type} # when requesting HTML, typically when browsing the API through its # documented views, we need to enrich the input data with documentation # related ones and inform DRF that we request HTML template rendering if request.accepted_media_type == 'text/html': if data: data = json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')) doc_env['response_data'] = data - doc_env['request'] = request + doc_env['request'] = { + 'path': request.path, + 'method': request.method, + 'absolute_uri': request.build_absolute_uri() + } doc_env['heading'] = shorten_path(str(request.path)) response_args['data'] = doc_env response_args['template_name'] = 'apidoc.html' # otherwise simply return the raw data and let DRF picks # the correct renderer (JSON or YAML) else: response_args['data'] = data return Response(**response_args) def error_response(request, error, doc_data): """Private function to create a custom error response. Args: request: a DRF Request object error: the exception that caused the error doc_data: documentation data for HTML response """ error_code = 400 if isinstance(error, NotFoundExc): error_code = 404 elif isinstance(error, ForbiddenExc): error_code = 403 elif isinstance(error, StorageDBError): error_code = 503 elif isinstance(error, StorageAPIError): error_code = 503 error_opts = {'status': error_code} error_data = { 'exception': error.__class__.__name__, 'reason': str(error), } return make_api_response(request, error_data, doc_data, options=error_opts) diff --git a/swh/web/settings/common.py b/swh/web/settings/common.py index 57cc078d..e80ca18b 100644 --- a/swh/web/settings/common.py +++ b/swh/web/settings/common.py @@ -1,189 +1,189 @@ # Copyright (C) 2017 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information """ Django settings for swhweb project. Generated by 'django-admin startproject' using Django 1.11.3. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ import os from swh.web.config import get_config swh_web_config = get_config() # Build paths inside the project like this: os.path.join(BASE_DIR, ...) PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = swh_web_config['secret_key'] # SECURITY WARNING: don't run with debug turned on in production! DEBUG = swh_web_config['debug'] DEBUG_PROPAGATE_EXCEPTIONS = swh_web_config['debug'] ALLOWED_HOSTS = ['127.0.0.1', 'localhost'] + swh_web_config['allowed_hosts'] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'swh.web.api', 'swh.web.browse' ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware' ] ROOT_URLCONF = 'swh.web.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(PROJECT_DIR, "../templates")], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], 'libraries': { 'swh_templatetags': 'swh.web.common.swh_templatetags', }, }, }, ] WSGI_APPLICATION = 'swh.web.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(PROJECT_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', # noqa }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', # noqa }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', # noqa }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', # noqa }, ] # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(PROJECT_DIR, "../static") ] INTERNAL_IPS = ['127.0.0.1'] throttle_rates = {} throttling = swh_web_config['throttling'] for limiter_scope, limiter_conf in throttling['scopes'].items(): throttle_rates[limiter_scope] = limiter_conf['limiter_rate'] REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', 'swh.web.api.renderers.YAMLRenderer', 'rest_framework.renderers.TemplateHTMLRenderer' ), 'DEFAULT_THROTTLE_CLASSES': ( 'swh.web.common.throttling.SwhWebRateThrottle', ), 'DEFAULT_THROTTLE_RATES': throttle_rates } LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'filters': { 'require_debug_false': { '()': 'django.utils.log.RequireDebugFalse', }, 'require_debug_true': { '()': 'django.utils.log.RequireDebugTrue', }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', }, 'file': { 'level': 'INFO', 'filters': ['require_debug_false'], 'class': 'logging.FileHandler', 'filename': os.path.join(swh_web_config['log_dir'], 'swh-web.log'), }, }, 'loggers': { 'django': { 'handlers': ['console', 'file'], 'level': 'DEBUG' if DEBUG else 'INFO', 'propagate': True, } }, } diff --git a/swh/web/settings/development.py b/swh/web/settings/development.py index eb931812..9306877b 100644 --- a/swh/web/settings/development.py +++ b/swh/web/settings/development.py @@ -1,7 +1,10 @@ # Copyright (C) 2017 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information from .common import * # noqa + +from django.core.cache import cache +cache.clear() diff --git a/swh/web/settings/production.py b/swh/web/settings/production.py index 2c8f6b50..9dcec89d 100644 --- a/swh/web/settings/production.py +++ b/swh/web/settings/production.py @@ -1,21 +1,25 @@ # Copyright (C) 2017 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information - from .common import * # noqa from .common import swh_web_config +# activate per-site caching +MIDDLEWARE += ['django.middleware.cache.UpdateCacheMiddleware', # noqa + 'django.middleware.common.CommonMiddleware', + 'django.middleware.cache.FetchFromCacheMiddleware'] + CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': swh_web_config['throttling']['cache_uri'], } } # Setup support for proxy headers USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') ALLOWED_HOSTS += ['archive.softwareheritage.org'] # noqa diff --git a/swh/web/templates/apidoc.html b/swh/web/templates/apidoc.html index 753eb1a6..8bb02235 100644 --- a/swh/web/templates/apidoc.html +++ b/swh/web/templates/apidoc.html @@ -1,149 +1,149 @@ {% extends "layout.html" %} {% load swh_templatetags %} {% load static %} {% block title %}{{ heading }} – Software Heritage API {% endblock %} {% block header %} - + {% endblock %} {% block content %} {% if docstring %}
{{ request.method }} {{ request.build_absolute_uri }}+
{{ request.method }} {{ request.absolute_uri }}
{{ status_code }}{% endif %} {% if headers_data %}
{{ header_name }} {{ header_value | urlize_header_links | safe }}{% endfor %} {% endif %}
{{ response_data | urlize_links_and_mails | safe }}
URL | Allowed Methods |
---|---|
{{ url.rule }} | {{ url.methods | dictsort:0 | join:', ' }} |
')
self.assertContains(resp, escape(stub_content_text_data['raw_data']))
self.assertContains(resp, url_raw)
@patch('swh.web.browse.views.content.request_content')
@istest
def content_view_text_no_highlight(self, mock_request_content):
mock_request_content.return_value = stub_content_text_no_highlight_data
url = reverse('browse-content',
kwargs={'query_string': stub_content_text_no_highlight_data['checksums']['sha1']}) # noqa
url_raw = reverse('browse-content-raw',
kwargs={'query_string': stub_content_text_no_highlight_data['checksums']['sha1']}) # noqa
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('content.html')
self.assertContains(resp, '')
self.assertContains(resp, escape(stub_content_text_no_highlight_data['raw_data'])) # noqa
self.assertContains(resp, url_raw)
@patch('swh.web.browse.utils.service')
@istest
def content_view_no_utf8_text(self, mock_service):
mock_service.lookup_content.return_value = \
non_utf8_encoded_content_data
mock_service.lookup_content_raw.return_value = \
{'data': non_utf8_encoded_content}
mock_service.lookup_content_filetype.return_value = None
mock_service.lookup_content_language.return_value = None
mock_service.lookup_content_license.return_value = None
url = reverse('browse-content',
kwargs={'query_string': non_utf8_encoded_content_data['checksums']['sha1']}) # noqa
try:
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('content.html')
self.assertContains(resp, escape(non_utf8_encoded_content.decode(non_utf8_encoding).encode('utf-8'))) # noqa
except DjangoUnicodeDecodeError:
self.fail('Textual content is not encoded in utf-8')
@patch('swh.web.browse.views.content.request_content')
@istest
def content_view_image(self, mock_request_content):
mime_type = 'image/png'
mock_request_content.return_value = stub_content_bin_data
url = reverse('browse-content',
kwargs={'query_string': stub_content_bin_data['checksums']['sha1']}) # noqa
url_raw = reverse('browse-content-raw',
kwargs={'query_string': stub_content_bin_data['checksums']['sha1']}) # noqa
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('content.html')
pngEncoded = base64.b64encode(stub_content_bin_data['raw_data']) \
.decode('utf-8')
self.assertContains(resp, '
'
% (mime_type, pngEncoded))
self.assertContains(resp, url_raw)
@patch('swh.web.browse.views.content.request_content')
@istest
def content_view_with_path(self, mock_request_content):
mock_request_content.return_value = stub_content_text_data
url = reverse('browse-content',
kwargs={'query_string': stub_content_text_data['checksums']['sha1']}, # noqa
query_params={'path': stub_content_text_path_with_root_dir}) # noqa
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('content.html')
self.assertContains(resp, '')
self.assertContains(resp, escape(stub_content_text_data['raw_data']))
split_path = stub_content_text_path_with_root_dir.split('/')
root_dir_sha1 = split_path[0]
filename = split_path[-1]
path = stub_content_text_path_with_root_dir \
.replace(root_dir_sha1 + '/', '') \
.replace(filename, '')
path_info = gen_path_info(path)
root_dir_url = reverse('browse-directory',
kwargs={'sha1_git': root_dir_sha1})
self.assertContains(resp, '',
count=len(path_info)+1)
self.assertContains(resp, '' +
root_dir_sha1[:7] + '')
for p in path_info:
dir_url = reverse('browse-directory',
kwargs={'sha1_git': root_dir_sha1,
'path': p['path']})
self.assertContains(resp, '' +
p['name'] + '')
self.assertContains(resp, ' ' + filename + ' ')
url_raw = reverse('browse-content-raw',
kwargs={'query_string': stub_content_text_data['checksums']['sha1']}, # noqa
query_params={'filename': filename})
self.assertContains(resp, url_raw)
@patch('swh.web.browse.views.content.request_content')
@istest
def test_content_raw_text(self, mock_request_content):
mock_request_content.return_value = stub_content_text_data
url = reverse('browse-content-raw',
kwargs={'query_string': stub_content_text_data['checksums']['sha1']}) # noqa
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertEqual(resp['Content-Type'], 'text/plain')
self.assertEqual(resp['Content-disposition'],
'filename=%s_%s' % ('sha1', stub_content_text_data['checksums']['sha1'])) # noqa
self.assertEqual(resp.content, stub_content_text_data['raw_data'])
filename = stub_content_text_path_with_root_dir.split('/')[-1]
url = reverse('browse-content-raw',
kwargs={'query_string': stub_content_text_data['checksums']['sha1']}, # noqa
query_params={'filename': filename})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertEqual(resp['Content-Type'], 'text/plain')
self.assertEqual(resp['Content-disposition'],
'filename=%s' % filename)
self.assertEqual(resp.content, stub_content_text_data['raw_data'])
@patch('swh.web.browse.views.content.request_content')
@istest
def content_raw_bin(self, mock_request_content):
mock_request_content.return_value = stub_content_bin_data
url = reverse('browse-content-raw',
kwargs={'query_string': stub_content_bin_data['checksums']['sha1']}) # noqa
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertEqual(resp['Content-Type'], 'application/octet-stream')
self.assertEqual(resp['Content-disposition'],
'attachment; filename=%s_%s' %
('sha1', stub_content_bin_data['checksums']['sha1']))
self.assertEqual(resp.content, stub_content_bin_data['raw_data'])
url = reverse('browse-content-raw',
kwargs={'query_string': stub_content_bin_data['checksums']['sha1']}, # noqa
query_params={'filename': stub_content_bin_filename})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertEqual(resp['Content-Type'], 'application/octet-stream')
self.assertEqual(resp['Content-disposition'],
'attachment; filename=%s' % stub_content_bin_filename)
self.assertEqual(resp.content, stub_content_bin_data['raw_data'])
@patch('swh.web.browse.views.content.request_content')
@istest
def content_request_errors(self, mock_request_content):
url = reverse('browse-content', kwargs={'query_string': '123456'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 400)
self.assertTemplateUsed('error.html')
mock_request_content.side_effect = NotFoundExc('content not found')
url = reverse('browse-content',
kwargs={'query_string': stub_content_text_data['checksums']['sha1']}) # noqa
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
diff --git a/swh/web/tests/browse/views/test_directory.py b/swh/web/tests/browse/views/test_directory.py
index 68f45b1d..bd96ae29 100644
--- a/swh/web/tests/browse/views/test_directory.py
+++ b/swh/web/tests/browse/views/test_directory.py
@@ -1,126 +1,128 @@
# Copyright (C) 2017 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from unittest.mock import patch
from nose.tools import istest, nottest
from django.test import TestCase
from swh.web.common.exc import BadInputExc, NotFoundExc
from swh.web.common.utils import reverse
from swh.web.browse.utils import gen_path_info
+from swh.web.tests.testbase import SWHWebTestBase
+
from .data.directory_test_data import (
stub_root_directory_sha1, stub_root_directory_data,
stub_sub_directory_path, stub_sub_directory_data
)
-class SwhBrowseDirectoryTest(TestCase):
+class SwhBrowseDirectoryTest(SWHWebTestBase, TestCase):
@nottest
def directory_view(self, root_directory_sha1, directory_entries,
path=None):
dirs = [e for e in directory_entries if e['type'] == 'dir']
files = [e for e in directory_entries if e['type'] == 'file']
url_args = {'sha1_git': root_directory_sha1}
if path:
url_args['path'] = path
url = reverse('browse-directory',
kwargs=url_args)
root_dir_url = reverse('browse-directory',
kwargs={'sha1_git': root_directory_sha1})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('directory.html')
self.assertContains(resp, '' +
root_directory_sha1[:7] + '')
self.assertContains(resp, '',
count=len(dirs))
self.assertContains(resp, ' ',
count=len(files))
for d in dirs:
dir_path = d['name']
if path:
dir_path = "%s/%s" % (path, d['name'])
dir_url = reverse('browse-directory',
kwargs={'sha1_git': root_directory_sha1,
'path': dir_path})
self.assertContains(resp, dir_url)
for f in files:
file_path = "%s/%s" % (root_directory_sha1, f['name'])
if path:
file_path = "%s/%s/%s" % (root_directory_sha1, path, f['name'])
query_string = 'sha1_git:' + f['target']
file_url = reverse('browse-content',
kwargs={'query_string': query_string},
query_params={'path': file_path})
self.assertContains(resp, file_url)
path_info = gen_path_info(path)
self.assertContains(resp, '',
count=len(path_info)+1)
self.assertContains(resp, '%s' %
(root_dir_url, root_directory_sha1[:7]))
for p in path_info:
dir_url = reverse('browse-directory',
kwargs={'sha1_git': root_directory_sha1,
'path': p['path']})
self.assertContains(resp, '%s' %
(dir_url, p['name']))
@patch('swh.web.browse.utils.service')
@istest
def root_directory_view(self, mock_service):
mock_service.lookup_directory.return_value = \
stub_root_directory_data
self.directory_view(stub_root_directory_sha1, stub_root_directory_data)
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.directory.service')
@istest
def sub_directory_view(self, mock_directory_service, mock_utils_service):
mock_utils_service.lookup_directory.return_value = \
stub_sub_directory_data
mock_directory_service.lookup_directory_with_path.return_value = \
{'target': '120c39eeb566c66a77ce0e904d29dfde42228adc'}
self.directory_view(stub_root_directory_sha1, stub_sub_directory_data,
stub_sub_directory_path)
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.directory.service')
@istest
def directory_request_errors(self, mock_directory_service,
mock_utils_service):
mock_utils_service.lookup_directory.side_effect = \
BadInputExc('directory not found')
dir_url = reverse('browse-directory',
kwargs={'sha1_git': '1253456'})
resp = self.client.get(dir_url)
self.assertEquals(resp.status_code, 400)
self.assertTemplateUsed('error.html')
mock_utils_service.lookup_directory.side_effect = \
NotFoundExc('directory not found')
dir_url = reverse('browse-directory',
kwargs={'sha1_git': '1253456'})
resp = self.client.get(dir_url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
diff --git a/swh/web/tests/browse/views/test_origin.py b/swh/web/tests/browse/views/test_origin.py
index 3714a314..6f0d749c 100644
--- a/swh/web/tests/browse/views/test_origin.py
+++ b/swh/web/tests/browse/views/test_origin.py
@@ -1,499 +1,500 @@
# Copyright (C) 2017 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from unittest.mock import patch
from nose.tools import istest, nottest
from django.test import TestCase
from django.utils.html import escape
from swh.web.common.exc import NotFoundExc
from swh.web.common.utils import reverse
+from swh.web.tests.testbase import SWHWebTestBase
from .data.origin_test_data import (
origin_info_test_data,
origin_visits_test_data,
stub_content_origin_id, stub_content_origin_visit_id,
stub_content_origin_visit_unix_ts, stub_content_origin_visit_iso_date,
stub_content_origin_branch,
stub_content_origin_visits, stub_content_origin_branches,
stub_origin_id, stub_visit_id,
stub_origin_visits, stub_origin_branches,
stub_origin_root_directory_entries, stub_origin_master_branch,
stub_origin_root_directory_sha1, stub_origin_sub_directory_path,
stub_origin_sub_directory_entries, stub_visit_unix_ts, stub_visit_iso_date
)
from .data.content_test_data import (
stub_content_root_dir,
stub_content_text_data,
stub_content_text_path
)
from swh.web.browse.utils import (
gen_path_info
)
-class SwhBrowseOriginTest(TestCase):
+class SwhBrowseOriginTest(SWHWebTestBase, TestCase):
@patch('swh.web.browse.views.origin.get_origin_visits')
@patch('swh.web.browse.views.origin.service')
@istest
def test_origin_browse(self, mock_service, mock_get_origin_visits):
mock_service.lookup_origin.return_value = origin_info_test_data
mock_get_origin_visits.return_value = origin_visits_test_data
url = reverse('browse-origin',
kwargs={'origin_id': origin_info_test_data['id']})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('origin.html')
self.assertContains(resp, '%s ' % origin_info_test_data['id'])
self.assertContains(resp, '%s
' % origin_info_test_data['type']) # noqa
self.assertContains(resp, '%s
' %
(origin_info_test_data['url'],
origin_info_test_data['url']))
self.assertContains(resp, '',
count=len(origin_visits_test_data))
for visit in origin_visits_test_data:
browse_url = reverse('browse-origin-directory',
kwargs={'origin_id': visit['origin'],
'visit_id': visit['visit']})
self.assertContains(resp, '%s ' %
(browse_url, browse_url))
@nottest
def origin_content_view_test(self, origin_id, origin_visits,
origin_branches, origin_branch,
root_dir_sha1, content_sha1,
content_path, content_data,
content_language,
visit_id=None, ts=None):
url_args = {'origin_id': origin_id,
'path': content_path}
if not visit_id:
visit_id = origin_visits[-1]['visit']
if ts:
url_args['timestamp'] = ts
else:
url_args['visit_id'] = visit_id
url = reverse('browse-origin-content',
kwargs=url_args)
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('content.html')
self.assertContains(resp, '' % content_language)
self.assertContains(resp, escape(content_data))
split_path = content_path.split('/')
filename = split_path[-1]
path = content_path.replace(filename, '')[:-1]
path_info = gen_path_info(path)
del url_args['path']
root_dir_url = reverse('browse-origin-directory',
kwargs=url_args,
query_params={'branch': origin_branch})
self.assertContains(resp, '',
count=len(path_info)+1)
self.assertContains(resp, '%s' %
(root_dir_url, root_dir_sha1[:7]))
for p in path_info:
url_args['path'] = p['path']
dir_url = reverse('browse-origin-directory',
kwargs=url_args,
query_params={'branch': origin_branch})
self.assertContains(resp, '%s' %
(dir_url, p['name']))
self.assertContains(resp, ' %s ' % filename)
query_string = 'sha1_git:' + content_sha1
url_raw = reverse('browse-content-raw',
kwargs={'query_string': query_string},
query_params={'filename': filename})
self.assertContains(resp, url_raw)
self.assertContains(resp, '',
count=len(origin_branches))
url_args['path'] = content_path
for branch in origin_branches:
root_dir_branch_url = \
reverse('browse-origin-content',
kwargs=url_args,
query_params={'branch': branch['name']})
self.assertContains(resp, '%s' %
(root_dir_branch_url, branch['name']))
@patch('swh.web.browse.views.origin.get_origin_visits')
@patch('swh.web.browse.views.origin.get_origin_visit_branches')
@patch('swh.web.browse.views.origin.service')
@patch('swh.web.browse.views.origin.request_content')
@istest
def origin_content_view(self, mock_request_content, mock_service,
mock_get_origin_visit_branches,
mock_get_origin_visits):
stub_content_text_sha1 = stub_content_text_data['checksums']['sha1']
mock_get_origin_visits.return_value = stub_content_origin_visits
mock_get_origin_visit_branches.return_value = stub_content_origin_branches # noqa
mock_service.lookup_directory_with_path.return_value = \
{'target': stub_content_text_sha1}
mock_request_content.return_value = stub_content_text_data
self.origin_content_view_test(stub_content_origin_id,
stub_content_origin_visits,
stub_content_origin_branches,
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp')
self.origin_content_view_test(stub_content_origin_id,
stub_content_origin_visits,
stub_content_origin_branches,
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp',
visit_id=stub_content_origin_visit_id)
self.origin_content_view_test(stub_content_origin_id,
stub_content_origin_visits,
stub_content_origin_branches,
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp',
ts=stub_content_origin_visit_unix_ts)
self.origin_content_view_test(stub_content_origin_id,
stub_content_origin_visits,
stub_content_origin_branches,
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp',
ts=stub_content_origin_visit_iso_date)
@nottest
def origin_directory_view(self, origin_id, origin_visits,
origin_branches, origin_branch,
root_directory_sha1, directory_entries,
visit_id=None, ts=None, path=None):
dirs = [e for e in directory_entries
if e['type'] == 'dir']
files = [e for e in directory_entries
if e['type'] == 'file']
if not visit_id:
visit_id = origin_visits[-1]['visit']
url_args = {'origin_id': origin_id}
if ts:
url_args['timestamp'] = ts
else:
url_args['visit_id'] = visit_id
if path:
url_args['path'] = path
url = reverse('browse-origin-directory',
kwargs=url_args)
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('directory.html')
self.assertContains(resp, '',
count=len(dirs))
self.assertContains(resp, ' ',
count=len(files))
for d in dirs:
dir_path = d['name']
if path:
dir_path = "%s/%s" % (path, d['name'])
dir_url_args = dict(url_args)
dir_url_args['path'] = dir_path
dir_url = reverse('browse-origin-directory',
kwargs=dir_url_args,
query_params={'branch': origin_branch}) # noqa
self.assertContains(resp, dir_url)
for f in files:
file_path = f['name']
if path:
file_path = "%s/%s" % (path, f['name'])
file_url_args = dict(url_args)
file_url_args['path'] = file_path
file_url = reverse('browse-origin-content',
kwargs=file_url_args,
query_params={'branch': origin_branch}) # noqa
self.assertContains(resp, file_url)
if 'path' in url_args:
del url_args['path']
root_dir_branch_url = \
reverse('browse-origin-directory',
kwargs=url_args,
query_params={'branch': origin_branch})
nb_bc_paths = 1
if path:
nb_bc_paths = len(path.split('/')) + 1
self.assertContains(resp, '', count=nb_bc_paths)
self.assertContains(resp, '%s' %
(root_dir_branch_url,
root_directory_sha1[:7]))
self.assertContains(resp, ' ',
count=len(origin_branches))
if path:
url_args['path'] = path
for branch in origin_branches:
root_dir_branch_url = \
reverse('browse-origin-directory',
kwargs=url_args,
query_params={'branch': branch['name']})
self.assertContains(resp, '%s' %
(root_dir_branch_url, branch['name']))
@patch('swh.web.browse.views.origin.get_origin_visits')
@patch('swh.web.browse.views.origin.get_origin_visit_branches')
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.origin.service')
@istest
def origin_root_directory_view(self, mock_origin_service,
mock_utils_service,
mock_get_origin_visit_branches,
mock_get_origin_visits):
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_branches.return_value = stub_origin_branches
mock_utils_service.lookup_directory.return_value = \
stub_origin_root_directory_entries
mock_origin_service.lookup_origin.return_value = origin_info_test_data
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries)
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries,
visit_id=stub_visit_id)
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries,
ts=stub_visit_unix_ts)
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries,
ts=stub_visit_iso_date)
@patch('swh.web.browse.views.origin.get_origin_visits')
@patch('swh.web.browse.views.origin.get_origin_visit_branches')
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.origin.service')
@istest
def origin_sub_directory_view(self, mock_origin_service,
mock_utils_service,
mock_get_origin_visit_branches,
mock_get_origin_visits):
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_branches.return_value = stub_origin_branches
mock_utils_service.lookup_directory.return_value = \
stub_origin_sub_directory_entries
mock_origin_service.lookup_directory_with_path.return_value = \
{'target': '120c39eeb566c66a77ce0e904d29dfde42228adb'}
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
path=stub_origin_sub_directory_path)
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
visit_id=stub_visit_id,
path=stub_origin_sub_directory_path)
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
ts=stub_visit_unix_ts,
path=stub_origin_sub_directory_path)
self.origin_directory_view(stub_origin_id, stub_origin_visits,
stub_origin_branches,
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
ts=stub_visit_iso_date,
path=stub_origin_sub_directory_path)
@patch('swh.web.browse.views.origin.request_content')
@patch('swh.web.browse.views.origin.get_origin_visits')
@patch('swh.web.browse.views.origin.get_origin_visit_branches')
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.origin.service')
@istest
def origin_request_errors(self, mock_origin_service,
mock_utils_service,
mock_get_origin_visit_branches,
mock_get_origin_visits,
mock_request_content):
mock_origin_service.lookup_origin.side_effect = \
NotFoundExc('origin not found')
url = reverse('browse-origin',
kwargs={'origin_id': '1'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, "origin not found", status_code=404)
mock_origin_service.lookup_origin.side_effect = None
mock_origin_service.lookup_origin.return_value = origin_info_test_data
mock_get_origin_visits.return_value = []
url = reverse('browse-origin-directory',
kwargs={'origin_id': '1'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, "No SWH visit", status_code=404)
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_branches.side_effect = \
NotFoundExc('visit not found')
url = reverse('browse-origin-directory',
kwargs={'origin_id': '1',
'visit_id': len(stub_origin_visits)+1})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'visit not found', status_code=404)
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_branches.side_effect = None
mock_get_origin_visit_branches.return_value = []
url = reverse('browse-origin-directory',
kwargs={'origin_id': '1'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertRegex(resp.content.decode('utf-8'),
'Branch HEAD.*not found')
mock_get_origin_visit_branches.return_value = stub_origin_branches
mock_utils_service.lookup_directory.side_effect = \
NotFoundExc('Directory not found')
url = reverse('browse-origin-directory',
kwargs={'origin_id': '1'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'Directory not found', status_code=404)
mock_origin_service.lookup_origin.side_effect = None
mock_origin_service.lookup_origin.return_value = origin_info_test_data
mock_get_origin_visits.return_value = []
url = reverse('browse-origin-content',
kwargs={'origin_id': '1',
'path': 'foo'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, "No SWH visit", status_code=404)
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_branches.side_effect = \
NotFoundExc('visit not found')
url = reverse('browse-origin-content',
kwargs={'origin_id': '1',
'visit_id': len(stub_origin_visits)+1,
'path': 'foo'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'visit not found', status_code=404)
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_branches.side_effect = None
mock_get_origin_visit_branches.return_value = []
url = reverse('browse-origin-content',
kwargs={'origin_id': '1',
'path': 'foo'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertRegex(resp.content.decode('utf-8'),
'Branch HEAD.*not found')
mock_get_origin_visit_branches.return_value = stub_origin_branches
mock_origin_service.lookup_directory_with_path.return_value = \
{'target': stub_content_text_data['checksums']['sha1']}
mock_request_content.side_effect = \
NotFoundExc('Content not found')
url = reverse('browse-origin-content',
kwargs={'origin_id': '1',
'path': 'foo'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'Content not found', status_code=404)
diff --git a/swh/web/tests/browse/views/test_person.py b/swh/web/tests/browse/views/test_person.py
index 416c0365..e031fff6 100644
--- a/swh/web/tests/browse/views/test_person.py
+++ b/swh/web/tests/browse/views/test_person.py
@@ -1,55 +1,56 @@
# Copyright (C) 2017 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from unittest.mock import patch
from nose.tools import istest
from django.test import TestCase
from swh.web.common.exc import NotFoundExc
from swh.web.common.utils import reverse
+from swh.web.tests.testbase import SWHWebTestBase
-class SwhBrowsePersonTest(TestCase):
+class SwhBrowsePersonTest(SWHWebTestBase, TestCase):
@patch('swh.web.browse.views.person.service')
@istest
def person_browse(self, mock_service):
test_person_data = \
{
"email": "j.adams440@gmail.com",
"fullname": "oysterCrusher ",
"id": 457587,
"name": "oysterCrusher"
}
mock_service.lookup_person.return_value = test_person_data
url = reverse('browse-person', kwargs={'person_id': 457587})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('person.html')
self.assertContains(resp, '%s
' % test_person_data['id'])
self.assertContains(resp, '%s
' % test_person_data['name'])
self.assertContains(resp, '%s
' %
(test_person_data['email'],
test_person_data['email']))
self.assertContains(resp, '%s <%s>
' % # noqa
(test_person_data['name'],
test_person_data['email'],
test_person_data['email']))
@patch('swh.web.browse.views.person.service')
@istest
def person_request_error(self, mock_service):
mock_service.lookup_person.side_effect = \
NotFoundExc('Person not found')
url = reverse('browse-person', kwargs={'person_id': 457587})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'Person not found', status_code=404)
diff --git a/swh/web/tests/browse/views/test_revision.py b/swh/web/tests/browse/views/test_revision.py
index cf8debed..430548b0 100644
--- a/swh/web/tests/browse/views/test_revision.py
+++ b/swh/web/tests/browse/views/test_revision.py
@@ -1,199 +1,200 @@
# Copyright (C) 2017 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
from unittest.mock import patch
from nose.tools import istest
from django.test import TestCase
from django.utils.html import escape
from swh.web.common.exc import NotFoundExc
from swh.web.common.utils import reverse, format_utc_iso_date
+from swh.web.tests.testbase import SWHWebTestBase
from .data.revision_test_data import (
revision_id_test, revision_metadata_test,
revision_history_log_test
)
-class SwhBrowseRevisionTest(TestCase):
+class SwhBrowseRevisionTest(SWHWebTestBase, TestCase):
@patch('swh.web.browse.views.revision.service')
@istest
def revision_browse(self, mock_service):
mock_service.lookup_revision.return_value = revision_metadata_test
url = reverse('browse-revision',
kwargs={'sha1_git': revision_id_test})
author_id = revision_metadata_test['author']['id']
author_name = revision_metadata_test['author']['name']
committer_id = revision_metadata_test['committer']['id']
committer_name = revision_metadata_test['committer']['name']
dir_id = revision_metadata_test['directory']
author_url = reverse('browse-person',
kwargs={'person_id': author_id})
committer_url = reverse('browse-person',
kwargs={'person_id': committer_id})
directory_url = reverse('browse-directory',
kwargs={'sha1_git': dir_id})
history_url = reverse('browse-revision-log',
kwargs={'sha1_git': revision_id_test})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('revision.html')
self.assertContains(resp, '%s' %
(author_url, author_name))
self.assertContains(resp, '%s' %
(committer_url, committer_name))
self.assertContains(resp, '%s' %
(directory_url, dir_id))
self.assertContains(resp, '%s' %
(history_url, history_url))
for parent in revision_metadata_test['parents']:
parent_url = reverse('browse-revision',
kwargs={'sha1_git': parent})
self.assertContains(resp, '%s' %
(parent_url, parent))
author_date = revision_metadata_test['date']
committer_date = revision_metadata_test['committer_date']
message = revision_metadata_test['message']
self.assertContains(resp, format_utc_iso_date(author_date))
self.assertContains(resp, format_utc_iso_date(committer_date))
self.assertContains(resp, message)
@patch('swh.web.browse.views.revision.service')
@istest
def revision_log_browse(self, mock_service):
per_page = 10
mock_service.lookup_revision_log.return_value = \
revision_history_log_test[:per_page+1]
url = reverse('browse-revision-log',
kwargs={'sha1_git': revision_id_test},
query_params={'per_page': per_page})
resp = self.client.get(url)
prev_rev = revision_history_log_test[per_page]['id']
next_page_url = reverse('browse-revision-log',
kwargs={'sha1_git': prev_rev},
query_params={'revs_breadcrumb': revision_id_test, # noqa
'per_page': per_page})
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('revision-log.html')
self.assertContains(resp, '',
count=per_page)
self.assertContains(resp, 'Newer ')
self.assertContains(resp, 'Older ' %
escape(next_page_url))
for log in revision_history_log_test[:per_page]:
author_url = reverse('browse-person',
kwargs={'person_id': log['author']['id']})
revision_url = reverse('browse-revision',
kwargs={'sha1_git': log['id']})
directory_url = reverse('browse-directory',
kwargs={'sha1_git': log['directory']})
self.assertContains(resp, '%s' %
(author_url, log['author']['name']))
self.assertContains(resp, '%s' %
(revision_url, log['id'][:7]))
self.assertContains(resp, '%s' %
(directory_url, 'Tree'))
mock_service.lookup_revision_log.return_value = \
revision_history_log_test[per_page:2*per_page+1]
resp = self.client.get(next_page_url)
prev_prev_rev = revision_history_log_test[2*per_page]['id']
prev_page_url = reverse('browse-revision-log',
kwargs={'sha1_git': revision_id_test},
query_params={'per_page': per_page})
next_page_url = reverse('browse-revision-log',
kwargs={'sha1_git': prev_prev_rev},
query_params={'revs_breadcrumb': revision_id_test + '/' + prev_rev, # noqa
'per_page': per_page})
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('revision-log.html')
self.assertContains(resp, ' ',
count=per_page)
self.assertContains(resp, 'Newer ' %
escape(prev_page_url))
self.assertContains(resp, 'Older ' %
escape(next_page_url))
mock_service.lookup_revision_log.return_value = \
revision_history_log_test[2*per_page:3*per_page+1]
resp = self.client.get(next_page_url)
prev_prev_prev_rev = revision_history_log_test[3*per_page]['id']
prev_page_url = reverse('browse-revision-log',
kwargs={'sha1_git': prev_rev},
query_params={'revs_breadcrumb': revision_id_test, # noqa
'per_page': per_page})
next_page_url = reverse('browse-revision-log',
kwargs={'sha1_git': prev_prev_prev_rev},
query_params={'revs_breadcrumb': revision_id_test + '/' + prev_rev + '/' + prev_prev_rev, # noqa
'per_page': per_page})
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('revision-log.html')
self.assertContains(resp, ' ',
count=per_page)
self.assertContains(resp, 'Newer ' %
escape(prev_page_url))
self.assertContains(resp, 'Older ' %
escape(next_page_url))
mock_service.lookup_revision_log.return_value = \
revision_history_log_test[3*per_page:3*per_page+per_page//2]
resp = self.client.get(next_page_url)
prev_page_url = reverse('browse-revision-log',
kwargs={'sha1_git': prev_prev_rev},
query_params={'revs_breadcrumb': revision_id_test + '/' + prev_rev, # noqa
'per_page': per_page})
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('revision-log.html')
self.assertContains(resp, ' ',
count=per_page//2)
self.assertContains(resp, 'Older ')
self.assertContains(resp, 'Newer ' %
escape(prev_page_url))
@patch('swh.web.browse.views.revision.service')
@istest
def revision_request_errors(self, mock_service):
mock_service.lookup_revision.side_effect = \
NotFoundExc('Revision not found')
url = reverse('browse-revision',
kwargs={'sha1_git': revision_id_test})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'Revision not found', status_code=404)
mock_service.lookup_revision_log.side_effect = \
NotFoundExc('Revision not found')
url = reverse('browse-revision-log',
kwargs={'sha1_git': revision_id_test})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'Revision not found', status_code=404)
diff --git a/swh/web/tests/api/swh_api_testcase.py b/swh/web/tests/testbase.py
similarity index 77%
rename from swh/web/tests/api/swh_api_testcase.py
rename to swh/web/tests/testbase.py
index 4a59e3dc..bc312b1c 100644
--- a/swh/web/tests/api/swh_api_testcase.py
+++ b/swh/web/tests/testbase.py
@@ -1,70 +1,69 @@
# Copyright (C) 2015-2016 The Software Heritage developers
# See the AUTHORS file at the top-level directory of this distribution
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information
# Functions defined here are NOT DESIGNED FOR PRODUCTION
-from rest_framework.test import APITestCase
+from django.core.cache import cache
from swh.storage.api.client import RemoteStorage as Storage
from swh.web import config
# Because the Storage's __init__ function does side effect at startup...
class RemoteStorageAdapter(Storage):
def __init__(self, base_url):
self.base_url = base_url
def _init_mock_storage(base_url='https://somewhere.org:4321'):
"""Instanciate a remote storage whose goal is to be mocked in a test
context.
NOT FOR PRODUCTION
Returns:
An instance of swh.storage.api.client.RemoteStorage destined to be
mocked (it does not do any rest call)
"""
return RemoteStorageAdapter(base_url) # destined to be used as mock
def create_config(base_url='https://somewhere.org:4321'):
- """Function to initiate a flask app with storage designed to be mocked.
+ """Function to initiate swh-web config with storage designed to be mocked.
Returns:
- Tuple:
- - app test client (for testing api, client decorator from flask)
- - application's full configuration
- - the storage instance to stub and mock
- - the main app without any decoration
+ dict containing swh-web config for tests
NOT FOR PRODUCTION
"""
storage = _init_mock_storage(base_url)
swh_config = config.get_config()
# inject the mock data
swh_config.update({'storage': storage})
return swh_config
-class SWHApiTestCase(APITestCase):
+class SWHWebTestBase(object):
"""Testing API class.
"""
@classmethod
def setUpClass(cls):
- super(SWHApiTestCase, cls).setUpClass()
+ super(SWHWebTestBase, cls).setUpClass()
cls.test_config = create_config()
cls.maxDiff = None
@classmethod
def storage(cls):
return cls.test_config['storage']
+
+ def setUp(self):
+ cache.clear()