Merge branch 'master' of python/django-test into production
All checks were successful
buildbot/python3-test Build done.
buildbot/python2-test Build done.

This commit was merged in pull request #9.
This commit is contained in:
2019-10-25 11:46:41 +02:00
committed by Gitea
16 changed files with 160 additions and 45 deletions

View File

@@ -1,5 +1,6 @@
python_major_version=`python -c 'import sys; print sys.version_info.major'` python_major_version=`python -c 'import sys; print sys.version_info.major'`
if test "$python_major_version" = "2" ; then if test "$python_major_version" = "2" ; then
pip install 'django<2' pip install 'django<2'
pip install 'pylint-django<2'
fi fi
pip install -r requirements.txt pip install -r requirements-test.txt

View File

@@ -1 +1 @@
python manage.py test coverage run manage.py test

View File

@@ -0,0 +1 @@
coverage report --skip-covered --fail-under=99

View File

@@ -0,0 +1 @@
pylint apps.base

View File

@@ -1,2 +1,3 @@
[run] [run]
source = base source = apps.base
omit = apps/base/tests/utils.py

27
.pylintrc Normal file
View File

@@ -0,0 +1,27 @@
[MASTER]
persistent=no
#load-plugins=pylint_django
[MESSAGES CONTROL]
disable=missing-docstring,
missing-module-docstring,
missing-class-docstring,
missing-function-docstring,
useless-object-inheritance,
[BASIC]
good-names=_,
c,
d,
e,
i,
j,
k,
[FORMAT]
max-line-length=120

View File

@@ -6,7 +6,7 @@ from django.test import SimpleTestCase
class BaseTemplateTestCase(SimpleTestCase): class BaseTemplateTestCase(SimpleTestCase):
def assertInHTML_multi(self, response, needles, format_kwargs=None): def assertInHTMLMulti(self, response, needles, format_kwargs=None): # pylint: disable=invalid-name
content = response.content.decode('utf-8') content = response.content.decode('utf-8')
for needle in needles: for needle in needles:
if format_kwargs is not None: if format_kwargs is not None:
@@ -35,7 +35,7 @@ class BaseTemplateTestCase(SimpleTestCase):
'<link type="text/css" href="{static_url}{base_prefix}css/local.css" rel="stylesheet" />', '<link type="text/css" href="{static_url}{base_prefix}css/local.css" rel="stylesheet" />',
) )
self.assertInHTML_multi(response, needles, format_kwargs) self.assertInHTMLMulti(response, needles, format_kwargs)
def test_bootstrap_css_links(self): def test_bootstrap_css_links(self):
response = self.response response = self.response
@@ -55,7 +55,7 @@ class BaseTemplateTestCase(SimpleTestCase):
'<script type="text/javascript" src="{static_url}{base_prefix}bootstrap/js/bootstrap.min.js"></script>', '<script type="text/javascript" src="{static_url}{base_prefix}bootstrap/js/bootstrap.min.js"></script>',
) )
self.assertInHTML_multi(response, needles, format_kwargs) self.assertInHTMLMulti(response, needles, format_kwargs)
def test_page_footer(self): def test_page_footer(self):
response = self.response response = self.response

View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.test import SimpleTestCase
from django.urls import reverse
class UrlsTestCase(SimpleTestCase):
def test_root_reverse(self):
response = self.client.get(reverse('root'))
self.assertEqual(response.status_code, 200)

View File

