mirror of https://github.com/zulip/zulip.git
tests: Switch from PIL to pyvips.
This commit is contained in:
parent
b14a33c659
commit
0070b5da78
|
@ -1,4 +1,3 @@
|
||||||
import io
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
@ -8,9 +7,9 @@ from unittest.mock import patch
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
|
import pyvips
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
from PIL import Image
|
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
from urllib3 import encode_multipart_formdata
|
from urllib3 import encode_multipart_formdata
|
||||||
from urllib3.fields import RequestField
|
from urllib3.fields import RequestField
|
||||||
|
@ -1258,7 +1257,9 @@ class AvatarTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
if rfname is not None:
|
if rfname is not None:
|
||||||
response = self.client_get(url)
|
response = self.client_get(url)
|
||||||
data = response.getvalue()
|
data = response.getvalue()
|
||||||
self.assertEqual(Image.open(io.BytesIO(data)).size, (100, 100))
|
avatar_image = pyvips.Image.new_from_buffer(data, "")
|
||||||
|
self.assertEqual(avatar_image.height, 100)
|
||||||
|
self.assertEqual(avatar_image.width, 100)
|
||||||
|
|
||||||
# Verify that the medium-size avatar was created
|
# Verify that the medium-size avatar was created
|
||||||
user_profile = self.example_user("hamlet")
|
user_profile = self.example_user("hamlet")
|
||||||
|
@ -1385,21 +1386,27 @@ class AvatarTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
|
|
||||||
|
|
||||||
class EmojiTest(UploadSerializeMixin, ZulipTestCase):
|
class EmojiTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
# While testing GIF resizing, we can't test if the final GIF has the same
|
|
||||||
# number of frames as the original one because PIL drops duplicate frames
|
|
||||||
# with a corresponding increase in the duration of the previous frame.
|
|
||||||
def test_resize_emoji(self) -> None:
|
def test_resize_emoji(self) -> None:
|
||||||
# Test unequal width and height of animated GIF image
|
# Test unequal width and height of animated GIF image
|
||||||
animated_unequal_img_data = read_test_image_file("animated_unequal_img.gif")
|
animated_unequal_img_data = read_test_image_file("animated_unequal_img.gif")
|
||||||
|
original_image = pyvips.Image.new_from_buffer(animated_unequal_img_data, "n=-1")
|
||||||
resized_img_data, is_animated, still_img_data = resize_emoji(
|
resized_img_data, is_animated, still_img_data = resize_emoji(
|
||||||
animated_unequal_img_data, "animated_unequal_img.gif", size=50
|
animated_unequal_img_data, "animated_unequal_img.gif", size=50
|
||||||
)
|
)
|
||||||
im = Image.open(io.BytesIO(resized_img_data))
|
|
||||||
self.assertEqual((50, 50), im.size)
|
|
||||||
self.assertTrue(is_animated)
|
self.assertTrue(is_animated)
|
||||||
assert still_img_data is not None
|
assert still_img_data is not None
|
||||||
still_image = Image.open(io.BytesIO(still_img_data))
|
emoji_image = pyvips.Image.new_from_buffer(resized_img_data, "n=-1")
|
||||||
self.assertEqual((50, 50), still_image.size)
|
self.assertEqual(emoji_image.get("vips-loader"), "gifload_buffer")
|
||||||
|
self.assertEqual(emoji_image.get_n_pages(), original_image.get_n_pages())
|
||||||
|
self.assertEqual(emoji_image.get("page-height"), 50)
|
||||||
|
self.assertEqual(emoji_image.height, 150)
|
||||||
|
self.assertEqual(emoji_image.width, 50)
|
||||||
|
|
||||||
|
still_image = pyvips.Image.new_from_buffer(still_img_data, "")
|
||||||
|
self.assertEqual(still_image.get("vips-loader"), "pngload_buffer")
|
||||||
|
self.assertEqual(still_image.get_n_pages(), 1)
|
||||||
|
self.assertEqual(still_image.height, 50)
|
||||||
|
self.assertEqual(still_image.width, 50)
|
||||||
|
|
||||||
# Test corrupt image exception
|
# Test corrupt image exception
|
||||||
corrupted_img_data = read_test_image_file("corrupt.gif")
|
corrupted_img_data = read_test_image_file("corrupt.gif")
|
||||||
|
@ -1407,15 +1414,23 @@ class EmojiTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
resize_emoji(corrupted_img_data, "corrupt.gif")
|
resize_emoji(corrupted_img_data, "corrupt.gif")
|
||||||
|
|
||||||
animated_large_img_data = read_test_image_file("animated_large_img.gif")
|
animated_large_img_data = read_test_image_file("animated_large_img.gif")
|
||||||
|
original_image = pyvips.Image.new_from_buffer(animated_large_img_data, "n=-1")
|
||||||
resized_img_data, is_animated, still_img_data = resize_emoji(
|
resized_img_data, is_animated, still_img_data = resize_emoji(
|
||||||
animated_large_img_data, "animated_large_img.gif", size=50
|
animated_large_img_data, "animated_large_img.gif", size=50
|
||||||
)
|
)
|
||||||
im = Image.open(io.BytesIO(resized_img_data))
|
emoji_image = pyvips.Image.new_from_buffer(resized_img_data, "n=-1")
|
||||||
self.assertEqual((50, 50), im.size)
|
self.assertEqual(emoji_image.get("vips-loader"), "gifload_buffer")
|
||||||
|
self.assertEqual(emoji_image.get_n_pages(), original_image.get_n_pages())
|
||||||
|
self.assertEqual(emoji_image.get("page-height"), 50)
|
||||||
|
self.assertEqual(emoji_image.height, 150)
|
||||||
|
self.assertEqual(emoji_image.width, 50)
|
||||||
self.assertTrue(is_animated)
|
self.assertTrue(is_animated)
|
||||||
assert still_img_data
|
assert still_img_data
|
||||||
still_image = Image.open(io.BytesIO(still_img_data))
|
still_image = pyvips.Image.new_from_buffer(still_img_data, "")
|
||||||
self.assertEqual((50, 50), still_image.size)
|
self.assertEqual(still_image.get("vips-loader"), "pngload_buffer")
|
||||||
|
self.assertEqual(still_image.get_n_pages(), 1)
|
||||||
|
self.assertEqual(still_image.height, 50)
|
||||||
|
self.assertEqual(still_image.width, 50)
|
||||||
|
|
||||||
# Test an image file with too many bytes is not resized
|
# Test an image file with too many bytes is not resized
|
||||||
with patch("zerver.lib.thumbnail.MAX_EMOJI_GIF_FILE_SIZE_BYTES", 1024):
|
with patch("zerver.lib.thumbnail.MAX_EMOJI_GIF_FILE_SIZE_BYTES", 1024):
|
||||||
|
@ -1432,8 +1447,11 @@ class EmojiTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
resized_img_data, is_animated, no_still_data = resize_emoji(
|
resized_img_data, is_animated, no_still_data = resize_emoji(
|
||||||
still_large_img_data, "still_large_img.gif", size=50
|
still_large_img_data, "still_large_img.gif", size=50
|
||||||
)
|
)
|
||||||
im = Image.open(io.BytesIO(resized_img_data))
|
emoji_image = pyvips.Image.new_from_buffer(resized_img_data, "n=-1")
|
||||||
self.assertEqual((50, 50), im.size)
|
self.assertEqual(emoji_image.get("vips-loader"), "gifload_buffer")
|
||||||
|
self.assertEqual(emoji_image.height, 50)
|
||||||
|
self.assertEqual(emoji_image.width, 50)
|
||||||
|
self.assertEqual(emoji_image.get_n_pages(), 1)
|
||||||
self.assertFalse(is_animated)
|
self.assertFalse(is_animated)
|
||||||
assert no_still_data is None
|
assert no_still_data is None
|
||||||
|
|
||||||
|
@ -1442,8 +1460,11 @@ class EmojiTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
resized_img_data, is_animated, no_still_data = resize_emoji(
|
resized_img_data, is_animated, no_still_data = resize_emoji(
|
||||||
still_large_img_data, "img.jpg", size=50
|
still_large_img_data, "img.jpg", size=50
|
||||||
)
|
)
|
||||||
im = Image.open(io.BytesIO(resized_img_data))
|
emoji_image = pyvips.Image.new_from_buffer(resized_img_data, "")
|
||||||
self.assertEqual((50, 50), im.size)
|
self.assertEqual(emoji_image.get("vips-loader"), "jpegload_buffer")
|
||||||
|
self.assertEqual(emoji_image.height, 50)
|
||||||
|
self.assertEqual(emoji_image.width, 50)
|
||||||
|
self.assertEqual(emoji_image.get_n_pages(), 1)
|
||||||
self.assertFalse(is_animated)
|
self.assertFalse(is_animated)
|
||||||
assert no_still_data is None
|
assert no_still_data is None
|
||||||
|
|
||||||
|
@ -1535,7 +1556,9 @@ class RealmIconTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
if rfname is not None:
|
if rfname is not None:
|
||||||
response = self.client_get(url)
|
response = self.client_get(url)
|
||||||
data = response.getvalue()
|
data = response.getvalue()
|
||||||
self.assertEqual(Image.open(io.BytesIO(data)).size, (100, 100))
|
response_image = pyvips.Image.new_from_buffer(data, "")
|
||||||
|
self.assertEqual(response_image.height, 100)
|
||||||
|
self.assertEqual(response_image.width, 100)
|
||||||
|
|
||||||
def test_invalid_icons(self) -> None:
|
def test_invalid_icons(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -1719,7 +1742,9 @@ class RealmLogoTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
data = response.getvalue()
|
data = response.getvalue()
|
||||||
# size should be 100 x 100 because thumbnail keeps aspect ratio
|
# size should be 100 x 100 because thumbnail keeps aspect ratio
|
||||||
# while trying to fit in a 800 x 100 box without losing part of the image
|
# while trying to fit in a 800 x 100 box without losing part of the image
|
||||||
self.assertEqual(Image.open(io.BytesIO(data)).size, (100, 100))
|
response_image = pyvips.Image.new_from_buffer(data, "")
|
||||||
|
self.assertEqual(response_image.height, 100)
|
||||||
|
self.assertEqual(response_image.width, 100)
|
||||||
|
|
||||||
def test_invalid_logo_upload(self) -> None:
|
def test_invalid_logo_upload(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,8 +3,8 @@ import re
|
||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
from urllib.parse import urlsplit
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
|
import pyvips
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
import zerver.lib.upload
|
import zerver.lib.upload
|
||||||
from zerver.lib.avatar_hash import user_avatar_path
|
from zerver.lib.avatar_hash import user_avatar_path
|
||||||
|
@ -229,9 +229,9 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
with open(file_path + ".original", "rb") as original_file:
|
with open(file_path + ".original", "rb") as original_file:
|
||||||
self.assertEqual(read_test_image_file("img.png"), original_file.read())
|
self.assertEqual(read_test_image_file("img.png"), original_file.read())
|
||||||
|
|
||||||
expected_size = (DEFAULT_EMOJI_SIZE, DEFAULT_EMOJI_SIZE)
|
resized_emoji = pyvips.Image.new_from_file(file_path)
|
||||||
with Image.open(file_path) as resized_image:
|
self.assertEqual(DEFAULT_EMOJI_SIZE, resized_emoji.width)
|
||||||
self.assertEqual(expected_size, resized_image.size)
|
self.assertEqual(DEFAULT_EMOJI_SIZE, resized_emoji.height)
|
||||||
|
|
||||||
def test_tarball_upload_and_deletion(self) -> None:
|
def test_tarball_upload_and_deletion(self) -> None:
|
||||||
user_profile = self.example_user("iago")
|
user_profile = self.example_user("iago")
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import io
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
|
@ -6,8 +5,8 @@ from unittest.mock import patch
|
||||||
from urllib.parse import urlsplit
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import botocore.exceptions
|
import botocore.exceptions
|
||||||
|
import pyvips
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
import zerver.lib.upload
|
import zerver.lib.upload
|
||||||
from zerver.actions.user_settings import do_delete_avatar_image
|
from zerver.actions.user_settings import do_delete_avatar_image
|
||||||
|
@ -414,9 +413,9 @@ class S3Test(ZulipTestCase):
|
||||||
|
|
||||||
resized_path_id = os.path.join(str(user_profile.realm.id), "realm", "icon.png")
|
resized_path_id = os.path.join(str(user_profile.realm.id), "realm", "icon.png")
|
||||||
resized_data = bucket.Object(resized_path_id).get()["Body"].read()
|
resized_data = bucket.Object(resized_path_id).get()["Body"].read()
|
||||||
# while trying to fit in a 800 x 100 box without losing part of the image
|
resized_image = pyvips.Image.new_from_buffer(resized_data, "")
|
||||||
resized_image = Image.open(io.BytesIO(resized_data)).size
|
self.assertEqual(DEFAULT_AVATAR_SIZE, resized_image.height)
|
||||||
self.assertEqual(resized_image, (DEFAULT_AVATAR_SIZE, DEFAULT_AVATAR_SIZE))
|
self.assertEqual(DEFAULT_AVATAR_SIZE, resized_image.width)
|
||||||
|
|
||||||
@use_s3_backend
|
@use_s3_backend
|
||||||
def _test_upload_logo_image(self, night: bool, file_name: str) -> None:
|
def _test_upload_logo_image(self, night: bool, file_name: str) -> None:
|
||||||
|
@ -436,8 +435,9 @@ class S3Test(ZulipTestCase):
|
||||||
|
|
||||||
resized_path_id = os.path.join(str(user_profile.realm.id), "realm", f"{file_name}.png")
|
resized_path_id = os.path.join(str(user_profile.realm.id), "realm", f"{file_name}.png")
|
||||||
resized_data = bucket.Object(resized_path_id).get()["Body"].read()
|
resized_data = bucket.Object(resized_path_id).get()["Body"].read()
|
||||||
resized_image = Image.open(io.BytesIO(resized_data)).size
|
resized_image = pyvips.Image.new_from_buffer(resized_data, "")
|
||||||
self.assertEqual(resized_image, (DEFAULT_AVATAR_SIZE, DEFAULT_AVATAR_SIZE))
|
self.assertEqual(DEFAULT_AVATAR_SIZE, resized_image.height)
|
||||||
|
self.assertEqual(DEFAULT_AVATAR_SIZE, resized_image.width)
|
||||||
|
|
||||||
def test_upload_realm_logo_image(self) -> None:
|
def test_upload_realm_logo_image(self) -> None:
|
||||||
self._test_upload_logo_image(night=False, file_name="logo")
|
self._test_upload_logo_image(night=False, file_name="logo")
|
||||||
|
@ -489,8 +489,9 @@ class S3Test(ZulipTestCase):
|
||||||
self.assertEqual(read_test_image_file("img.png"), original_key.get()["Body"].read())
|
self.assertEqual(read_test_image_file("img.png"), original_key.get()["Body"].read())
|
||||||
|
|
||||||
resized_data = bucket.Object(emoji_path).get()["Body"].read()
|
resized_data = bucket.Object(emoji_path).get()["Body"].read()
|
||||||
resized_image = Image.open(io.BytesIO(resized_data))
|
resized_image = pyvips.Image.new_from_buffer(resized_data, "")
|
||||||
self.assertEqual(resized_image.size, (DEFAULT_EMOJI_SIZE, DEFAULT_EMOJI_SIZE))
|
self.assertEqual(DEFAULT_EMOJI_SIZE, resized_image.height)
|
||||||
|
self.assertEqual(DEFAULT_EMOJI_SIZE, resized_image.width)
|
||||||
|
|
||||||
@use_s3_backend
|
@use_s3_backend
|
||||||
def test_tarball_upload_and_deletion(self) -> None:
|
def test_tarball_upload_and_deletion(self) -> None:
|
||||||
|
|
Loading…
Reference in New Issue