Merge branch 'master' into custom-user-model-fixes

This commit is contained in:
John-Scott Atlakson 2014-10-26 19:39:15 -04:00
commit fdea93629d
5 changed files with 560 additions and 549 deletions

View file

View file

@ -1,251 +1,15 @@
import json
import datetime
from mock import MagicMock
import dateutil.parser
from django.utils import six
from django.utils.http import urlquote
from django.utils import timezone
from django.test import TestCase
from django.test.utils import override_settings
from django import template
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission
from django.utils.http import urlquote
from django.core.urlresolvers import reverse
from django.contrib.auth.models import Permission
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db.utils import IntegrityError
from wagtail.tests.utils import unittest, WagtailTestUtils
from wagtail.wagtailimages.models import get_image_model, Rendition
from wagtail.wagtailimages.formats import (
Format,
get_image_format,
register_image_format
)
from wagtail.tests.utils import WagtailTestUtils
from wagtail.wagtailimages.utils.crypto import generate_signature
from wagtail.wagtailimages.backends import get_image_backend
from wagtail.wagtailimages.backends.pillow import PillowBackend
from wagtail.wagtailimages.utils.crypto import generate_signature, verify_signature
from wagtail.tests.models import EventPage, EventPageCarouselItem
from wagtail.wagtailcore.models import Page
def get_test_image_file(filename='test.png'):
from six import BytesIO
from PIL import Image
from django.core.files.images import ImageFile
f = BytesIO()
image = Image.new('RGB', (640, 480), 'white')
image.save(f, 'PNG')
return ImageFile(f, name=filename)
Image = get_image_model()
class TestImage(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_is_portrait(self):
self.assertFalse(self.image.is_portrait())
def test_is_landscape(self):
self.assertTrue(self.image.is_landscape())
class TestImagePermissions(TestCase):
def setUp(self):
# Create some user accounts for testing permissions
User = get_user_model()
self.user = User.objects.create_user(username='user', email='user@email.com', password='password')
self.owner = User.objects.create_user(username='owner', email='owner@email.com', password='password')
self.editor = User.objects.create_user(username='editor', email='editor@email.com', password='password')
self.editor.groups.add(Group.objects.get(name='Editors'))
self.administrator = User.objects.create_superuser(username='administrator', email='administrator@email.com', password='password')
# Owner user must have the add_image permission
self.owner.user_permissions.add(Permission.objects.get(codename='add_image'))
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
uploaded_by_user=self.owner,
file=get_test_image_file(),
)
def test_administrator_can_edit(self):
self.assertTrue(self.image.is_editable_by_user(self.administrator))
def test_editor_can_edit(self):
self.assertTrue(self.image.is_editable_by_user(self.editor))
def test_owner_can_edit(self):
self.assertTrue(self.image.is_editable_by_user(self.owner))
def test_user_cant_edit(self):
self.assertFalse(self.image.is_editable_by_user(self.user))
class TestRenditions(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_default_backend(self):
# default backend should be pillow
backend = get_image_backend()
self.assertTrue(isinstance(backend, PillowBackend))
def test_minification(self):
rendition = self.image.get_rendition('width-400')
# Check size
self.assertEqual(rendition.width, 400)
self.assertEqual(rendition.height, 300)
def test_resize_to_max(self):
rendition = self.image.get_rendition('max-100x100')
# Check size
self.assertEqual(rendition.width, 100)
self.assertEqual(rendition.height, 75)
def test_resize_to_min(self):
rendition = self.image.get_rendition('min-120x120')
# Check size
self.assertEqual(rendition.width, 160)
self.assertEqual(rendition.height, 120)
def test_resize_to_original(self):
rendition = self.image.get_rendition('original')
# Check size
self.assertEqual(rendition.width, 640)
self.assertEqual(rendition.height, 480)
def test_cache(self):
# Get two renditions with the same filter
first_rendition = self.image.get_rendition('width-400')
second_rendition = self.image.get_rendition('width-400')
# Check that they are the same object
self.assertEqual(first_rendition, second_rendition)
class TestRenditionsWand(TestCase):
def setUp(self):
try:
import wand
except ImportError:
# skip these tests if Wand is not installed
raise unittest.SkipTest(
"Skipping image backend tests for wand, as wand is not installed")
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
self.image.backend = 'wagtail.wagtailimages.backends.wand.WandBackend'
def test_minification(self):
rendition = self.image.get_rendition('width-400')
# Check size
self.assertEqual(rendition.width, 400)
self.assertEqual(rendition.height, 300)
def test_resize_to_max(self):
rendition = self.image.get_rendition('max-100x100')
# Check size
self.assertEqual(rendition.width, 100)
self.assertEqual(rendition.height, 75)
def test_resize_to_min(self):
rendition = self.image.get_rendition('min-120x120')
# Check size
self.assertEqual(rendition.width, 160)
self.assertEqual(rendition.height, 120)
def test_resize_to_original(self):
rendition = self.image.get_rendition('original')
# Check size
self.assertEqual(rendition.width, 640)
self.assertEqual(rendition.height, 480)
def test_cache(self):
# Get two renditions with the same filter
first_rendition = self.image.get_rendition('width-400')
second_rendition = self.image.get_rendition('width-400')
# Check that they are the same object
self.assertEqual(first_rendition, second_rendition)
class TestImageTag(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def render_image_tag(self, image, filter_spec):
temp = template.Template('{% load wagtailimages_tags %}{% image image_obj ' + filter_spec + '%}')
context = template.Context({'image_obj': image})
return temp.render(context)
def test_image_tag(self):
result = self.render_image_tag(self.image, 'width-400')
# Check that all the required HTML attributes are set
self.assertTrue('width="400"' in result)
self.assertTrue('height="300"' in result)
self.assertTrue('alt="Test image"' in result)
def render_image_tag_as(self, image, filter_spec):
temp = template.Template('{% load wagtailimages_tags %}{% image image_obj ' + filter_spec + ' as test_img %}<img {{ test_img.attrs }} />')
context = template.Context({'image_obj': image})
return temp.render(context)
def test_image_tag_attrs(self):
result = self.render_image_tag_as(self.image, 'width-400')
# Check that all the required HTML attributes are set
self.assertTrue('width="400"' in result)
self.assertTrue('height="300"' in result)
self.assertTrue('alt="Test image"' in result)
def render_image_tag_with_extra_attributes(self, image, title):
temp = template.Template('{% load wagtailimages_tags %}{% image image_obj width-400 class="photo" title=title|lower %}')
context = template.Context({'image_obj': image, 'title': title})
return temp.render(context)
def test_image_tag_with_extra_attributes(self):
result = self.render_image_tag_with_extra_attributes(self.image, 'My Wonderful Title')
# Check that all the required HTML attributes are set
self.assertTrue('width="400"' in result)
self.assertTrue('height="300"' in result)
self.assertTrue('class="photo"' in result)
self.assertTrue('title="my wonderful title"' in result)
## ===== ADMIN VIEWS =====
from .utils import Image, get_test_image_file
class TestImageIndexView(TestCase, WagtailTestUtils):
@ -442,99 +206,6 @@ class TestImageChooserUploadView(TestCase, WagtailTestUtils):
# TODO: Test uploading through chooser
class TestFormat(TestCase):
def setUp(self):
# test format
self.format = Format(
'test name',
'test label',
'test classnames',
'test filter spec'
)
# test image
self.image = MagicMock()
self.image.id = 0
def test_editor_attributes(self):
result = self.format.editor_attributes(
self.image,
'test alt text'
)
self.assertEqual(result,
'data-embedtype="image" data-id="0" data-format="test name" data-alt="test alt text" ')
def test_image_to_editor_html(self):
result = self.format.image_to_editor_html(
self.image,
'test alt text'
)
six.assertRegex(self, result,
'<img data-embedtype="image" data-id="0" data-format="test name" data-alt="test alt text" class="test classnames" src="[^"]+" width="1" height="1" alt="test alt text">',
)
def test_image_to_html_no_classnames(self):
self.format.classnames = None
result = self.format.image_to_html(self.image, 'test alt text')
six.assertRegex(self, result,
'<img src="[^"]+" width="1" height="1" alt="test alt text">'
)
self.format.classnames = 'test classnames'
def test_get_image_format(self):
register_image_format(self.format)
result = get_image_format('test name')
self.assertEqual(result, self.format)
class TestUsageCount(TestCase):
fixtures = ['wagtail/tests/fixtures/test.json']
def setUp(self):
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_unused_image_usage_count(self):
self.assertEqual(self.image.get_usage().count(), 0)
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_used_image_document_usage_count(self):
page = EventPage.objects.get(id=4)
event_page_carousel_item = EventPageCarouselItem()
event_page_carousel_item.page = page
event_page_carousel_item.image = self.image
event_page_carousel_item.save()
self.assertEqual(self.image.get_usage().count(), 1)
class TestGetUsage(TestCase):
fixtures = ['wagtail/tests/fixtures/test.json']
def setUp(self):
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_image_get_usage_not_enabled(self):
self.assertEqual(list(self.image.get_usage()), [])
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_unused_image_get_usage(self):
self.assertEqual(list(self.image.get_usage()), [])
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_used_image_document_get_usage(self):
page = EventPage.objects.get(id=4)
event_page_carousel_item = EventPageCarouselItem()
event_page_carousel_item.page = page
event_page_carousel_item.image = self.image
event_page_carousel_item.save()
self.assertTrue(issubclass(Page, type(self.image.get_usage()[0])))
class TestMultipleImageUploader(TestCase, WagtailTestUtils):
"""
This tests the multiple image upload views located in wagtailimages/views/multiple.py
@ -741,79 +412,6 @@ class TestMultipleImageUploader(TestCase, WagtailTestUtils):
self.assertEqual(response.status_code, 400)
class TestSignatureGeneration(TestCase):
def test_signature_generation(self):
self.assertEqual(generate_signature(100, 'fill-800x600'), b'xnZOzQyUg6pkfciqcfRJRosOrGg=')
def test_signature_verification(self):
self.assertTrue(verify_signature(b'xnZOzQyUg6pkfciqcfRJRosOrGg=', 100, 'fill-800x600'))
def test_signature_changes_on_image_id(self):
self.assertFalse(verify_signature(b'xnZOzQyUg6pkfciqcfRJRosOrGg=', 200, 'fill-800x600'))
def test_signature_changes_on_filter_spec(self):
self.assertFalse(verify_signature(b'xnZOzQyUg6pkfciqcfRJRosOrGg=', 100, 'fill-800x700'))
class TestFrontendServeView(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_get(self):
"""
Test a valid GET request to the view
"""
# Generate signature
signature = generate_signature(self.image.id, 'fill-800x600')
# Get the image
response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')))
# Check response
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'image/jpeg')
# Make sure the cache headers are set to expire after at least one month
self.assertIn('Cache-Control', response)
self.assertEqual(response['Cache-Control'].split('=')[0], 'max-age')
self.assertTrue(int(response['Cache-Control'].split('=')[1]) > datetime.timedelta(days=30).seconds)
def test_get_invalid_signature(self):
"""
Test that an invalid signature returns a 403 response
"""
# Generate a signature for the incorrect image id
signature = generate_signature(self.image.id + 1, 'fill-800x600')
# Get the image
response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')))
# Check response
self.assertEqual(response.status_code, 403)
def test_get_invalid_filter_spec(self):
"""
Test that an invalid filter spec returns a 400 response
This is very unlikely to happen in reality. A user would have
to create signature for the invalid filter spec which can't be
done with Wagtails built in URL generator. We should test it
anyway though.
"""
# Generate a signature with the invalid filterspec
signature = generate_signature(self.image.id, 'bad-filter-spec')
# Get the image
response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'bad-filter-spec')))
# Check response
self.assertEqual(response.status_code, 400)
class TestURLGeneratorView(TestCase, WagtailTestUtils):
def setUp(self):
# Create an image for running tests on
@ -947,145 +545,3 @@ class TestGenerateURLView(TestCase, WagtailTestUtils):
self.assertJSONEqual(response.content.decode(), json.dumps({
'error': 'Invalid filter spec.',
}))
class TestIssue573(TestCase):
"""
This tests for a bug which causes filename limit on Renditions to be reached
when the Image has a long original filename and a big focal point key
"""
def test_issue_573(self):
# Create an image with a big filename and focal point
image = Image.objects.create(
title="Test image",
file=get_test_image_file('thisisaverylongfilename-abcdefghijklmnopqrstuvwxyz-supercalifragilisticexpialidocious.png'),
focal_point_x=1000,
focal_point_y=1000,
focal_point_width=1000,
focal_point_height=1000,
)
# Try creating a rendition from that image
# This would crash if the bug is present
image.get_rendition('fill-800x600')
class TestIssue613(TestCase, WagtailTestUtils):
def get_elasticsearch_backend(self):
from django.conf import settings
from wagtail.wagtailsearch.backends import get_search_backend
backend_path = 'wagtail.wagtailsearch.backends.elasticsearch.ElasticSearch'
# Search WAGTAILSEARCH_BACKENDS for an entry that uses the given backend path
for backend_name, backend_conf in settings.WAGTAILSEARCH_BACKENDS.items():
if backend_conf['BACKEND'] == backend_path:
return get_search_backend(backend_name)
else:
# no conf entry found - skip tests for this backend
raise unittest.SkipTest("No WAGTAILSEARCH_BACKENDS entry for the backend %s" % backend_path)
def setUp(self):
self.search_backend = self.get_elasticsearch_backend()
self.login()
def add_image(self, **params):
post_data = {
'title': "Test image",
'file': SimpleUploadedFile('test.png', get_test_image_file().file.getvalue()),
}
post_data.update(params)
response = self.client.post(reverse('wagtailimages_add_image'), post_data)
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailimages_index'))
# Check that the image was created
images = Image.objects.filter(title="Test image")
self.assertEqual(images.count(), 1)
# Test that size was populated correctly
image = images.first()
self.assertEqual(image.width, 640)
self.assertEqual(image.height, 480)
return image
def edit_image(self, **params):
# Create an image to edit
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
# Edit it
post_data = {
'title': "Edited",
}
post_data.update(params)
response = self.client.post(reverse('wagtailimages_edit_image', args=(self.image.id,)), post_data)
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailimages_index'))
# Check that the image was edited
image = Image.objects.get(id=self.image.id)
self.assertEqual(image.title, "Edited")
return image
def test_issue_613_on_add(self):
# Reset the search index
self.search_backend.reset_index()
self.search_backend.add_type(Image)
# Add an image with some tags
image = self.add_image(tags="hello")
self.search_backend.refresh_index()
# Search for it by tag
results = self.search_backend.search("hello", Image)
# Check
self.assertEqual(len(results), 1)
self.assertEqual(results[0].id, image.id)
def test_issue_613_on_edit(self):
# Reset the search index
self.search_backend.reset_index()
self.search_backend.add_type(Image)
# Add an image with some tags
image = self.edit_image(tags="hello")
self.search_backend.refresh_index()
# Search for it by tag
results = self.search_backend.search("hello", Image)
# Check
self.assertEqual(len(results), 1)
self.assertEqual(results[0].id, image.id)
class TestIssue312(TestCase):
def test_duplicate_renditions(self):
# Create an image
image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
# Get two renditions and check that they're the same
rend1 = image.get_rendition('fill-100x100')
rend2 = image.get_rendition('fill-100x100')
self.assertEqual(rend1, rend2)
# Now manually duplicate the renditon and check that the database blocks it
self.assertRaises(
IntegrityError,
Rendition.objects.create,
image=rend1.image,
filter=rend1.filter,
width=rend1.width,
height=rend1.height,
focal_point_key=rend1.focal_point_key,
)

View file

@ -0,0 +1,360 @@
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.test.utils import override_settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db.utils import IntegrityError
from wagtail.tests.utils import WagtailTestUtils, unittest
from wagtail.wagtailcore.models import Page
from wagtail.tests.models import EventPage, EventPageCarouselItem
from wagtail.wagtailimages.models import Rendition
from wagtail.wagtailimages.backends import get_image_backend
from wagtail.wagtailimages.backends.pillow import PillowBackend
from .utils import Image, get_test_image_file
class TestImage(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_is_portrait(self):
self.assertFalse(self.image.is_portrait())
def test_is_landscape(self):
self.assertTrue(self.image.is_landscape())
class TestImagePermissions(TestCase):
def setUp(self):
# Create some user accounts for testing permissions
User = get_user_model()
self.user = User.objects.create_user(username='user', email='user@email.com', password='password')
self.owner = User.objects.create_user(username='owner', email='owner@email.com', password='password')
self.editor = User.objects.create_user(username='editor', email='editor@email.com', password='password')
self.editor.groups.add(Group.objects.get(name='Editors'))
self.administrator = User.objects.create_superuser(username='administrator', email='administrator@email.com', password='password')
# Owner user must have the add_image permission
self.owner.user_permissions.add(Permission.objects.get(codename='add_image'))
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
uploaded_by_user=self.owner,
file=get_test_image_file(),
)
def test_administrator_can_edit(self):
self.assertTrue(self.image.is_editable_by_user(self.administrator))
def test_editor_can_edit(self):
self.assertTrue(self.image.is_editable_by_user(self.editor))
def test_owner_can_edit(self):
self.assertTrue(self.image.is_editable_by_user(self.owner))
def test_user_cant_edit(self):
self.assertFalse(self.image.is_editable_by_user(self.user))
class TestRenditions(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_default_backend(self):
# default backend should be pillow
backend = get_image_backend()
self.assertTrue(isinstance(backend, PillowBackend))
def test_minification(self):
rendition = self.image.get_rendition('width-400')
# Check size
self.assertEqual(rendition.width, 400)
self.assertEqual(rendition.height, 300)
def test_resize_to_max(self):
rendition = self.image.get_rendition('max-100x100')
# Check size
self.assertEqual(rendition.width, 100)
self.assertEqual(rendition.height, 75)
def test_resize_to_min(self):
rendition = self.image.get_rendition('min-120x120')
# Check size
self.assertEqual(rendition.width, 160)
self.assertEqual(rendition.height, 120)
def test_resize_to_original(self):
rendition = self.image.get_rendition('original')
# Check size
self.assertEqual(rendition.width, 640)
self.assertEqual(rendition.height, 480)
def test_cache(self):
# Get two renditions with the same filter
first_rendition = self.image.get_rendition('width-400')
second_rendition = self.image.get_rendition('width-400')
# Check that they are the same object
self.assertEqual(first_rendition, second_rendition)
class TestRenditionsWand(TestCase):
def setUp(self):
try:
import wand
except ImportError:
# skip these tests if Wand is not installed
raise unittest.SkipTest(
"Skipping image backend tests for wand, as wand is not installed")
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
self.image.backend = 'wagtail.wagtailimages.backends.wand.WandBackend'
def test_minification(self):
rendition = self.image.get_rendition('width-400')
# Check size
self.assertEqual(rendition.width, 400)
self.assertEqual(rendition.height, 300)
def test_resize_to_max(self):
rendition = self.image.get_rendition('max-100x100')
# Check size
self.assertEqual(rendition.width, 100)
self.assertEqual(rendition.height, 75)
def test_resize_to_min(self):
rendition = self.image.get_rendition('min-120x120')
# Check size
self.assertEqual(rendition.width, 160)
self.assertEqual(rendition.height, 120)
def test_resize_to_original(self):
rendition = self.image.get_rendition('original')
# Check size
self.assertEqual(rendition.width, 640)
self.assertEqual(rendition.height, 480)
def test_cache(self):
# Get two renditions with the same filter
first_rendition = self.image.get_rendition('width-400')
second_rendition = self.image.get_rendition('width-400')
# Check that they are the same object
self.assertEqual(first_rendition, second_rendition)
class TestUsageCount(TestCase):
fixtures = ['wagtail/tests/fixtures/test.json']
def setUp(self):
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_unused_image_usage_count(self):
self.assertEqual(self.image.get_usage().count(), 0)
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_used_image_document_usage_count(self):
page = EventPage.objects.get(id=4)
event_page_carousel_item = EventPageCarouselItem()
event_page_carousel_item.page = page
event_page_carousel_item.image = self.image
event_page_carousel_item.save()
self.assertEqual(self.image.get_usage().count(), 1)
class TestGetUsage(TestCase):
fixtures = ['wagtail/tests/fixtures/test.json']
def setUp(self):
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_image_get_usage_not_enabled(self):
self.assertEqual(list(self.image.get_usage()), [])
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_unused_image_get_usage(self):
self.assertEqual(list(self.image.get_usage()), [])
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_used_image_document_get_usage(self):
page = EventPage.objects.get(id=4)
event_page_carousel_item = EventPageCarouselItem()
event_page_carousel_item.page = page
event_page_carousel_item.image = self.image
event_page_carousel_item.save()
self.assertTrue(issubclass(Page, type(self.image.get_usage()[0])))
class TestIssue573(TestCase):
"""
This tests for a bug which causes filename limit on Renditions to be reached
when the Image has a long original filename and a big focal point key
"""
def test_issue_573(self):
# Create an image with a big filename and focal point
image = Image.objects.create(
title="Test image",
file=get_test_image_file('thisisaverylongfilename-abcdefghijklmnopqrstuvwxyz-supercalifragilisticexpialidocious.png'),
focal_point_x=1000,
focal_point_y=1000,
focal_point_width=1000,
focal_point_height=1000,
)
# Try creating a rendition from that image
# This would crash if the bug is present
image.get_rendition('fill-800x600')
class TestIssue613(TestCase, WagtailTestUtils):
def get_elasticsearch_backend(self):
from django.conf import settings
from wagtail.wagtailsearch.backends import get_search_backend
backend_path = 'wagtail.wagtailsearch.backends.elasticsearch.ElasticSearch'
# Search WAGTAILSEARCH_BACKENDS for an entry that uses the given backend path
for backend_name, backend_conf in settings.WAGTAILSEARCH_BACKENDS.items():
if backend_conf['BACKEND'] == backend_path:
return get_search_backend(backend_name)
else:
# no conf entry found - skip tests for this backend
raise unittest.SkipTest("No WAGTAILSEARCH_BACKENDS entry for the backend %s" % backend_path)
def setUp(self):
self.search_backend = self.get_elasticsearch_backend()
self.login()
def add_image(self, **params):
post_data = {
'title': "Test image",
'file': SimpleUploadedFile('test.png', get_test_image_file().file.getvalue()),
}
post_data.update(params)
response = self.client.post(reverse('wagtailimages_add_image'), post_data)
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailimages_index'))
# Check that the image was created
images = Image.objects.filter(title="Test image")
self.assertEqual(images.count(), 1)
# Test that size was populated correctly
image = images.first()
self.assertEqual(image.width, 640)
self.assertEqual(image.height, 480)
return image
def edit_image(self, **params):
# Create an image to edit
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
# Edit it
post_data = {
'title': "Edited",
}
post_data.update(params)
response = self.client.post(reverse('wagtailimages_edit_image', args=(self.image.id,)), post_data)
# Should redirect back to index
self.assertRedirects(response, reverse('wagtailimages_index'))
# Check that the image was edited
image = Image.objects.get(id=self.image.id)
self.assertEqual(image.title, "Edited")
return image
def test_issue_613_on_add(self):
# Reset the search index
self.search_backend.reset_index()
self.search_backend.add_type(Image)
# Add an image with some tags
image = self.add_image(tags="hello")
self.search_backend.refresh_index()
# Search for it by tag
results = self.search_backend.search("hello", Image)
# Check
self.assertEqual(len(results), 1)
self.assertEqual(results[0].id, image.id)
def test_issue_613_on_edit(self):
# Reset the search index
self.search_backend.reset_index()
self.search_backend.add_type(Image)
# Add an image with some tags
image = self.edit_image(tags="hello")
self.search_backend.refresh_index()
# Search for it by tag
results = self.search_backend.search("hello", Image)
# Check
self.assertEqual(len(results), 1)
self.assertEqual(results[0].id, image.id)
class TestIssue312(TestCase):
def test_duplicate_renditions(self):
# Create an image
image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
# Get two renditions and check that they're the same
rend1 = image.get_rendition('fill-100x100')
rend2 = image.get_rendition('fill-100x100')
self.assertEqual(rend1, rend2)
# Now manually duplicate the renditon and check that the database blocks it
self.assertRaises(
IntegrityError,
Rendition.objects.create,
image=rend1.image,
filter=rend1.filter,
width=rend1.width,
height=rend1.height,
focal_point_key=rend1.focal_point_key,
)

View file

@ -0,0 +1,179 @@
import datetime
from mock import MagicMock
from django.test import TestCase
from django import template
from django.utils import six
from django.core.urlresolvers import reverse
from wagtail.wagtailimages.utils.crypto import generate_signature, verify_signature
from wagtail.wagtailimages.formats import Format, get_image_format, register_image_format
from .utils import Image, get_test_image_file
class TestImageTag(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def render_image_tag(self, image, filter_spec):
temp = template.Template('{% load wagtailimages_tags %}{% image image_obj ' + filter_spec + '%}')
context = template.Context({'image_obj': image})
return temp.render(context)
def test_image_tag(self):
result = self.render_image_tag(self.image, 'width-400')
# Check that all the required HTML attributes are set
self.assertTrue('width="400"' in result)
self.assertTrue('height="300"' in result)
self.assertTrue('alt="Test image"' in result)
def render_image_tag_as(self, image, filter_spec):
temp = template.Template('{% load wagtailimages_tags %}{% image image_obj ' + filter_spec + ' as test_img %}<img {{ test_img.attrs }} />')
context = template.Context({'image_obj': image})
return temp.render(context)
def test_image_tag_attrs(self):
result = self.render_image_tag_as(self.image, 'width-400')
# Check that all the required HTML attributes are set
self.assertTrue('width="400"' in result)
self.assertTrue('height="300"' in result)
self.assertTrue('alt="Test image"' in result)
def render_image_tag_with_extra_attributes(self, image, title):
temp = template.Template('{% load wagtailimages_tags %}{% image image_obj width-400 class="photo" title=title|lower %}')
context = template.Context({'image_obj': image, 'title': title})
return temp.render(context)
def test_image_tag_with_extra_attributes(self):
result = self.render_image_tag_with_extra_attributes(self.image, 'My Wonderful Title')
# Check that all the required HTML attributes are set
self.assertTrue('width="400"' in result)
self.assertTrue('height="300"' in result)
self.assertTrue('class="photo"' in result)
self.assertTrue('title="my wonderful title"' in result)
class TestFormat(TestCase):
def setUp(self):
# test format
self.format = Format(
'test name',
'test label',
'test classnames',
'test filter spec'
)
# test image
self.image = MagicMock()
self.image.id = 0
def test_editor_attributes(self):
result = self.format.editor_attributes(
self.image,
'test alt text'
)
self.assertEqual(result,
'data-embedtype="image" data-id="0" data-format="test name" data-alt="test alt text" ')
def test_image_to_editor_html(self):
result = self.format.image_to_editor_html(
self.image,
'test alt text'
)
six.assertRegex(self, result,
'<img data-embedtype="image" data-id="0" data-format="test name" data-alt="test alt text" class="test classnames" src="[^"]+" width="1" height="1" alt="test alt text">',
)
def test_image_to_html_no_classnames(self):
self.format.classnames = None
result = self.format.image_to_html(self.image, 'test alt text')
six.assertRegex(self, result,
'<img src="[^"]+" width="1" height="1" alt="test alt text">'
)
self.format.classnames = 'test classnames'
def test_get_image_format(self):
register_image_format(self.format)
result = get_image_format('test name')
self.assertEqual(result, self.format)
class TestSignatureGeneration(TestCase):
def test_signature_generation(self):
self.assertEqual(generate_signature(100, 'fill-800x600'), b'xnZOzQyUg6pkfciqcfRJRosOrGg=')
def test_signature_verification(self):
self.assertTrue(verify_signature(b'xnZOzQyUg6pkfciqcfRJRosOrGg=', 100, 'fill-800x600'))
def test_signature_changes_on_image_id(self):
self.assertFalse(verify_signature(b'xnZOzQyUg6pkfciqcfRJRosOrGg=', 200, 'fill-800x600'))
def test_signature_changes_on_filter_spec(self):
self.assertFalse(verify_signature(b'xnZOzQyUg6pkfciqcfRJRosOrGg=', 100, 'fill-800x700'))
class TestFrontendServeView(TestCase):
def setUp(self):
# Create an image for running tests on
self.image = Image.objects.create(
title="Test image",
file=get_test_image_file(),
)
def test_get(self):
"""
Test a valid GET request to the view
"""
# Generate signature
signature = generate_signature(self.image.id, 'fill-800x600')
# Get the image
response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')))
# Check response
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'image/jpeg')
# Make sure the cache headers are set to expire after at least one month
self.assertIn('Cache-Control', response)
self.assertEqual(response['Cache-Control'].split('=')[0], 'max-age')
self.assertTrue(int(response['Cache-Control'].split('=')[1]) > datetime.timedelta(days=30).seconds)
def test_get_invalid_signature(self):
"""
Test that an invalid signature returns a 403 response
"""
# Generate a signature for the incorrect image id
signature = generate_signature(self.image.id + 1, 'fill-800x600')
# Get the image
response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'fill-800x600')))
# Check response
self.assertEqual(response.status_code, 403)
def test_get_invalid_filter_spec(self):
"""
Test that an invalid filter spec returns a 400 response
This is very unlikely to happen in reality. A user would have
to create signature for the invalid filter spec which can't be
done with Wagtails built in URL generator. We should test it
anyway though.
"""
# Generate a signature with the invalid filterspec
signature = generate_signature(self.image.id, 'bad-filter-spec')
# Get the image
response = self.client.get(reverse('wagtailimages_serve', args=(signature, self.image.id, 'bad-filter-spec')))
# Check response
self.assertEqual(response.status_code, 400)

View file

@ -0,0 +1,16 @@
import PIL.Image
from six import BytesIO
from django.core.files.images import ImageFile
from wagtail.wagtailimages.models import get_image_model
Image = get_image_model()
def get_test_image_file(filename='test.png'):
f = BytesIO()
image = PIL.Image.new('RGB', (640, 480), 'white')
image.save(f, 'PNG')
return ImageFile(f, name=filename)