Merge branch 'master' of python/django-test into production
This commit was merged in pull request #9.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
python manage.py test
|
coverage run manage.py test
|
||||||
|
|||||||
1
.buildbot/test/60-coverage_report.sh
Normal file
1
.buildbot/test/60-coverage_report.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
coverage report --skip-covered --fail-under=99
|
||||||
1
.buildbot/test/70-pylint.sh
Normal file
1
.buildbot/test/70-pylint.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pylint apps.base
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
[run]
|
[run]
|
||||||
source = base
|
source = apps.base
|
||||||
|
omit = apps/base/tests/utils.py
|
||||||
|
|||||||
27
.pylintrc
Normal file
27
.pylintrc
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
10
apps/base/tests/test_urls.py
Normal file
10
apps/base/tests/test_urls.py
Normal 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)
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
5
requirements-test.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
-r requirements.txt
|
||||||
|
coverage
|
||||||
|
mock
|
||||||
|
pylint-django
|
||||||
|
selenium
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
coverage
|
|
||||||
django
|
django
|
||||||
django-extensions
|
django-extensions
|
||||||
|
|||||||
Reference in New Issue
Block a user