test_classes: Extract a thumbnailing output format helper.

This commit is contained in:
Alex Vandiver
2024-07-19 17:37:40 +00:00
committed by Tim Abbott
parent 94ff443c00
commit aacf28f7e3
2 changed files with 40 additions and 49 deletions

View File

@@ -74,6 +74,7 @@ from zerver.lib.test_helpers import (
instrument_url, instrument_url,
queries_captured, queries_captured,
) )
from zerver.lib.thumbnail import ThumbnailFormat
from zerver.lib.topic import RESOLVED_TOPIC_PREFIX, filter_by_topic_name_via_message from zerver.lib.topic import RESOLVED_TOPIC_PREFIX, filter_by_topic_name_via_message
from zerver.lib.user_groups import get_system_user_group_for_user from zerver.lib.user_groups import get_system_user_group_for_user
from zerver.lib.users import get_api_key from zerver.lib.users import get_api_key
@@ -2018,6 +2019,14 @@ Output:
user_group.direct_subgroups.set(direct_subgroups) user_group.direct_subgroups.set(direct_subgroups)
return user_group return user_group
@contextmanager
def thumbnail_formats(self, *thumbnail_formats: ThumbnailFormat) -> Iterator[None]:
with (
mock.patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", thumbnail_formats),
mock.patch("zerver.views.upload.THUMBNAIL_OUTPUT_FORMATS", thumbnail_formats),
):
yield
class ZulipTestCase(ZulipTestCaseMixin, TestCase): class ZulipTestCase(ZulipTestCaseMixin, TestCase):
@contextmanager @contextmanager

View File