@@ -1,31 +1,82 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime
import re
import socket import socket
import unittest
import mock
from django.test import SimpleTestCase from django.test import SimpleTestCase
from ..views import RootView
class DjangoAdminTestCase(SimpleTestCase):
class RootUnitTestCase(unittest.TestCase):
def test_get_context_data(self):
default_color_hex = '47825b'
test_data_sets = [
{},
{'hostname': 'localhost'},
{'hostname': 'abcde'},
{'hostname': 'frodo.abcdef.example.com'},
{'hostname': 'aBc-dEf', 'expected_color_hex': 'abcdef'},
{'hostname': 'ab34EF12cd56ZZ', 'expected_color_hex': 'ab34ef'},
{'hostname': 'abcde.example.com', 'expected_color_hex': 'abcdee'},
{'hostname': 'abcdef', 'kwargs': {'color_hex': '123456'}, 'expected_color_hex': '123456'},
]
real_hostname = socket.gethostname()
for test_data in test_data_sets:
if 'hostname' in test_data:
hostname = test_data['hostname']
else:
hostname = real_hostname
if 'expected_color_hex' in test_data:
expected_color_hex = test_data['expected_color_hex']
else:
expected_color_hex = default_color_hex
with mock.patch('socket.gethostname', return_value=hostname):
view = RootView()
if 'kwargs' in test_data:
ctx = view.get_context_data(**test_data['kwargs'])
else:
ctx = view.get_context_data()
self.assertIsInstance(ctx, dict)
self.assertIn('hostname', ctx)
self.assertEqual(ctx['hostname'], hostname)
self.assertIn('color_hex', ctx)
self.assertTrue(re.match('[0-9a-f]{6}', ctx['color_hex']))
self.assertEqual(ctx['color_hex'], expected_color_hex)
self.assertIn('time', ctx)
self.assertIsInstance(ctx['time'], datetime.datetime)
class DjangoAdminDjangoTestCase(SimpleTestCase):
def test_djangoadmin(self): def test_djangoadmin(self):
response = self.client.get('/djangoadmin', follow=True) response = self.client.get('/djangoadmin', follow=True)
self.assertContains(response, 'Django administration') self.assertContains(response, 'Django administration')
class RootTestCase(SimpleTestCase): class RootDjangoTestCase(SimpleTestCase):
def setUp(self):
super(RootTestCase, self).setUp()
self.response = self.client.get('/')
def test_root_template(self): def test_root_template(self):
response = self.response response = self.client.get('/')
self.assertTemplateUsed(response, 'base/root.html') self.assertTemplateUsed(response, 'base/root.html')
def test_root_context(self): def test_root_context(self):
response = self.response response = self.client.get('/')
self.assertIn('hostname', response.context) self.assertIn('hostname', response.context)
hostname = socket.gethostname() hostname = socket.gethostname()
self.assertEqual(response.context['hostname'], hostname) self.assertEqual(response.context['hostname'], hostname)
self.assertIn('color_hex', response.context)
self.assertTrue(re.match('[0-9a-f]{6}', response.context['color_hex']))
self.assertIn('time', response.context)
self.assertIsInstance(response.context['time'], datetime.datetime)
def test_root_content(self): def test_root_content(self):
response = self.response response = self.client.get('/')
hostname = socket.gethostname().capitalize() hostname = socket.gethostname().capitalize()
self.assertContains(response, hostname) self.assertContains(response, hostname)

View File

@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# pylint: skip-file
from __future__ import unicode_literals from __future__ import unicode_literals
import os import os
from tempfile import mkdtemp as _mkdtmp from tempfile import mkdtemp as _mkdtmp

View File

@@ -5,7 +5,7 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [ # pylint: disable=invalid-name
url(r'^$', views.RootView.as_view(), name='root'), url(r'^$', views.RootView.as_view(), name='root'),
url(r'^djangoadmin/', admin.site.urls), url(r'^djangoadmin/', admin.site.urls),
] ]

View File

@@ -8,16 +8,23 @@ from django.views import generic
class RootView(generic.TemplateView): class RootView(generic.TemplateView):
template_name = 'base/root.html' template_name = 'base/root.html'
_default_color_hex = '47825b'
def _get_color_hex(self, hostname=None):
color_hex = self._default_color_hex
if hostname:
buf = hostname
buf = re.sub('[-.]', '', buf)
buf = buf[:6].lower()
if re.match('[0-9a-f]{6}', buf):
color_hex = buf
return color_hex
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
if 'hostname' not in kwargs: if 'hostname' not in kwargs:
kwargs['hostname'] = socket.gethostname() kwargs['hostname'] = socket.gethostname()
if 'color_hex' not in kwargs: if 'color_hex' not in kwargs:
buf = kwargs['hostname'] kwargs['color_hex'] = self._get_color_hex(kwargs['hostname'])
buf = re.sub('[-.]', '', buf)
buf = buf[:6].lower()
if re.match('[0-9a-f]{6}', buf):
kwargs['color_hex'] = buf
if 'time' not in kwargs: if 'time' not in kwargs:
kwargs['time'] = timezone.now() kwargs['time'] = timezone.now()
return super(RootView, self).get_context_data(**kwargs) return super(RootView, self).get_context_data(**kwargs)

