1
0
mirror of https://github.com/django/django.git synced 2025-03-31 19:46:42 +00:00

Prevented staticfiles test from colliding when run in parallel.

This requires that each test never alters files in static directories
collected by other tests. The alternative is to add a temporary
directory to STATICFILES_DIRS or a new app to INSTALLED_APPS.
This commit is contained in:
Aymeric Augustin 2015-06-05 00:02:32 +02:00
parent 326bc0955b
commit bf2c969eb7
3 changed files with 56 additions and 45 deletions

View File

@ -6,8 +6,6 @@ from django.utils._os import upath
TEST_ROOT = os.path.dirname(upath(__file__)) TEST_ROOT = os.path.dirname(upath(__file__))
TESTFILES_PATH = os.path.join(TEST_ROOT, 'apps', 'test', 'static', 'test')
TEST_SETTINGS = { TEST_SETTINGS = {
'DEBUG': True, 'DEBUG': True,
'MEDIA_URL': '/media/', 'MEDIA_URL': '/media/',

View File

@ -3,6 +3,7 @@ from __future__ import unicode_literals
import codecs import codecs
import os import os
import shutil import shutil
import tempfile
import unittest import unittest
from django.conf import settings from django.conf import settings
@ -11,6 +12,7 @@ from django.contrib.staticfiles.management.commands import collectstatic
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.core.management import call_command from django.core.management import call_command
from django.test import override_settings from django.test import override_settings
from django.test.utils import extend_sys_path
from django.utils import six from django.utils import six
from django.utils._os import symlinks_supported from django.utils._os import symlinks_supported
from django.utils.encoding import force_text from django.utils.encoding import force_text
@ -197,31 +199,45 @@ class TestCollectionFilesOverride(CollectionTestCase):
Test overriding duplicated files by ``collectstatic`` management command. Test overriding duplicated files by ``collectstatic`` management command.
Check for proper handling of apps order in installed apps even if file modification Check for proper handling of apps order in installed apps even if file modification
dates are in different order: dates are in different order:
'staticfiles_tests.apps.test', 'staticfiles_test_app',
'staticfiles_tests.apps.no_label', 'staticfiles_tests.apps.no_label',
""" """
def setUp(self): def setUp(self):
self.orig_path = os.path.join(TEST_ROOT, 'apps', 'no_label', 'static', 'file2.txt') self.temp_dir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, self.temp_dir)
# get modification and access times for no_label/static/file2.txt # get modification and access times for no_label/static/file2.txt
self.orig_path = os.path.join(TEST_ROOT, 'apps', 'no_label', 'static', 'file2.txt')
self.orig_mtime = os.path.getmtime(self.orig_path) self.orig_mtime = os.path.getmtime(self.orig_path)
self.orig_atime = os.path.getatime(self.orig_path) self.orig_atime = os.path.getatime(self.orig_path)
# prepare duplicate of file2.txt from no_label app # prepare duplicate of file2.txt from a temporary app
# this file will have modification time older than no_label/static/file2.txt # this file will have modification time older than no_label/static/file2.txt
# anyway it should be taken to STATIC_ROOT because 'test' app is before # anyway it should be taken to STATIC_ROOT because the temporary app is before
# 'no_label' app in installed apps # 'no_label' app in installed apps
self.testfile_path = os.path.join(TEST_ROOT, 'apps', 'test', 'static', 'file2.txt') self.temp_app_path = os.path.join(self.temp_dir, 'staticfiles_test_app')
self.testfile_path = os.path.join(self.temp_app_path, 'static', 'file2.txt')
os.makedirs(self.temp_app_path)
with open(os.path.join(self.temp_app_path, '__init__.py'), 'w+'):
pass
os.makedirs(os.path.dirname(self.testfile_path))
with open(self.testfile_path, 'w+') as f: with open(self.testfile_path, 'w+') as f:
f.write('duplicate of file2.txt') f.write('duplicate of file2.txt')
os.utime(self.testfile_path, (self.orig_atime - 1, self.orig_mtime - 1)) os.utime(self.testfile_path, (self.orig_atime - 1, self.orig_mtime - 1))
self.settings_with_test_app = self.modify_settings(
INSTALLED_APPS={'prepend': 'staticfiles_test_app'})
with extend_sys_path(self.temp_dir):
self.settings_with_test_app.enable()
super(TestCollectionFilesOverride, self).setUp() super(TestCollectionFilesOverride, self).setUp()
def tearDown(self): def tearDown(self):
if os.path.exists(self.testfile_path):
os.unlink(self.testfile_path)
# set back original modification time
os.utime(self.orig_path, (self.orig_atime, self.orig_mtime))
super(TestCollectionFilesOverride, self).tearDown() super(TestCollectionFilesOverride, self).tearDown()
self.settings_with_test_app.disable()
def test_ordering_override(self): def test_ordering_override(self):
""" """
@ -234,22 +250,11 @@ class TestCollectionFilesOverride(CollectionTestCase):
self.assertFileContains('file2.txt', 'duplicate of file2.txt') self.assertFileContains('file2.txt', 'duplicate of file2.txt')
# and now change modification time of no_label/static/file2.txt
# test app is first in installed apps so file2.txt should remain unmodified
mtime = os.path.getmtime(self.testfile_path)
atime = os.path.getatime(self.testfile_path)
os.utime(self.orig_path, (mtime + 1, atime + 1))
# run collectstatic again
self.run_collectstatic()
self.assertFileContains('file2.txt', 'duplicate of file2.txt')
# The collectstatic test suite already has conflicting files since both # The collectstatic test suite already has conflicting files since both
# project/test/file.txt and apps/test/static/test/file.txt are collected. To # project/test/file.txt and apps/test/static/test/file.txt are collected. To
# properly test for the warning not happening unless we tell it to explicitly, # properly test for the warning not happening unless we tell it to explicitly,
# we only include static files from the default finders. # we remove the project directory and will add back a conflicting file later.
@override_settings(STATICFILES_DIRS=[]) @override_settings(STATICFILES_DIRS=[])
class TestCollectionOverwriteWarning(CollectionTestCase): class TestCollectionOverwriteWarning(CollectionTestCase):
""" """
@ -268,41 +273,37 @@ class TestCollectionOverwriteWarning(CollectionTestCase):
""" """
out = six.StringIO() out = six.StringIO()
call_command('collectstatic', interactive=False, verbosity=3, stdout=out, **kwargs) call_command('collectstatic', interactive=False, verbosity=3, stdout=out, **kwargs)
out.seek(0) return force_text(out.getvalue())
return out.read()
def test_no_warning(self): def test_no_warning(self):
""" """
There isn't a warning if there isn't a duplicate destination. There isn't a warning if there isn't a duplicate destination.
""" """
output = self._collectstatic_output(clear=True) output = self._collectstatic_output(clear=True)
self.assertNotIn(self.warning_string, force_text(output)) self.assertNotIn(self.warning_string, output)
def test_warning(self): def test_warning(self):
""" """
There is a warning when there are duplicate destinations. There is a warning when there are duplicate destinations.
""" """
# Create new file in the no_label app that also exists in the test app. static_dir = tempfile.mkdtemp()
test_dir = os.path.join(TEST_ROOT, 'apps', 'no_label', 'static', 'test') self.addCleanup(shutil.rmtree, static_dir)
if not os.path.exists(test_dir):
os.mkdir(test_dir)
try: duplicate = os.path.join(static_dir, 'test', 'file.txt')
duplicate_path = os.path.join(test_dir, 'file.txt') os.mkdir(os.path.dirname(duplicate))
with open(duplicate_path, 'w+') as f: with open(duplicate, 'w+') as f:
f.write('duplicate of file.txt') f.write('duplicate of file.txt')
with self.settings(STATICFILES_DIRS=[static_dir]):
output = self._collectstatic_output(clear=True) output = self._collectstatic_output(clear=True)
self.assertIn(self.warning_string, force_text(output)) self.assertIn(self.warning_string, output)
finally:
if os.path.exists(duplicate_path):
os.unlink(duplicate_path)
if os.path.exists(test_dir): os.remove(duplicate)
os.rmdir(test_dir)
# Make sure the warning went away again. # Make sure the warning went away again.
output = self._collectstatic_output(clear=True) with self.settings(STATICFILES_DIRS=[static_dir]):
self.assertNotIn(self.warning_string, force_text(output)) output = self._collectstatic_output(clear=True)
self.assertNotIn(self.warning_string, output)
@override_settings(STATICFILES_STORAGE='staticfiles_tests.storage.DummyStorage') @override_settings(STATICFILES_STORAGE='staticfiles_tests.storage.DummyStorage')

View File

@ -1,7 +1,9 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import os import os
import shutil
import sys import sys
import tempfile
import unittest import unittest
from django.conf import settings from django.conf import settings
@ -18,7 +20,7 @@ from django.utils.encoding import force_text
from .cases import ( from .cases import (
BaseCollectionTestCase, BaseStaticFilesTestCase, StaticFilesTestCase, BaseCollectionTestCase, BaseStaticFilesTestCase, StaticFilesTestCase,
) )
from .settings import TEST_ROOT, TEST_SETTINGS, TESTFILES_PATH from .settings import TEST_ROOT, TEST_SETTINGS
def hashed_file_path(test, path): def hashed_file_path(test, path):
@ -252,15 +254,25 @@ class TestCollectionManifestStorage(TestHashedFiles, BaseCollectionTestCase,
def setUp(self): def setUp(self):
super(TestCollectionManifestStorage, self).setUp() super(TestCollectionManifestStorage, self).setUp()
self._clear_filename = os.path.join(TESTFILES_PATH, 'cleared.txt') temp_dir = tempfile.mkdtemp()
os.makedirs(os.path.join(temp_dir, 'test'))
self._clear_filename = os.path.join(temp_dir, 'test', 'cleared.txt')
with open(self._clear_filename, 'w') as f: with open(self._clear_filename, 'w') as f:
f.write('to be deleted in one test') f.write('to be deleted in one test')
self.patched_settings = self.settings(
STATICFILES_DIRS=settings.STATICFILES_DIRS + [temp_dir])
self.patched_settings.enable()
self.addCleanup(shutil.rmtree, six.text_type(temp_dir))
def tearDown(self): def tearDown(self):
super(TestCollectionManifestStorage, self).tearDown() self.patched_settings.disable()
if os.path.exists(self._clear_filename): if os.path.exists(self._clear_filename):
os.unlink(self._clear_filename) os.unlink(self._clear_filename)
super(TestCollectionManifestStorage, self).tearDown()
def test_manifest_exists(self): def test_manifest_exists(self):
filename = storage.staticfiles_storage.manifest_name filename = storage.staticfiles_storage.manifest_name
path = storage.staticfiles_storage.path(filename) path = storage.staticfiles_storage.path(filename)