summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
Diffstat (limited to 'django')
-rw-r--r--django/contrib/staticfiles/testing.py14
-rw-r--r--django/contrib/staticfiles/views.py2
-rw-r--r--django/test/testcases.py92
3 files changed, 92 insertions, 16 deletions
diff --git a/django/contrib/staticfiles/testing.py b/django/contrib/staticfiles/testing.py
new file mode 100644
index 0000000000..868323988b
--- /dev/null
+++ b/django/contrib/staticfiles/testing.py
@@ -0,0 +1,14 @@
+from django.test import LiveServerTestCase
+
+from django.contrib.staticfiles.handlers import StaticFilesHandler
+
+
+class StaticLiveServerCase(LiveServerTestCase):
+ """
+ Extends django.test.LiveServerTestCase to transparently overlay at test
+ execution-time the assets provided by the staticfiles app finders. This
+ means you don't need to run collectstatic before or as a part of your tests
+ setup.
+ """
+
+ static_handler = StaticFilesHandler
diff --git a/django/contrib/staticfiles/views.py b/django/contrib/staticfiles/views.py
index 7ddc6a1bc2..efba1690c0 100644
--- a/django/contrib/staticfiles/views.py
+++ b/django/contrib/staticfiles/views.py
@@ -27,7 +27,7 @@ def serve(request, path, insecure=False, **kwargs):
in your URLconf.
- It uses the django.views.static view to serve the found files.
+ It uses the django.views.static.serve() view to serve the found files.
"""
if not settings.DEBUG and not insecure:
raise Http404
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 5b72d4e8b8..2c65901c80 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -6,23 +6,25 @@ import errno
from functools import wraps
import json
import os
+import posixpath
import re
import sys
-import socket
import threading
import unittest
from unittest import skipIf # Imported here for backward compatibility
from unittest.util import safe_repr
try:
- from urllib.parse import urlsplit, urlunsplit
+ from urllib.parse import urlsplit, urlunsplit, urlparse, unquote
+ from urllib.request import url2pathname
except ImportError: # Python 2
- from urlparse import urlsplit, urlunsplit
+ from urlparse import urlsplit, urlunsplit, urlparse
+ from urllib import url2pathname, unquote
from django.conf import settings
-from django.contrib.staticfiles.handlers import StaticFilesHandler
from django.core import mail
from django.core.exceptions import ValidationError, ImproperlyConfigured
from django.core.handlers.wsgi import WSGIHandler
+from django.core.handlers.base import get_path_info
from django.core.management import call_command
from django.core.management.color import no_style
from django.core.management.commands import flush
@@ -933,10 +935,70 @@ class QuietWSGIRequestHandler(WSGIRequestHandler):
pass
-class _MediaFilesHandler(StaticFilesHandler):
+class FSFilesHandler(WSGIHandler):
"""
- Handler for serving the media files. This is a private class that is
- meant to be used solely as a convenience by LiveServerThread.
+ WSGI middleware that intercepts calls to a directory, as defined by one of
+ the *_ROOT settings, and serves those files, publishing them under *_URL.
+ """
+ def __init__(self, application):
+ self.application = application
+ self.base_url = urlparse(self.get_base_url())
+ super(FSFilesHandler, self).__init__()
+
+ def _should_handle(self, path):
+ """
+ Checks if the path should be handled. Ignores the path if:
+
+ * the host is provided as part of the base_url
+ * the request's path isn't under the media path (or equal)
+ """
+ return path.startswith(self.base_url[2]) and not self.base_url[1]
+
+ def file_path(self, url):
+ """
+ Returns the relative path to the file on disk for the given URL.
+ """
+ relative_url = url[len(self.base_url[2]):]
+ return url2pathname(relative_url)
+
+ def get_response(self, request):
+ from django.http import Http404
+
+ if self._should_handle(request.path):
+ try:
+ return self.serve(request)
+ except Http404:
+ pass
+ return super(FSFilesHandler, self).get_response(request)
+
+ def serve(self, request):
+ os_rel_path = self.file_path(request.path)
+ final_rel_path = posixpath.normpath(unquote(os_rel_path)).lstrip('/')
+ return serve(request, final_rel_path, document_root=self.get_base_dir())
+
+ def __call__(self, environ, start_response):
+ if not self._should_handle(get_path_info(environ)):
+ return self.application(environ, start_response)
+ return super(FSFilesHandler, self).__call__(environ, start_response)
+
+
+class _StaticFilesHandler(FSFilesHandler):
+ """
+ Handler for serving static files. A private class that is meant to be used
+ solely as a convenience by LiveServerThread.
+ """
+
+ def get_base_dir(self):
+ return settings.STATIC_ROOT
+
+ def get_base_url(self):
+ return settings.STATIC_URL
+
+
+class _MediaFilesHandler(FSFilesHandler):
+ """
+ Handler for serving the media files. A private class that is meant to be
+ used solely as a convenience by LiveServerThread.
"""
def get_base_dir(self):
@@ -945,22 +1007,19 @@ class _MediaFilesHandler(StaticFilesHandler):
def get_base_url(self):
return settings.MEDIA_URL
- def serve(self, request):
- relative_url = request.path[len(self.base_url[2]):]
- return serve(request, relative_url, document_root=self.get_base_dir())
-
class LiveServerThread(threading.Thread):
"""
Thread for running a live http server while the tests are running.
"""
- def __init__(self, host, possible_ports, connections_override=None):
+ def __init__(self, host, possible_ports, static_handler, connections_override=None):
self.host = host
self.port = None
self.possible_ports = possible_ports
self.is_ready = threading.Event()
self.error = None
+ self.static_handler = static_handler
self.connections_override = connections_override
super(LiveServerThread, self).__init__()
@@ -976,7 +1035,7 @@ class LiveServerThread(threading.Thread):
connections[alias] = conn
try:
# Create the handler for serving static and media files
- handler = StaticFilesHandler(_MediaFilesHandler(WSGIHandler()))
+ handler = self.static_handler(_MediaFilesHandler(WSGIHandler()))
# Go through the list of possible ports, hoping that we can find
# one that is free to use for the WSGI server.
@@ -1028,6 +1087,8 @@ class LiveServerTestCase(TransactionTestCase):
other thread can see the changes.
"""
+ static_handler = _StaticFilesHandler
+
@property
def live_server_url(self):
return 'http://%s:%s' % (
@@ -1069,8 +1130,9 @@ class LiveServerTestCase(TransactionTestCase):
except Exception:
msg = 'Invalid address ("%s") for live server.' % specified_address
six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg), sys.exc_info()[2])
- cls.server_thread = LiveServerThread(
- host, possible_ports, connections_override)
+ cls.server_thread = LiveServerThread(host, possible_ports,
+ cls.static_handler,
+ connections_override=connections_override)
cls.server_thread.daemon = True
cls.server_thread.start()