tests.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. import os
  2. import posixpath
  3. import shutil
  4. import sys
  5. import tempfile
  6. from StringIO import StringIO
  7. from django.conf import settings
  8. from django.contrib.staticfiles import finders, storage
  9. from django.core.exceptions import ImproperlyConfigured
  10. from django.core.files.storage import default_storage
  11. from django.core.management import call_command
  12. from django.db.models.loading import load_app
  13. from django.template import Template, Context
  14. from django.test import TestCase
  15. from django.utils._os import rmtree_errorhandler
  16. TEST_ROOT = os.path.normcase(os.path.dirname(__file__))
  17. class StaticFilesTestCase(TestCase):
  18. """
  19. Test case with a couple utility assertions.
  20. """
  21. def setUp(self):
  22. self.old_static_url = settings.STATIC_URL
  23. self.old_static_root = settings.STATIC_ROOT
  24. self.old_staticfiles_dirs = settings.STATICFILES_DIRS
  25. self.old_staticfiles_finders = settings.STATICFILES_FINDERS
  26. self.old_media_root = settings.MEDIA_ROOT
  27. self.old_media_url = settings.MEDIA_URL
  28. self.old_admin_media_prefix = settings.ADMIN_MEDIA_PREFIX
  29. self.old_debug = settings.DEBUG
  30. self.old_installed_apps = settings.INSTALLED_APPS
  31. site_media = os.path.join(TEST_ROOT, 'project', 'site_media')
  32. settings.DEBUG = True
  33. settings.MEDIA_ROOT = os.path.join(site_media, 'media')
  34. settings.MEDIA_URL = '/media/'
  35. settings.STATIC_ROOT = os.path.join(site_media, 'static')
  36. settings.STATIC_URL = '/static/'
  37. settings.ADMIN_MEDIA_PREFIX = '/static/admin/'
  38. settings.STATICFILES_DIRS = (
  39. os.path.join(TEST_ROOT, 'project', 'documents'),
  40. )
  41. settings.STATICFILES_FINDERS = (
  42. 'django.contrib.staticfiles.finders.FileSystemFinder',
  43. 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
  44. 'django.contrib.staticfiles.finders.DefaultStorageFinder',
  45. )
  46. settings.INSTALLED_APPS = [
  47. 'django.contrib.admin',
  48. 'django.contrib.staticfiles',
  49. 'regressiontests.staticfiles_tests',
  50. 'regressiontests.staticfiles_tests.apps.test',
  51. 'regressiontests.staticfiles_tests.apps.no_label',
  52. ]
  53. # Clear the cached default_storage out, this is because when it first
  54. # gets accessed (by some other test), it evaluates settings.MEDIA_ROOT,
  55. # since we're planning on changing that we need to clear out the cache.
  56. default_storage._wrapped = None
  57. def tearDown(self):
  58. settings.DEBUG = self.old_debug
  59. settings.MEDIA_ROOT = self.old_media_root
  60. settings.MEDIA_URL = self.old_media_url
  61. settings.ADMIN_MEDIA_PREFIX = self.old_admin_media_prefix
  62. settings.STATIC_ROOT = self.old_static_root
  63. settings.STATIC_URL = self.old_static_url
  64. settings.STATICFILES_DIRS = self.old_staticfiles_dirs
  65. settings.STATICFILES_FINDERS = self.old_staticfiles_finders
  66. settings.INSTALLED_APPS = self.old_installed_apps
  67. def assertFileContains(self, filepath, text):
  68. self.assertTrue(text in self._get_file(filepath),
  69. "'%s' not in '%s'" % (text, filepath))
  70. def assertFileNotFound(self, filepath):
  71. self.assertRaises(IOError, self._get_file, filepath)
  72. class BuildStaticTestCase(StaticFilesTestCase):
  73. """
  74. Tests shared by all file-resolving features (collectstatic,
  75. findstatic, and static serve view).
  76. This relies on the asserts defined in UtilityAssertsTestCase, but
  77. is separated because some test cases need those asserts without
  78. all these tests.
  79. """
  80. def setUp(self):
  81. super(BuildStaticTestCase, self).setUp()
  82. self.old_root = settings.STATIC_ROOT
  83. settings.STATIC_ROOT = tempfile.mkdtemp()
  84. self.run_collectstatic()
  85. def tearDown(self):
  86. # Use our own error handler that can handle .svn dirs on Windows
  87. shutil.rmtree(settings.STATIC_ROOT, ignore_errors=True,
  88. onerror=rmtree_errorhandler)
  89. settings.STATIC_ROOT = self.old_root
  90. super(BuildStaticTestCase, self).tearDown()
  91. def run_collectstatic(self, **kwargs):
  92. call_command('collectstatic', interactive=False, verbosity='0',
  93. ignore_patterns=['*.ignoreme'], **kwargs)
  94. def _get_file(self, filepath):
  95. assert filepath, 'filepath is empty.'
  96. filepath = os.path.join(settings.STATIC_ROOT, filepath)
  97. f = open(filepath)
  98. try:
  99. return f.read()
  100. finally:
  101. f.close()
  102. class TestDefaults(object):
  103. """
  104. A few standard test cases.
  105. """
  106. def test_staticfiles_dirs(self):
  107. """
  108. Can find a file in a STATICFILES_DIRS directory.
  109. """
  110. self.assertFileContains('test.txt', 'Can we find')
  111. def test_staticfiles_dirs_subdir(self):
  112. """
  113. Can find a file in a subdirectory of a STATICFILES_DIRS
  114. directory.
  115. """
  116. self.assertFileContains('subdir/test.txt', 'Can we find')
  117. def test_staticfiles_dirs_priority(self):
  118. """
  119. File in STATICFILES_DIRS has priority over file in app.
  120. """
  121. self.assertFileContains('test/file.txt', 'STATICFILES_DIRS')
  122. def test_app_files(self):
  123. """
  124. Can find a file in an app media/ directory.
  125. """
  126. self.assertFileContains('test/file1.txt', 'file1 in the app dir')
  127. class TestFindStatic(BuildStaticTestCase, TestDefaults):
  128. """
  129. Test ``findstatic`` management command.
  130. """
  131. def _get_file(self, filepath):
  132. _stdout = sys.stdout
  133. sys.stdout = StringIO()
  134. try:
  135. call_command('findstatic', filepath, all=False, verbosity='0')
  136. sys.stdout.seek(0)
  137. lines = [l.strip() for l in sys.stdout.readlines()]
  138. contents = open(lines[1].strip()).read()
  139. finally:
  140. sys.stdout = _stdout
  141. return contents
  142. def test_all_files(self):
  143. """
  144. Test that findstatic returns all candidate files if run without --first.
  145. """
  146. _stdout = sys.stdout
  147. sys.stdout = StringIO()
  148. try:
  149. call_command('findstatic', 'test/file.txt', verbosity='0')
  150. sys.stdout.seek(0)
  151. lines = [l.strip() for l in sys.stdout.readlines()]
  152. finally:
  153. sys.stdout = _stdout
  154. self.assertEquals(len(lines), 3) # three because there is also the "Found <file> here" line
  155. self.assertTrue('project' in lines[1])
  156. self.assertTrue('apps' in lines[2])
  157. class TestBuildStatic(BuildStaticTestCase, TestDefaults):
  158. """
  159. Test ``collectstatic`` management command.
  160. """
  161. def test_ignore(self):
  162. """
  163. Test that -i patterns are ignored.
  164. """
  165. self.assertFileNotFound('test/test.ignoreme')
  166. def test_common_ignore_patterns(self):
  167. """
  168. Common ignore patterns (*~, .*, CVS) are ignored.
  169. """
  170. self.assertFileNotFound('test/.hidden')
  171. self.assertFileNotFound('test/backup~')
  172. self.assertFileNotFound('test/CVS')
  173. class TestBuildStaticExcludeNoDefaultIgnore(BuildStaticTestCase, TestDefaults):
  174. """
  175. Test ``--exclude-dirs`` and ``--no-default-ignore`` options for
  176. ``collectstatic`` management command.
  177. """
  178. def run_collectstatic(self):
  179. super(TestBuildStaticExcludeNoDefaultIgnore, self).run_collectstatic(
  180. use_default_ignore_patterns=False)
  181. def test_no_common_ignore_patterns(self):
  182. """
  183. With --no-default-ignore, common ignore patterns (*~, .*, CVS)
  184. are not ignored.
  185. """
  186. self.assertFileContains('test/.hidden', 'should be ignored')
  187. self.assertFileContains('test/backup~', 'should be ignored')
  188. self.assertFileContains('test/CVS', 'should be ignored')
  189. class TestNoFilesCreated(object):
  190. def test_no_files_created(self):
  191. """
  192. Make sure no files were create in the destination directory.
  193. """
  194. self.assertEquals(os.listdir(settings.STATIC_ROOT), [])
  195. class TestBuildStaticDryRun(BuildStaticTestCase, TestNoFilesCreated):
  196. """
  197. Test ``--dry-run`` option for ``collectstatic`` management command.
  198. """
  199. def run_collectstatic(self):
  200. super(TestBuildStaticDryRun, self).run_collectstatic(dry_run=True)
  201. class TestBuildStaticNonLocalStorage(BuildStaticTestCase, TestNoFilesCreated):
  202. """
  203. Tests for #15035
  204. """
  205. def setUp(self):
  206. self.old_staticfiles_storage = settings.STATICFILES_STORAGE
  207. settings.STATICFILES_STORAGE = 'regressiontests.staticfiles_tests.storage.DummyStorage'
  208. super(TestBuildStaticNonLocalStorage, self).setUp()
  209. def tearDown(self):
  210. super(TestBuildStaticNonLocalStorage, self).tearDown()
  211. settings.STATICFILES_STORAGE = self.old_staticfiles_storage
  212. if sys.platform != 'win32':
  213. class TestBuildStaticLinks(BuildStaticTestCase, TestDefaults):
  214. """
  215. Test ``--link`` option for ``collectstatic`` management command.
  216. Note that by inheriting ``TestDefaults`` we repeat all
  217. the standard file resolving tests here, to make sure using
  218. ``--link`` does not change the file-selection semantics.
  219. """
  220. def run_collectstatic(self):
  221. super(TestBuildStaticLinks, self).run_collectstatic(link=True)
  222. def test_links_created(self):
  223. """
  224. With ``--link``, symbolic links are created.
  225. """
  226. self.assertTrue(os.path.islink(os.path.join(settings.STATIC_ROOT, 'test.txt')))
  227. class TestServeStatic(StaticFilesTestCase):
  228. """
  229. Test static asset serving view.
  230. """
  231. urls = 'regressiontests.staticfiles_tests.urls.default'
  232. def _response(self, filepath):
  233. return self.client.get(
  234. posixpath.join(settings.STATIC_URL, filepath))
  235. def assertFileContains(self, filepath, text):
  236. self.assertContains(self._response(filepath), text)
  237. def assertFileNotFound(self, filepath):
  238. self.assertEquals(self._response(filepath).status_code, 404)
  239. class TestServeDisabled(TestServeStatic):
  240. """
  241. Test serving media from django.contrib.admin.
  242. """
  243. def setUp(self):
  244. super(TestServeDisabled, self).setUp()
  245. settings.DEBUG = False
  246. def test_disabled_serving(self):
  247. self.assertRaisesRegexp(ImproperlyConfigured, 'The view to serve '
  248. 'static files can only be used if the DEBUG setting is True',
  249. self._response, 'test.txt')
  250. class TestServeStaticWithDefaultURL(TestServeStatic, TestDefaults):
  251. """
  252. Test static asset serving view with staticfiles_urlpatterns helper.
  253. """
  254. pass
  255. class TestServeStaticWithURLHelper(TestServeStatic, TestDefaults):
  256. """
  257. Test static asset serving view with staticfiles_urlpatterns helper.
  258. """
  259. urls = 'regressiontests.staticfiles_tests.urls.helper'
  260. class TestServeAdminMedia(TestServeStatic):
  261. """
  262. Test serving media from django.contrib.admin.
  263. """
  264. def _response(self, filepath):
  265. return self.client.get(
  266. posixpath.join(settings.ADMIN_MEDIA_PREFIX, filepath))
  267. def test_serve_admin_media(self):
  268. self.assertFileContains('css/base.css', 'body')
  269. class FinderTestCase(object):
  270. """
  271. Base finder test mixin
  272. """
  273. def test_find_first(self):
  274. src, dst = self.find_first
  275. self.assertEquals(self.finder.find(src), dst)
  276. def test_find_all(self):
  277. src, dst = self.find_all
  278. self.assertEquals(self.finder.find(src, all=True), dst)
  279. class TestFileSystemFinder(StaticFilesTestCase, FinderTestCase):
  280. """
  281. Test FileSystemFinder.
  282. """
  283. def setUp(self):
  284. super(TestFileSystemFinder, self).setUp()
  285. self.finder = finders.FileSystemFinder()
  286. test_file_path = os.path.join(TEST_ROOT, 'project', 'documents', 'test', 'file.txt')
  287. self.find_first = (os.path.join('test', 'file.txt'), test_file_path)
  288. self.find_all = (os.path.join('test', 'file.txt'), [test_file_path])
  289. class TestAppDirectoriesFinder(StaticFilesTestCase, FinderTestCase):
  290. """
  291. Test AppDirectoriesFinder.
  292. """
  293. def setUp(self):
  294. super(TestAppDirectoriesFinder, self).setUp()
  295. self.finder = finders.AppDirectoriesFinder()
  296. test_file_path = os.path.join(TEST_ROOT, 'apps', 'test', 'static', 'test', 'file1.txt')
  297. self.find_first = (os.path.join('test', 'file1.txt'), test_file_path)
  298. self.find_all = (os.path.join('test', 'file1.txt'), [test_file_path])
  299. class TestDefaultStorageFinder(StaticFilesTestCase, FinderTestCase):
  300. """
  301. Test DefaultStorageFinder.
  302. """
  303. def setUp(self):
  304. super(TestDefaultStorageFinder, self).setUp()
  305. self.finder = finders.DefaultStorageFinder(
  306. storage=storage.StaticFilesStorage(location=settings.MEDIA_ROOT))
  307. test_file_path = os.path.join(settings.MEDIA_ROOT, 'media-file.txt')
  308. self.find_first = ('media-file.txt', test_file_path)
  309. self.find_all = ('media-file.txt', [test_file_path])
  310. class TestMiscFinder(TestCase):
  311. """
  312. A few misc finder tests.
  313. """
  314. def test_get_finder(self):
  315. self.assertTrue(isinstance(finders.get_finder(
  316. 'django.contrib.staticfiles.finders.FileSystemFinder'),
  317. finders.FileSystemFinder))
  318. self.assertRaises(ImproperlyConfigured,
  319. finders.get_finder, 'django.contrib.staticfiles.finders.FooBarFinder')
  320. self.assertRaises(ImproperlyConfigured,
  321. finders.get_finder, 'foo.bar.FooBarFinder')