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__))
TESTFILES_PATH = os.path.join(TEST_ROOT, 'apps', 'test', 'static', 'test')
TEST_SETTINGS = {
'DEBUG': True,
'MEDIA_URL': '/media/',

View File

@ -3,6 +3,7 @@ from __future__ import unicode_literals
import codecs
import os
import shutil
import tempfile
import unittest
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.management import call_command
from django.test import override_settings
from django.test.utils import extend_sys_path
from django.utils import six
from django.utils._os import symlinks_supported
from django.utils.encoding import force_text
@ -197,31 +199,45 @@ class TestCollectionFilesOverride(CollectionTestCase):
Test overriding duplicated files by ``collectstatic`` management command.
Check for proper handling of apps order in installed apps even if file modification
dates are in different order:
'staticfiles_tests.apps.test',
'staticfiles_test_app',
'staticfiles_tests.apps.no_label',
"""
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
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_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
# 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
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:
f.write('duplicate of file2.txt')
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()
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()
self.settings_with_test_app.disable()
def test_ordering_override(self):
"""
@ -234,22 +250,11 @@ class TestCollectionFilesOverride(CollectionTestCase):
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
# 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,
# 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=[])
class TestCollectionOverwriteWarning(CollectionTestCase):
"""
@ -268,41 +273,37 @@ class TestCollectionOverwriteWarning(CollectionTestCase):
"""
out = six.StringIO()
call_command('collectstatic', interactive=False, verbosity=3, stdout=out, **kwargs)
out.seek(0)
return out.read()
return force_text(out.getvalue())
def test_no_warning(self):
"""
There isn't a warning if there isn't a duplicate destination.
"""
output = self._collectstatic_output(clear=True)
self.assertNotIn(self.warning_string, force_text(output))
self.assertNotIn(self.warning_string, output)
def test_warning(self):
"""
There is a warning when there are duplicate destinations.
"""
# Create new file in the no_label app that also exists in the test app.
test_dir = os.path.join(TEST_ROOT, 'apps', 'no_label', 'static', 'test')
if not os.path.exists(test_dir):
os.mkdir(test_dir)
static_dir = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, static_dir)
try:
duplicate_path = os.path.join(test_dir, 'file.txt')
with open(duplicate_path, 'w+') as f:
f.write('duplicate of file.txt')
duplicate = os.path.join(static_dir, 'test', 'file.txt')
os.mkdir(os.path.dirname(duplicate))
with open(duplicate, 'w+') as f:
f.write('duplicate of file.txt')
with self.settings(STATICFILES_DIRS=[static_dir]):
output = self._collectstatic_output(clear=True)
self.assertIn(self.warning_string, force_text(output))
finally:
if os.path.exists(duplicate_path):
os.unlink(duplicate_path)
self.assertIn(self.warning_string, output)
if os.path.exists(test_dir):
os.rmdir(test_dir)
os.remove(duplicate)
# Make sure the warning went away again.
output = self._collectstatic_output(clear=True)
self.assertNotIn(self.warning_string, force_text(output))
with self.settings(STATICFILES_DIRS=[static_dir]):
output = self._collectstatic_output(clear=True)
self.assertNotIn(self.warning_string, output)
@override_settings(STATICFILES_STORAGE='staticfiles_tests.storage.DummyStorage')

View File

@ -1,7 +1,9 @@
from __future__ import unicode_literals
import os
import shutil
import sys
import tempfile
import unittest
from django.conf import settings
@ -18,7 +20,7 @@ from django.utils.encoding import force_text
from .cases import (
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):
@ -252,15 +254,25 @@ class TestCollectionManifestStorage(TestHashedFiles, BaseCollectionTestCase,
def setUp(self):
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:
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):
super(TestCollectionManifestStorage, self).tearDown()
self.patched_settings.disable()
if os.path.exists(self._clear_filename):
os.unlink(self._clear_filename)
super(TestCollectionManifestStorage, self).tearDown()
def test_manifest_exists(self):
filename = storage.staticfiles_storage.manifest_name
path = storage.staticfiles_storage.path(filename)