View File

@@ -2,22 +2,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import argparse import argparse
import coverage
import datetime import datetime
import os import os
import shutil import shutil
import sys import sys
import time
import coverage
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
class Command(object): class Command(object): # pylint: disable=too-few-public-methods
default_browser = 'firefox' default_browser = 'firefox'
@staticmethod @staticmethod
def _setup_argparser(): def _setup_argparser():
kwargs = { kwargs = {
'description': 'Tool to create html coverage report.', 'description': 'Create a coverage report from a previous coverage run and show it within a browser window.',
} }
parser = argparse.ArgumentParser(**kwargs) parser = argparse.ArgumentParser(**kwargs)
parser.add_argument('-k', '--keep', action='store_true', dest='keep_report',
help='keep the report after closing the browser')
return parser return parser
def _parse_args(self, argv=None): def _parse_args(self, argv=None):
@@ -35,41 +40,45 @@ class Command(object):
os.makedirs(path) os.makedirs(path)
return path return path
def _remove_report_directory(self, path=None): @staticmethod
if path is None: def _remove_report_directory(path):
path = self._report_directory if os.path.isdir(path):
if path is not None: sys.stdout.write('Removing report directory {}\n'.format(path))
if os.path.isdir(path): shutil.rmtree(path)
sys.stdout.write('Removing report directory {}\n'.format(path))
shutil.rmtree(path)
def _create_report(self, path): def _create_report(self, path):
return self._coverage.html_report(directory=path, skip_covered=True) return self._coverage.html_report(directory=path, skip_covered=True)
def _show_report(self, path): @staticmethod
start_file = os.path.join(path, 'index.html') def _show_report(path):
browser = os.environ.get('BROWSER', self.default_browser) browser = webdriver.Firefox()
cmd = '{browser} --new-window "{file}"'.format(browser=browser, file=start_file) start_file = os.path.abspath(os.path.join(path, 'index.html'))
return os.system(cmd) browser.get('file://{}'.format(start_file))
while True:
time.sleep(1)
try:
_ = browser.window_handles
except WebDriverException:
break
return True
def __init__(self): def __init__(self):
self._argparser = self._setup_argparser() self._argparser = self._setup_argparser()
self._report_directory = self._create_report_directory()
self._coverage = coverage.Coverage() self._coverage = coverage.Coverage()
self._coverage.load() self._coverage.load()
def __call__(self, argv=None): def __call__(self, argv=None):
self._parse_args(argv) cmd_args = self._parse_args(argv)
report_dir = self._report_directory report_dir = self._create_report_directory()
sys.stdout.write('Report directory: {}\n'.format(report_dir)) sys.stdout.write('Report directory: {}\n'.format(report_dir))
try: try:
self._create_report(report_dir) self._create_report(report_dir)
except Exception as e1: self._show_report(report_dir)
self._remove_report_directory(report_dir) finally:
raise e1 if not cmd_args.keep_report:
self._remove_report_directory(report_dir)
exitval = self._show_report(report_dir) return os.EX_OK
return exitval
def main(): def main():

5
requirements-test.txt Normal file
View File

@@ -0,0 +1,5 @@
-r requirements.txt
coverage
mock
pylint-django
selenium

View File

@@ -1,3 +1,2 @@
coverage
django django
django-extensions django-extensions

View File

@@ -110,6 +110,8 @@ class SetupDjangoProject(MyCommand):
if not os.path.exists(d): if not os.path.exists(d):
os.makedirs(d) os.makedirs(d)
return os.EX_OK
setup( setup(
name='django-test', name='django-test',