Skip to content

Commit f8804b4

Browse files
committed
Added 3 tests which checks 1) that all templates can be parsed and loaded, 2) that url template-tags refer to an urlconf callback that exists, and 3) that static template-tags resolve to urls that work. This was prompted by some 500 errors earlier which weren't caught by existing texts.
- Legacy-Id: 11483
1 parent a405449 commit f8804b4

1 file changed

Lines changed: 119 additions & 0 deletions

File tree

ietf/utils/tests.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
22
import os.path
3+
import types
34
#import json
45
#from pathlib import Path
56

@@ -9,12 +10,18 @@
910
from email.mime.multipart import MIMEMultipart
1011

1112
from django.conf import settings
13+
from django.template import Context
14+
from django.template.defaulttags import URLNode
15+
from django.templatetags.static import StaticNode
16+
from django.template.loaders.filesystem import Loader
1217
from django.test import TestCase
1318

1419
import debug # pyflakes:ignore
1520

21+
import ietf.urls
1622
from ietf.utils.management.commands import pyflakes
1723
from ietf.utils.mail import send_mail_text, send_mail_mime, outbox
24+
from ietf.utils.test_runner import get_template_paths
1825

1926
class PyFlakesTestCase(TestCase):
2027

@@ -65,6 +72,118 @@ def send_complex_mail(to):
6572
self.assertEqual(len(outbox),len_before+2)
6673

6774

75+
def get_callbacks(urllist):
76+
callbacks = set()
77+
for entry in urllist:
78+
if hasattr(entry, 'url_patterns'):
79+
callbacks.update(get_callbacks(entry.url_patterns))
80+
else:
81+
if hasattr(entry, '_callback_str'):
82+
callbacks.add(unicode(entry._callback_str))
83+
if (hasattr(entry, 'callback') and entry.callback
84+
and type(entry.callback) in [types.FunctionType, types.MethodType ]):
85+
callbacks.add("%s.%s" % (entry.callback.__module__, entry.callback.__name__))
86+
if hasattr(entry, 'name') and entry.name:
87+
callbacks.add(unicode(entry.name))
88+
# There are some entries we don't handle here, mostly clases
89+
# (such as Feed subclasses)
90+
91+
return list(callbacks)
92+
93+
class TemplateChecksTestCase(TestCase):
94+
95+
paths = []
96+
templates = {}
97+
98+
def setUp(self):
99+
self.loader = Loader()
100+
self.paths = list(get_template_paths())
101+
self.paths.sort()
102+
for path in self.paths:
103+
try:
104+
self.templates[path], _ = self.loader.load_template(path)
105+
except Exception:
106+
pass
107+
108+
def tearDown(self):
109+
pass
110+
111+
def test_parse_templates(self):
112+
errors = []
113+
for path in self.paths:
114+
if not path in self.templates:
115+
try:
116+
self.loader.load_template(path)
117+
except Exception as e:
118+
errors.append((path, e))
119+
if errors:
120+
messages = [ "Parsing template '%s' failed with error: %s" % (path, ex) for (path, ex) in errors ]
121+
raise self.failureException("Template parsing failed for %s templates:\n %s" % (len(errors), "\n ".join(messages)))
122+
123+
def apply_template_test(self, func, node_type, msg, *args, **kwargs):
124+
errors = []
125+
for path, template in self.templates.items():
126+
origin = str(template.origin).replace(settings.BASE_DIR, '')
127+
for node in template:
128+
for child in node.get_nodes_by_type(node_type):
129+
errors += func(child, origin, *args, **kwargs)
130+
if errors:
131+
errors = list(set(errors))
132+
errors.sort()
133+
messages = [ msg % (k, v) for (k, v) in errors ]
134+
raise self.failureException("Found %s errors when trying to %s:\n %s" %(len(errors), func.__name__.replace('_',' '), "\n ".join(messages)))
135+
136+
def test_template_url_lookup(self):
137+
"""
138+
This test doesn't do full url resolving, using the appropriate contexts, as it
139+
simply doesn't have any context to use. It only looks if there exists a URL
140+
pattern with the appropriate callback, callback string, or name. If no matching
141+
urlconf can be found, a full resolution would also fail.
142+
"""
143+
#
144+
def check_that_url_tag_callbacks_exists(node, origin, callbacks):
145+
"""
146+
Check that an URLNode's callback is in callbacks.
147+
"""
148+
cb = node.view_name.token.strip("\"'")
149+
if cb in callbacks:
150+
return []
151+
else:
152+
return [ (origin, cb), ]
153+
#
154+
155+
callbacks = get_callbacks(ietf.urls.urlpatterns)
156+
self.apply_template_test(check_that_url_tag_callbacks_exists, URLNode, 'In %s: Could not find urlpattern for "%s"', callbacks)
157+
158+
def test_template_statics_exists(self):
159+
"""
160+
This test checks that every static template tag found in the template files found
161+
by utils.test_runner.get_template_paths() actually resolves to a file that can be
162+
served. If collectstatic is correctly set up and used, the results should apply
163+
to both development and production mode.
164+
"""
165+
#
166+
def check_that_static_tags_resolve(node, origin, checked):
167+
"""
168+
Check that a StaticNode resolves to an url that can be served.
169+
"""
170+
url = node.render(Context((), {}))
171+
if url in checked:
172+
return []
173+
else:
174+
r = self.client.get(url)
175+
if r.status_code == 200:
176+
checked[url] = origin
177+
return []
178+
else:
179+
return [(origin, url), ]
180+
#
181+
checked = {}
182+
# the test client will only return static files when settings.DEBUG is True:
183+
saved_debug = settings.DEBUG
184+
settings.DEBUG = True
185+
self.apply_template_test(check_that_static_tags_resolve, StaticNode, 'In %s: Could not find static file for "%s"', checked)
186+
settings.DEBUG = saved_debug
68187

69188

70189
## One might think that the code below would work, but it doesn't ...

0 commit comments

Comments
 (0)