@@ -1,6 +1,4 @@
import re import re
from collections.abc import Iterator
from contextlib import contextmanager
from dataclasses import asdict from dataclasses import asdict
from io import StringIO from io import StringIO
from unittest.mock import patch from unittest.mock import patch
@@ -300,15 +298,14 @@ class ThumbnailClassesTest(ZulipTestCase):
class TestStoreThumbnail(ZulipTestCase): class TestStoreThumbnail(ZulipTestCase):
@patch(
"zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS",
[ThumbnailFormat("webp", 100, 75, animated=True)],
)
def test_upload_image(self) -> None: def test_upload_image(self) -> None:
assert settings.LOCAL_FILES_DIR assert settings.LOCAL_FILES_DIR
self.login_user(self.example_user("hamlet")) self.login_user(self.example_user("hamlet"))
with self.captureOnCommitCallbacks(execute=True): with (
self.thumbnail_formats(ThumbnailFormat("webp", 100, 75, animated=True)),
self.captureOnCommitCallbacks(execute=True),
):
with get_test_image_file("animated_unequal_img.gif") as image_file: with get_test_image_file("animated_unequal_img.gif") as image_file:
response = self.assert_json_success( response = self.assert_json_success(
self.client_post("/json/user_uploads", {"file": image_file}) self.client_post("/json/user_uploads", {"file": image_file})
@@ -354,10 +351,10 @@ class TestStoreThumbnail(ZulipTestCase):
sorted([path_id, f"thumbnail/{path_id}/100x75-anim.webp"]), sorted([path_id, f"thumbnail/{path_id}/100x75-anim.webp"]),
) )
self.assertEqual(ensure_thumbnails(image_attachment), 0) with self.thumbnail_formats(ThumbnailFormat("webp", 100, 75, animated=True)):
self.assertEqual(ensure_thumbnails(image_attachment), 0)
bigger_thumb_format = ThumbnailFormat("webp", 150, 100, opts="Q=90", animated=False) with self.thumbnail_formats(ThumbnailFormat("webp", 150, 100, opts="Q=90", animated=False)):
with patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [bigger_thumb_format]):
self.assertEqual(ensure_thumbnails(image_attachment), 1) self.assertEqual(ensure_thumbnails(image_attachment), 1)
self.assert_length(image_attachment.thumbnail_metadata, 2) self.assert_length(image_attachment.thumbnail_metadata, 2)
@@ -383,10 +380,6 @@ class TestStoreThumbnail(ZulipTestCase):
), ),
) )
@patch(
"zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS",
[ThumbnailFormat("webp", 100, 75, animated=False)],
)
def test_bad_upload(self) -> None: def test_bad_upload(self) -> None:
assert settings.LOCAL_FILES_DIR assert settings.LOCAL_FILES_DIR
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
@@ -412,16 +405,19 @@ class TestStoreThumbnail(ZulipTestCase):
frames=1, frames=1,
thumbnail_metadata=[], thumbnail_metadata=[],
) )
self.assert_length(missing_thumbnails(image_attachment), 1) with self.thumbnail_formats(ThumbnailFormat("webp", 100, 75, animated=False)):
with self.assertLogs("zerver.worker.thumbnail", level="ERROR") as error_log: self.assert_length(missing_thumbnails(image_attachment), 1)
self.assertEqual(ensure_thumbnails(image_attachment), 0)
libvips_version = (pyvips.version(0), pyvips.version(1)) with self.assertLogs("zerver.worker.thumbnail", level="ERROR") as error_log:
# This error message changed self.assertEqual(ensure_thumbnails(image_attachment), 0)
if libvips_version < (8, 13): # nocoverage # branch varies with version
expected_message = "gifload_buffer: Insufficient data to do anything" libvips_version = (pyvips.version(0), pyvips.version(1))
else: # nocoverage # branch varies with version # This error message changed
expected_message = "gifload_buffer: no frames in GIF" if libvips_version < (8, 13): # nocoverage # branch varies with version
self.assertTrue(expected_message in error_log.output[0]) expected_message = "gifload_buffer: Insufficient data to do anything"
else: # nocoverage # branch varies with version
expected_message = "gifload_buffer: no frames in GIF"
self.assertTrue(expected_message in error_log.output[0])
# It should have now been removed # It should have now been removed
self.assertEqual(ImageAttachment.objects.filter(path_id=path_id).count(), 0) self.assertEqual(ImageAttachment.objects.filter(path_id=path_id).count(), 0)
@@ -434,22 +430,20 @@ class TestStoreThumbnail(ZulipTestCase):
frames=1, frames=1,
thumbnail_metadata=[], thumbnail_metadata=[],
) )
with patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", []): with self.thumbnail_formats():
self.assertEqual(missing_thumbnails(image_attachment), []) self.assertEqual(missing_thumbnails(image_attachment), [])
still_webp = ThumbnailFormat("webp", 100, 75, animated=False, opts="Q=90") still_webp = ThumbnailFormat("webp", 100, 75, animated=False, opts="Q=90")
with patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp]): with self.thumbnail_formats(still_webp):
self.assertEqual(missing_thumbnails(image_attachment), [still_webp]) self.assertEqual(missing_thumbnails(image_attachment), [still_webp])
anim_webp = ThumbnailFormat("webp", 100, 75, animated=True, opts="Q=90") anim_webp = ThumbnailFormat("webp", 100, 75, animated=True, opts="Q=90")
with patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp, anim_webp]): with self.thumbnail_formats(still_webp, anim_webp):
# It's not animated, so the animated format doesn't appear at all # It's not animated, so the animated format doesn't appear at all
self.assertEqual(missing_thumbnails(image_attachment), [still_webp]) self.assertEqual(missing_thumbnails(image_attachment), [still_webp])
still_jpeg = ThumbnailFormat("jpeg", 100, 75, animated=False, opts="Q=90") still_jpeg = ThumbnailFormat("jpeg", 100, 75, animated=False, opts="Q=90")
with patch( with self.thumbnail_formats(still_webp, anim_webp, still_jpeg):
"zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp, anim_webp, still_jpeg]
):
# But other still formats do # But other still formats do
self.assertEqual(missing_thumbnails(image_attachment), [still_webp, still_jpeg]) self.assertEqual(missing_thumbnails(image_attachment), [still_webp, still_jpeg])
@@ -465,28 +459,16 @@ class TestStoreThumbnail(ZulipTestCase):
byte_size=1234, byte_size=1234,
) )
image_attachment.thumbnail_metadata = [asdict(rendered_still_webp)] image_attachment.thumbnail_metadata = [asdict(rendered_still_webp)]
with patch( with self.thumbnail_formats(still_webp, anim_webp, still_jpeg):
"zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp, anim_webp, still_jpeg]
):
self.assertEqual(missing_thumbnails(image_attachment), [still_jpeg]) self.assertEqual(missing_thumbnails(image_attachment), [still_jpeg])
# If we have the still, and it's animated, we do still need the animated # If we have the still, and it's animated, we do still need the animated
image_attachment.frames = 10 image_attachment.frames = 10
with patch( with self.thumbnail_formats(still_webp, anim_webp, still_jpeg):
"zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp, anim_webp, still_jpeg]
):
self.assertEqual(missing_thumbnails(image_attachment), [anim_webp, still_jpeg]) self.assertEqual(missing_thumbnails(image_attachment), [anim_webp, still_jpeg])
class TestThumbnailRetrieval(ZulipTestCase): class TestThumbnailRetrieval(ZulipTestCase):
@contextmanager
def mock_formats(self, thumbnail_formats: list[ThumbnailFormat]) -> Iterator[None]:
with (
patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", thumbnail_formats),
patch("zerver.views.upload.THUMBNAIL_OUTPUT_FORMATS", thumbnail_formats),
):
yield
def test_get_thumbnail(self) -> None: def test_get_thumbnail(self) -> None:
assert settings.LOCAL_FILES_DIR assert settings.LOCAL_FILES_DIR
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
@@ -494,7 +476,7 @@ class TestThumbnailRetrieval(ZulipTestCase):
webp_anim = ThumbnailFormat("webp", 100, 75, animated=True) webp_anim = ThumbnailFormat("webp", 100, 75, animated=True)
webp_still = ThumbnailFormat("webp", 100, 75, animated=False) webp_still = ThumbnailFormat("webp", 100, 75, animated=False)
with self.mock_formats([webp_anim, webp_still]): with self.thumbnail_formats(webp_anim, webp_still):
with ( with (
self.captureOnCommitCallbacks(execute=True), self.captureOnCommitCallbacks(execute=True),
get_test_image_file("animated_unequal_img.gif") as image_file, get_test_image_file("animated_unequal_img.gif") as image_file,
@@ -560,7 +542,7 @@ class TestThumbnailRetrieval(ZulipTestCase):
# Shrink the list of formats, and check that we can still get # Shrink the list of formats, and check that we can still get
# the thumbnails that were generated at the time # the thumbnails that were generated at the time
with self.mock_formats([webp_still]): with self.thumbnail_formats(webp_still):
response = self.client_get(f"/user_uploads/thumbnail/{path_id}/{webp_still!s}") response = self.client_get(f"/user_uploads/thumbnail/{path_id}/{webp_still!s}")
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
consume_response(response) consume_response(response)
@@ -574,7 +556,7 @@ class TestThumbnailRetrieval(ZulipTestCase):
jpeg_still = ThumbnailFormat("jpg", 100, 75, animated=False) jpeg_still = ThumbnailFormat("jpg", 100, 75, animated=False)
big_jpeg_still = ThumbnailFormat("jpg", 200, 150, animated=False) big_jpeg_still = ThumbnailFormat("jpg", 200, 150, animated=False)
with ( with (
self.mock_formats([webp_still, jpeg_still, big_jpeg_still]), self.thumbnail_formats(webp_still, jpeg_still, big_jpeg_still),
patch.object( patch.object(
pyvips.Image, "thumbnail_buffer", wraps=pyvips.Image.thumbnail_buffer pyvips.Image, "thumbnail_buffer", wraps=pyvips.Image.thumbnail_buffer
) as thumb_mock, ) as thumb_mock,
@@ -599,7 +581,7 @@ class TestThumbnailRetrieval(ZulipTestCase):
) )
# Upload a static image, and verify that we only generate the still versions # Upload a static image, and verify that we only generate the still versions
with self.mock_formats([webp_anim, webp_still, jpeg_still]): with self.thumbnail_formats(webp_anim, webp_still, jpeg_still):
with ( with (
self.captureOnCommitCallbacks(execute=True), self.captureOnCommitCallbacks(execute=True),
get_test_image_file("img.tif") as image_file, get_test_image_file("img.tif") as image_file,
@@ -641,7 +623,7 @@ class TestThumbnailRetrieval(ZulipTestCase):
tiny_webp_still = ThumbnailFormat("webp", 10, 10, animated=False) tiny_webp_still = ThumbnailFormat("webp", 10, 10, animated=False)
gif_still = ThumbnailFormat("gif", 100, 75, animated=False) gif_still = ThumbnailFormat("gif", 100, 75, animated=False)
with ( with (
self.mock_formats([webp_anim, webp_still, tiny_webp_still, gif_still]), self.thumbnail_formats(webp_anim, webp_still, tiny_webp_still, gif_still),
self.captureOnCommitCallbacks(execute=True), self.captureOnCommitCallbacks(execute=True),
get_test_image_file("animated_img.gif") as image_file, get_test_image_file("animated_img.gif") as image_file,
): ):