1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
import os
import brotli
from django.core.files.base import ContentFile
from django.core.files.storage import storages
from django.core.files.storage.base import Storage
from django.test import TestCase
from django.test.utils import override_settings
from django.utils.functional import LazyObject
from compressor import storage
from compressor.conf import settings
from compressor.css import CssCompressor
from compressor.tests.test_base import css_tag
from compressor.tests.test_templatetags import render
class GzipStorage(LazyObject):
def _setup(self):
self._wrapped = storages.create_storage({
"BACKEND": "compressor.storage.GzipCompressorFileStorage"
})
class BrotliStorage(LazyObject):
def _setup(self):
self._wrapped = storages.create_storage({
"BACKEND": "compressor.storage.BrotliCompressorFileStorage"
})
class DummyPathNotImplementedStorage(Storage):
"""
A dummy storage backend that mimics a remote storage that does not implement
`.path()` e.g. `storages.backends.s3.S3Storage`.
"""
def exists(self, name):
return True
def path(self, name):
raise NotImplementedError
@override_settings(COMPRESS_ENABLED=True)
class StorageTestCase(TestCase):
def setUp(self):
self.default_storage = storage.default_storage
storage.default_storage = GzipStorage()
storage.brotli_storage = BrotliStorage()
def tearDown(self):
storage.default_storage = self.default_storage
def test_gzip_storage(self):
storage.default_storage.save("test.txt", ContentFile("yeah yeah"))
self.assertTrue(
os.path.exists(os.path.join(settings.COMPRESS_ROOT, "test.txt"))
)
self.assertTrue(
os.path.exists(os.path.join(settings.COMPRESS_ROOT, "test.txt.gz"))
)
def test_brotli_storage(self):
payload = ",".join([str(i) for i in range(1000)]).encode()
chunk_size = 1024
storage.brotli_storage.save("test.txt", ContentFile(payload))
self.assertTrue(
os.path.exists(os.path.join(settings.COMPRESS_ROOT, "test.txt"))
)
self.assertTrue(
os.path.exists(os.path.join(settings.COMPRESS_ROOT, "test.txt.br"))
)
decompressed_data = b""
br_decompressor = brotli.Decompressor()
with open(os.path.join(settings.COMPRESS_ROOT, "test.txt.br"), "rb") as f:
for data in iter(lambda: f.read(chunk_size), b""):
decompressed_data += br_decompressor.process(data)
self.assertEqual(payload, decompressed_data)
def test_css_tag_with_storage(self):
template = """{% load compress %}{% compress css %}
<link rel="stylesheet" href="{{ STATIC_URL }}css/one.css" type="text/css">
<style type="text/css">p { border:5px solid white;}</style>
<link rel="stylesheet" href="{{ STATIC_URL }}css/two.css" type="text/css">
{% endcompress %}
"""
context = {"STATIC_URL": settings.COMPRESS_URL}
out = css_tag("/static/CACHE/css/output.e701f86c6430.css")
self.assertEqual(out, render(template, context))
def test_duplicate_save_overwrites_same_file(self):
filename1 = self.default_storage.save("test.txt", ContentFile("yeah yeah"))
filename2 = self.default_storage.save("test.txt", ContentFile("yeah yeah"))
self.assertEqual(filename1, filename2)
self.assertNotIn("_", filename2)
def test_offline_manifest_storage(self):
storage.default_offline_manifest_storage.save(
"test.txt", ContentFile("yeah yeah")
)
self.assertTrue(
os.path.exists(os.path.join(settings.COMPRESS_ROOT, "CACHE", "test.txt"))
)
# Check that the file is stored at the same default location as before
# the new manifest storage.
self.assertTrue(self.default_storage.exists(os.path.join("CACHE", "test.txt")))
class CompressorFileNameTestCase(TestCase):
@override_settings(
COMPRESS_ENABLED=True,
DEBUG=False,
COMPRESS_STORAGE=(
"compressor.tests.test_storages.DummyPathNotImplementedStorage"
),
)
def test_storage_without_path_fallback(self):
"""
Remote storages not implementing path need a fallback to a private
instance of CompressorFileStorage. This must not be dependent on
project settings.
"""
old_default_storage = storage.default_storage
storage.default_storage = storage.DefaultStorage()
css = (
'<link rel="stylesheet" href="/static/css/one.css" type="text/css" />'
)
compressor = CssCompressor("css", css)
try:
# Remote storage would raise NotImplementedError if fallback is
# unsuccessful.
compressor.get_filename("css/one.css")
finally:
storage.default_storage = old_default_storage
|