diff --git a/zerver/lib/test_classes.py b/zerver/lib/test_classes.py index 77325584bf..df3df6ff6c 100644 --- a/zerver/lib/test_classes.py +++ b/zerver/lib/test_classes.py @@ -74,6 +74,7 @@ from zerver.lib.test_helpers import ( instrument_url, 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.user_groups import get_system_user_group_for_user from zerver.lib.users import get_api_key @@ -2018,6 +2019,14 @@ Output: user_group.direct_subgroups.set(direct_subgroups) 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): @contextmanager diff --git a/zerver/tests/test_thumbnail.py b/zerver/tests/test_thumbnail.py index fbc00aef95..72b6cb3d4e 100644 --- a/zerver/tests/test_thumbnail.py +++ b/zerver/tests/test_thumbnail.py @@ -1,6 +1,4 @@ import re -from collections.abc import Iterator -from contextlib import contextmanager from dataclasses import asdict from io import StringIO from unittest.mock import patch @@ -300,15 +298,14 @@ class ThumbnailClassesTest(ZulipTestCase): class TestStoreThumbnail(ZulipTestCase): - @patch( - "zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", - [ThumbnailFormat("webp", 100, 75, animated=True)], - ) def test_upload_image(self) -> None: assert settings.LOCAL_FILES_DIR 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: response = self.assert_json_success( 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"]), ) - 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 patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [bigger_thumb_format]): + with self.thumbnail_formats(ThumbnailFormat("webp", 150, 100, opts="Q=90", animated=False)): self.assertEqual(ensure_thumbnails(image_attachment), 1) 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: assert settings.LOCAL_FILES_DIR hamlet = self.example_user("hamlet") @@ -412,16 +405,19 @@ class TestStoreThumbnail(ZulipTestCase): frames=1, thumbnail_metadata=[], ) - self.assert_length(missing_thumbnails(image_attachment), 1) - with self.assertLogs("zerver.worker.thumbnail", level="ERROR") as error_log: - self.assertEqual(ensure_thumbnails(image_attachment), 0) - libvips_version = (pyvips.version(0), pyvips.version(1)) - # This error message changed - if libvips_version < (8, 13): # nocoverage # branch varies with version - 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]) + with self.thumbnail_formats(ThumbnailFormat("webp", 100, 75, animated=False)): + self.assert_length(missing_thumbnails(image_attachment), 1) + + with self.assertLogs("zerver.worker.thumbnail", level="ERROR") as error_log: + self.assertEqual(ensure_thumbnails(image_attachment), 0) + + libvips_version = (pyvips.version(0), pyvips.version(1)) + # This error message changed + if libvips_version < (8, 13): # nocoverage # branch varies with version + 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 self.assertEqual(ImageAttachment.objects.filter(path_id=path_id).count(), 0) @@ -434,22 +430,20 @@ class TestStoreThumbnail(ZulipTestCase): frames=1, thumbnail_metadata=[], ) - with patch("zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", []): + with self.thumbnail_formats(): self.assertEqual(missing_thumbnails(image_attachment), []) 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]) 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 self.assertEqual(missing_thumbnails(image_attachment), [still_webp]) still_jpeg = ThumbnailFormat("jpeg", 100, 75, animated=False, opts="Q=90") - with patch( - "zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp, anim_webp, still_jpeg] - ): + with self.thumbnail_formats(still_webp, anim_webp, still_jpeg): # But other still formats do self.assertEqual(missing_thumbnails(image_attachment), [still_webp, still_jpeg]) @@ -465,28 +459,16 @@ class TestStoreThumbnail(ZulipTestCase): byte_size=1234, ) image_attachment.thumbnail_metadata = [asdict(rendered_still_webp)] - with patch( - "zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp, anim_webp, still_jpeg] - ): + with self.thumbnail_formats(still_webp, anim_webp, 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 image_attachment.frames = 10 - with patch( - "zerver.lib.thumbnail.THUMBNAIL_OUTPUT_FORMATS", [still_webp, anim_webp, still_jpeg] - ): + with self.thumbnail_formats(still_webp, anim_webp, still_jpeg): self.assertEqual(missing_thumbnails(image_attachment), [anim_webp, still_jpeg]) 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: assert settings.LOCAL_FILES_DIR hamlet = self.example_user("hamlet") @@ -494,7 +476,7 @@ class TestThumbnailRetrieval(ZulipTestCase): webp_anim = ThumbnailFormat("webp", 100, 75, animated=True) 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 ( self.captureOnCommitCallbacks(execute=True), 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 # 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}") self.assertEqual(response.status_code, 200) consume_response(response) @@ -574,7 +556,7 @@ class TestThumbnailRetrieval(ZulipTestCase): jpeg_still = ThumbnailFormat("jpg", 100, 75, animated=False) big_jpeg_still = ThumbnailFormat("jpg", 200, 150, animated=False) with ( - self.mock_formats([webp_still, jpeg_still, big_jpeg_still]), + self.thumbnail_formats(webp_still, jpeg_still, big_jpeg_still), patch.object( pyvips.Image, "thumbnail_buffer", wraps=pyvips.Image.thumbnail_buffer ) as thumb_mock, @@ -599,7 +581,7 @@ class TestThumbnailRetrieval(ZulipTestCase): ) # 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 ( self.captureOnCommitCallbacks(execute=True), 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) gif_still = ThumbnailFormat("gif", 100, 75, animated=False) 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), get_test_image_file("animated_img.gif") as image_file, ):